Start a Windows service from a batch script and take appropriate action based on result

送分小仙女□ 提交于 2020-08-10 13:56:26

问题


I have a .bat script that attempts to start a Windows service at the end.

:start_wildfly
echo.
set /p wildfly_service_name="Enter Wildfly service name: "
echo INFO: Starting %wildfly_service_name%...
echo.
call net start "%wildfly_service_name%"

I want to be able to interpret the result of the net start attempt so that I can have my script take the appropriate action if it fails (e.g. if the service is already running, restart it. If the service name is invalid, re-prompt for the name again, if the user doesn't have sufficient privileges, exit).

The problem is that the NET command does not return the documented Win32_Service class codes.

It does echo errors on the console, however:

The requested service has already been started.

More help is available by typing NET HELPMSG 2182.

See http://ss64.com/nt/net_service.html for a list of the errors.

Unforunately, the errorlevel variable is always 2 in these error cases, so I can't rely on that.

What I'm now trying to do is run a FIND on the output of the NET command, searching for specific error codes and act upon them.

net start Wildfly 2>&1 | FIND "2182"
if %errorlevel% equ 0 goto service_already_running

So, the result of the FIND is stored in errorlevel and I can check to see if the FIND succeeded by checking if errorlevel is 0. This works.

Now, the problem comes when I want to check for more than one error code. I don't know how to expand the code above to check for "2185" as well, for example, and goto a different label in that case.

I'm now attempting to store the entire result of the NET command into a variable, and then run a FINDSTR on that variable.

setlocal EnableDelayedExpansion
set "output_cnt=0"
for /F "delims=" %%f in ('dir /b') do (
    set /a output_cnt+=1
    set "output[!output_cnt!]=%%f"
)
for /L %%n in (1 1 !output_cnt!) DO echo !output[%%n]!

This should store and echo each line of the output, however the last line doesn't seem to do anything.

And then I've also found some code that should search within a variable and return whether or not that string was found:

echo.%output%|findstr /C:"2182" >nul 2>&1 && echo Found || echo Not found.

I've had no luck putting it all together though. I just want to be able to interpret the result of the NET START <SERVICE> and jump to certain labels based on the result.


回答1:


I want to be able to interpret the result of the net start attempt

so that I can have my script take the appropriate action if it fails (e.g. if the service is already running, restart it. If the service name is invalid, re-prompt for the name again, if the user doesn't have sufficient privileges, exit).

Start the service as you are already doing:

net start "%wildfly_service_name%"

Now check the status of the service.

There are two ways to do this.

  1. Use net start again to see if the service is running:

    net start | find "%wildfly_service_name%" > nul
    if errorlevel 1 echo The service is not running
    
  2. Use sc (Service Control) to check the service status:

    SC query %wildfly_service_name% | find "STATE" | find "STOPPED"
    

    Or

    sc query %wildfly_service_name% | find "STATE" | find "RUNNING"
    

    The two statements above will return %errorlevel% = 1 if the text is not found.


Further Reading

  • An A-Z Index of the Windows CMD command line - An excellent reference for all things Windows cmd line related.
  • net - The NET Command is used to manage network resources.
  • sc - Service Control - Create, Start, Stop, Query or Delete any Windows SERVICE.



回答2:


Taking DavidPostill's answer of using net start to check the status of the service, here is my new solution:

echo.
echo INFO: Starting %wildfly_service_name%...
echo.

:verify_not_running
net start | find "%wildfly_service_name%" > nul
if %errorlevel% equ 0 goto restart_wildfly

:start_wildfly
net start "%wildfly_service_name%"
goto verify_running

:restart_wildfly
echo The %wildfly_service_name% service is already running. Will now restart...
net stop "%wildfly_service_name%"
net start "%wildfly_service_name%"

:verify_running
net start | find "%wildfly_service_name%" > nul
if errorlevel 1 goto start_wildfly

This script will first verify the service is not running.

If the service is already running, it will restart the service.

In either case, I check at the end to make sure the service is now started. If not, repeat the process over again.

Note that I no longer have a requirement to check that the service name was valid. The service name is now hardcoded earlier in the script so it is assumed to be correct.

And to handle the case of insufficient privileges, I added this snippet at the beginning of the script:

:check_permissions
net session >nul 2>&1
if errorlevel 1 (
    echo.
    echo ERROR: This script must be run as an Administrator. Please re-run the script from an elevated command prompt. 
    echo.
    echo Right-click "cmd.exe" from the Start menu and select "Run As Administrator".
    exit /b %error_level%
)



回答3:


You're right; the net command apparently always returns 2 for any kind of error. However, you can use the sc start command as a drop-in replacement for net start, and that one does indicate different errors through distinct exit statuses, in particular 1056 for An instance of the service is already running. So, you can use use

sc start "%wildfly_service_name%"

And then check %errorlevel% afterwards.



来源:https://stackoverflow.com/questions/40187380/start-a-windows-service-from-a-batch-script-and-take-appropriate-action-based-on

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!