Halt batch file until service stop is complete? - batch-file

I'm using a batch file to stop a Windows service. I'm using the sc command, but I'm open to other ideas, given the question below. The problem is that the batch file proceeds while the service is stopping (the stop argument to sc seems only to request the stop -- it doesn't wait for the stop).
How can I modify the batch file to not proceed until the stop is complete?

You can use NET stop, which is synchronous, i.e it will wait until the service stops.
See
- NET stop

sc stop webdriveservice
:loop
sc query webdriveservice | find "STOPPED"
if errorlevel 1 (
timeout 1
goto loop
)
Another version with a repetition count limit:
sc stop webdriveservice
set count=1
set limit=10
:loop
sc query webdriveservice | find "STOPPED"
if errorlevel 1 (
timeout 1
set /a count += 1
if %count% lss %limit% goto loop
)

As mentioned above, NET STOP will send a stop command to the service, but, if the service takes more than a certain time (20 seconds or so is my observation), NET STOP will NOT wait for the service to actually stop before returning.
To actually pause the batch file until the service stops, you need to use an approach like those outlined in these threads:
How to check if a service is running via batch file and start it, if it is not running?
Stopping/Starting a remote Windows service and waiting for it to open/close

I believe net stop [Service] should wait until the service has fully stopped before moving on. sc stop [Service] simply sends a "stop" message to the service.

I had a similar issue with net stop. It returns when the service is indeed stopped, but the executable may still be running.
For upgrade reasons, this is not good enough, we need to wait until the process has finished.
I've used a simple loop to wait until the service executable has actually finished:
net stop "ServiceName"
:loop1
set _CmdResult=""
for /f "tokens=1" %%a in ('TASKLIST ^| FINDSTR ServiceName.exe') do set _CmdResult=%%a
if not %_CmdResult% == "" (
timeout 5
goto loop1
)
Once the the executable finishes, the loop will break.

This is a bit crude but it worked for me in order to ensure that I could schedule a daily batch file to essentially RESTART a service.
NET STOP [Service]
:TryAgain
TIMEOUT /T 10 /NOBREAK
NET START [Service]
IF %ERRORLEVEL% NEQ 0 GOTO TryAgain
I realize with this code snippet that this could result in an endless loop if the service was to not successfully start. I just wanted to basically show how to get around the issue using TIMEOUT where a service may take longer to stop than what the NET STOP command allows.

Use the && symbol between commands. The && symbol waits to finish the previous command before proceed to next command.
All commands must be at the same command row. You can use as many commands you want in a row.
You can use also the pause command. With this, asks to press any key, before proceed to next procedure.
For example:
sc qdescription "MyServiceName" && echo. && sc stop "MyServiceName" && echo. && echo [ "MyServiceName" service stopped ] && echo. && pause

Related

I need to write a batch script that will restart two services, but only start the second service after checking the log file

I need to write a batch script that will restart two services, but it will need to check the log file of the first service for a specific string value before restarting the second service, keep looping back until the sting value is found before starting the second service.
I have very little experience with batch scripting, but I think I need to somehow assign the string value to Var and only if it's the correct value start the second service?
#echo off
sc \localhost Stop IMS01
sc \0.0.0.0 stop IMS02
sc \localhost Start IMS01
rem delay of 4mins
ping 127.0.0.1 -n 240 > nul
:Loop
IF EXIST Find "started and accepting connections" D:\logs\IMS.log
GOTO StartIMS02
IF NOT EXIST Find "started and accepting connections" D:\logs\IMS.log
Goto Loop
:StartIMS02
sc \0.0.0.0 Start IMS02
May I assume that all of your 0.0.0.0 are placeholders for known working code and you just need help with the parsing of the log file? If so:
#(
echo off
SETLOCAL EnableDelayedExpansion
SET "_Svr1=localhost"
SET "_Svc1=IMS01"
SET "_Svr2=0.0.0.0 "
SET "_Svc2=IMS02"
SET "_Delay=240"
SET "_Delay_Loop=30"
SET "_StringToMatch=started and accepting connections"
)
FOR /L %%L IN (1,1,2) DO (
ECHO.Stopping: !_Svc%%L! On: !_Svc%%L!
SC \\!_Svr%%L! Stop !_Svc%%L!
)
ECHO.Starting: %_Svc1% On: %_Svr1%
SC \\%_Svr1% Start %_Svc1%
rem delay of 3 minute(s)
PING 127.0.0.1 -n %_Delay% > nul
:Loop
rem delay of 1 minute(s)
PING 127.0.0.1 -n %_Delay_Loop% > nul
IF EXIST "D:\logs\IMS.log" (
(
Find /I "%_StringToMatch%" "D:\logs\IMS.log"
) && (
ECHO.
ECHO.============================
ECHO.Success! Found the String "%_StringToMatch%"
ECHO.
ECHO. Starting %_Svc2% on %_Svr2%
SC \\%_Svr2% Start %_Svc2%
) || (
ECHO. Failed to Find the String "%_StringToMatch%"
ECHO. Looping, will wait another %_Delay_Loop% Seconds before testing again.
GOTO :Loop
)
) ELSE (
ECHO Log File Not Found! Aborting!
)
GOTO :EOF
Now I decided to set a bunch of variable names just for my own sanity, that is all optional, although it does mean we can loop the two services to stop them.
The Logic I have put in place checks if the log file exists, if it does not it aborts the script.
It also adds a 30-second wait on the looping, you can play around with those a lot easier when they are variables IMHO.
I put in some ECHOs to let you keep tabs on what the script is doing they are all optional.
Now the meat of it is I use the FIND /I "String" command to check for the string, a dif it exists we'll start service 2. && is a logical test to see if the result was a success, while as you may have guessed, || tests for a fail state. We have to test for success first or the actions of the fail state could theoretically trigger the success state to run too. (although in your specific case the GoTo would break that from happening.)
If the string was not matched w loop again and we'll have our 30 second delay before retry.

Check if CTRL-C pressed Or batch wait for agreement

I need to know how can I check in batch file if the second batch file which is opened in other command window has stopped (waiting for argument or process not successful).
#echo off
:loop
start /wait rapidminer-batch.bat -f C:\Users\AHM-PC\Documents\ccc.rmp
echo cmd stopped
pause
goto loop
When called batch ends, it returns a value to errorlevel. It works for call, don't know if for start too.
if %errorlevel% gtr 0 (
echo failed
) else (
echo success)
or call exit /b <number of error> in your called batch, to return specific value. Check exit for more details.
The normal method to provide interbatch communication is a flag file
Either you create a flag file in the main routine and wait for the started routine to delete it or wait until the started batch creates a file, and delete it.
eg
echo.>myflag.txt
start anotherbatch.bat
:loop
timeout /t 1 >nul
if exist myflag.txt goto loop
Here, the batch will wait until myflag.txt is deleted, which you do in the second batch. All you need is for the two routines to agree on a filename to use.

Batch Script to wait for program to close by user before applying msi update

I'm using a network management tool to apply updates to software and I have an issue where if a users is already using the program you want to update the update will fail as you would expect.
I have been trying to put together a batch script that will detect whether the the program is running and if it is the script will wait until the user closes down the program and the apply the msi update.
I've pretty much scoured google but can only really find previous scripts that kill the program first before proceeding and I don't want that to happen as the user may lose work.
Hope someone can help!
#echo off
start "" notepad.exe
:loop
(tasklist | find /i "notepad.exe" && ( ping -n 2 localhost & goto loop)) >nul
echo Notepad closed
This just starts notepad.exe (the running program) and waits until it is closed. Adapt according to your needs
`tasklist |find "programname"`
will tell you if the programm is running:
if %errorlevel%==0 echo running
put just a little loop around it:
:loop
tasklist |find "programname" >nul
if %errorlevel%==0 (
echo prgram running
timeout 2>nul
goto loop
)
echo program not running

Calling a setup.cmd and waiting for it complete

I am running 1 st batch utility calling another 2nd batch. The 2nd batch calls a setup.cmd command which has internal Java code to patch files.
When I just call the 2nd batch from 1st batch --
1st batch calls the second batch
2nd batch calls the setup.cmd
1st batch continues with further code without waiting for setup.cmd to complete.
I tried using start /wait to call the setup.cmd but that does not returns back the control to 1st batch. It keeps the session after installing.
1st batch calls 2nd batch by using CALL
2nd batch has following code to call setup.cmd
%windir%\system32\cmd /c start /WAIT Disk1\setup.cmd %parameter%
How can I get the control back to 1st batch once the setup.cmd completes?
If you just use this without the start command, and call batch2 then it will wait until it is finished.
call Disk1\setup.cmd %parameter%
Resolved this last week by using loops and by calling the setup.cmd...sorry for delay in this post.
#echo off
CALL \Installers\Disk1\setup.cmd -i silent -FILE=\Silent\Silent.txt
:LOOP
tasklist /FI "username eq SOMEUSER" 2>NUL | find /I /N "java">NUL
ECHO %ERRORLEVEL%
if "%ERRORLEVEL%"=="1" (
GOTO CONTINUE
) ELSE (
ECHO PATCH is still running, Sleeping for 5 Mins
SLEEP 300
GOTO LOOP
)
:CONTINUE

Run DOS Command for a Time Limit

I want to perform the following operations.
Read 1 word at a time from an input file consisting of many words.
Pass this word as an argument to another command line based application.
Run that application for a fixed amount of time, say 10 seconds.
Abort the execution of the application if it is still running after 10 seconds and go back, pick the next word from the input file and repeat steps 1 to 3.
Here is what I have written though it does not achieve exactly what I want it to:
#echo off
for /f %%i in ('type input.txt') do call:Routine %%i
:Routine
set app="myApp.exe"
set limit=60
%app% %1
goto Delay
:Delay
ping localhost -n %limit% > nul
The above script will introduce the delay after the execution of myApp has completed. However, I want it to run myApp.exe for not more than 10 seconds, if it does, then abort the application using taskkill and move on to the next word from the input file.
I searched for a solution online and came across this:
http://www.tech-archive.net/Archive/WinXP/microsoft.public.windowsxp.general/2006-04/msg03609.html
Though it does not answer my query exactly, I would like to make my code do something similar.
Thanks.
The logic in the linked code looks flawed: It either launches 3 download commands, or it delays ~59 seconds and attempts to kill all download commands, but it never does both. The TASKKILL command arguments are not correct - the imagename belongs after the /IM parameter.
In your code, you are not going to kill your task without the TASKKILL command!
You must GOTO :EOF or EXIT /B after your loop finishes, otherwise the code will fall through and execute the subroutine without using CALL. But there really is no need to use a subroutine at all.
You only need to initialize your variables once.
No need to execute a command in your IN() clause. FOR /F has a variation that can read the text file directly. Type HELP FOR from the command line and read the documentation carefully.
PING has roughly a 1 second delay between each echo request. So a count of 11 will yield a delay of roughly 10 seconds.
EDIT - originally forgot the critical START command to start the app in its own process
#echo off
set app="myApp.exe"
set limit=11
for /f %%i in (input.txt) do (
start "" %app% %%i
ping localhost -n %limit% > nul
taskkill /im %app% /f
)

Resources