• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1054
  • Last Modified:

SC Query output


Could someone please enlighten me as to how do the following.
From time to time I need to shut down an application that runs as a service on a large number of servers, the service that requires shutting down can take anything from 30-60 mins and following a successful shutdown I need to run a súpplíed batch file that will that will run updates against this application.
Where I am stuck is on how to get a batch file to pick up on sc query "state stopped" on each server and if the service has stopped for the batch file to kick in.

So I am assuming the simplified order of this is.

1.Shutdown Service
2.Run sc query
3.If state stopped then run supplied_update.bat
4.If not wait or check again in 30 mins etc

Many Thanks
2 Solutions
Bill PrewCommented:
It's pretty easy to check the state of a service remotely, and stop or start it as needed, that can be done easy enough.

The bigger problem you are going to have I think is keeping track of which servers have been done, and which haven't.  You will want to loop through a file that lists each server name, and then process that server.  But I don't think you want to wait 30 to 60 minutes on each server for the service to stop, before going to the next server.

Rather I would think you would start with a list of servers to be processed, and loop over them.  For any that the service is running, initiate a stop of the service, and then move on to the next server.  For any servers where the service is already stopped, perform the update, and restart.

Then you need to keep rechecking the servers that you initiated the stop on, maybe every 5 minutes, to see when the service is stopped, so you can perform the update.  For every server updated, you remove it from the list.

Hope that makes a little sense, we could come up with a way to do this, but wanted to say it out loud before I did any scripting to make sure you agreed.

Gerwin Jansen, EE MVETopic Advisor Commented:
The sc query command could look like this:
sc \\ServerName ServiceName | findstr /i "stopped"

Open in new window

After the sc command, check %ERRORLEVEL% to determine whether the service was stopped, 0 would mean is has stopped, 1 would mean that it has another state. You could also explicitly check for "running" before you attempt the sc stop command.

I agree with Bill on using a servername list, you could add a status file per server to keep track of the service's state on each server.
steveuk71Author Commented:
Thanks Bill and Gerwin, Bill I agree with your comment and if there is any chance of some assistance with this matter it would be most appreciated.
Gerwin,the status file per server sounds interesting, could you please elaborate if possible.
For the fun of it; you might want to change the properties of your cmd console to be wider than 80 characters. The script will spawn a separate cmd window for each server in the list that will do the actual updating; the main script window will only monitor the progress (closing/killing the main window will NOT close the spawned windows!). You can add your own code where indicated, starting in line 181.
The script requires sleep.exe from the W2k3 Resource Kit (http://www.microsoft.com/en-us/download/details.aspx?id=17657); put it somewhere in the path or in the script's folder.
@echo off
setlocal enabledelayedexpansion
REM *** (Path and) name of the file with the server list to process (one name per line, no leading backslashes; host names, FQDN, or IP.
set ServerList=%~dp0ServerList.txt
REM *** Name of the service to stop/start:
set Service=Some Service
REM *** Timeout for service stop/start in minutes:
set TimeoutServiceStop=240
set TimeoutServiceStart=120
REM *** Monitor refresh interval in seconds:
set RefreshInterval=5
REM *** Service poll interval in seconds:
set QueryInterval=10
REM *** Time for the spawned windows to remain open once the server has been processed:
set DisplayDelay=10

REM *** Column headers:
set Col1Name=Computer
set Col2Name=Time
set Col3Name=Status
set Col4Name=Message
REM ***  Column sizes (13 more characters are required for the table lines):
set Col1Size=20
set Col2Size=13
set Col3Size=6
set Col4Size=80

set echo2=^<NUL set /p Dummy=
(set FillerSpace=                                                                                                    )
(set FillerLine=----------------------------------------------------------------------------------------------------)
set StatusFolder=%~dp0Status

if /i "%~1"=="/spawn" (goto :Process)

if not exist "%StatusFolder%" md "%StatusFolder%"
set /a i = 0
for /f "usebackq" %%a in ("%ServerList%") do (
	echo Creating status file for %%~a ...
	call :SetStatus "%%~a" "BUSY" "Waiting for start."
	set /a i += 1
	set Server[!i!]=%%~a
set /a ServerCount = i
for /l %%i in (1, 1, %ServerCount%) do (
	echo Spawning process for !Server[%%i]! ...
	start "" /min "%~f0" /spawn !Server[%%i]!
	sleep.exe -m 500

call :FormatString Col1Name %Col1Size% FillerSpace
call :FormatString Col2Name %Col2Size% FillerSpace
call :FormatString Col3Name %Col3Size% FillerSpace
call :FormatString Col4Name %Col4Size% FillerSpace
set Header=^^^| %Col1Name% ^^^| %Col2Name% ^^^| %Col3Name% ^^^| %Col4Name% ^^^|
set HLine=+-!FillerLine:~0,%Col1Size%!-+-!FillerLine:~0,%Col2Size%!-+-!FillerLine:~0,%Col3Size%!-+-!FillerLine:~0,%Col4Size%!-+
	echo %HLine%
	echo %Header%
	echo %HLine%
	set Done=1
	for /l %%i in (1, 1, %ServerCount%) do (
		set Server=!Server[%%i]!
		call :GetStatus !Server! StatusTime Status Message
		if "!Status!" equ "BUSY" (set Done=0)
		call :FormatString Server %Col1Size% FillerSpace
		call :FormatString StatusTime %Col2Size% FillerSpace
		call :FormatString Status %Col3Size% FillerSpace
		call :FormatString Message %Col4Size% FillerSpace
		set Line[%%i]=^^^| !Server! ^^^| !StatusTime! ^^^| !Status! ^^^| !Message! ^^^|
	for /l %%i in (1, 1, %ServerCount%) do (
		echo !Line[%%i]!
	echo %HLine%
	sleep %RefreshInterval%
if "%Done%" equ "0" goto LoopMonitor
echo Done.
set /a SuccessCount = 0
set /a ErrorCount = 0
for /l %%i in (1, 1, %ServerCount%) do (
	call :GetStatus !Server[%%i]! StatusTime Status Message
	if "!Status!" equ "OK" (
		set /a SuccessCount += 1
	) else (
		set /a ErrorCount += 1
echo Successfully updated %SuccessCount% machines, errors on %ErrorCount% machines.
goto :eof

REM ********************************************************************************
REM *** Helper function
>"%StatusFolder%\%~1.ini" echo "%Time%"~"%~2"~"%~3"
goto :eof

for /f "usebackq tokens=1-3 delims=~" %%a in ("%StatusFolder%\%~1!.ini") do (
	set %2=%%~a
	set %3=%%~b
	set %4=%%~c
goto :eof

set _tmp_=!%1!!%3!
set %1=!_tmp_:~0,%2!

set Server=%~1
set Action=%~2
if /i "%Action%"=="stop" (
	set TimeoutService=%TimeoutServiceStop%
	set QueryString=STOPPED
) else (
	set TimeoutService=%TimeoutServiceStart%
	set QueryString=RUNNING
set /a Timeout = 60 * TimeoutService / QueryInterval
sc.exe \\%Server% %Action% "%Service%" >NUL 2>&1
if %errorlevel% equ 1062 (
	call :SetStatus %Server% "BUSY" "Service Control '%Action%': already stopped."
	exit /b 0
if %errorlevel% neq 0 (
	call :SetStatus %Server% "ERROR" "Service Control: could not send %Action% signal; errorlevel: %errorlevel%"
	exit /b 1
set /a CurrentWait = 0
%echo2% [%Time%] Waiting for state '%QueryString%' ^(Timeout %TimeoutService% minutes^)
	sleep.exe %QueryInterval%
	set /a CurrentWait += QueryInterval
	set QueryState=INACCESSIBLE
	for /f "tokens=1* delims=: " %%a in ('sc.exe \\%Server% query "%Service%" 2^>NUL') do (
		if "%%a" equ "STATE" (set QueryState=%%b)
	if "%QueryState%" neq "!QueryState:%QueryString%=!" (
		call :SetStatus %Server% "BUSY" "Service Control '%Action%': success."
		echo.& exit /b 0
	if "%QueryState%" equ "INACCESSIBLE" (
		call :SetStatus %Server% "ERROR" "Service Control '%Action%': lost access to remote SCM; last state: %QueryState%"
		echo.& exit /b 1
	If %CurrentWait% geq %Timeout% (
		call :SetStatus %Server% "ERROR" "Service Control '%Action%': timeout of %TimeoutService% minutes reached; last state: %QueryState%"
		echo.& exit /b 1
	call :SetStatus %Server% "BUSY" "Service Control '%Action%': waiting for state '%QueryString%'; current state: %QueryState%"
goto LoopQuery

REM ********************************************************************************
REM *** Spawned processing of a server
set Server=%~2
title %~n0 - %Server%

call :SetStatus %Server% "BUSY" "Pinging"
echo [%Time%] Pinging %Server% ...
ping.exe %Server% | find /i "TTL" >NUL
if errorlevel 1 (
	call :SetStatus %Server% "ERROR" "No response to ping."
	echo ... no response; leaving.
	goto Leave

echo [%Time%] Stopping service ...
call :SetStatus %Server% "BUSY" "Stopping service"
call :ServiceControl %Server% stop
if errorlevel 1 (goto Leave)

echo [%Time%] Running Update ...
call :SetStatus %Server% "BUSY" "Updating"
REM *** Update the server here; replace "SLEEP 15" with whatever you need to do, for example 'call supplied_update.bat %Server%'

echo [%Time%] Starting service ...
call :SetStatus %Server% "BUSY" "Starting service"
call :ServiceControl %Server% start
if errorlevel 1 (goto Leave)

echo [%Time%] Done.
call :SetStatus %Server% "OK" "Successfully updated."

sleep.exe %DisplayDelay%

Open in new window

steveuk71Author Commented:
Many Many Thanks for this assistance, I haven't had time to go through and attempt to understand it just yet.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now