Redirect pipe to a variable in Windows batch file
I want to stop and start a Windows service from a remote PC using the Windows command line, in a batch file.
sc \\192.168.1.1 stop <ServiceName>
rem sc \\192.168.1.1 query <ServiceName> | findstr STATUS | SET VAR=
However, I want to wait until the status of the service is assured to be stopped or started. So I was planning to loop and check the status continuously until the status is STOPPED.
I think that repeated request to the server may be processor intensive but there is no wait for the command line except for some hacks on checking time. But my main question is how do I get the status of the Windows service so I can check with an IF statement if it is OK to proceed to the next command?
To set a variable to the output of a command, use for /f
:
for /f "tokens=*" %%a in ('command') do set _CmdResult=%%a
The problem is, to use a pipe in the command you need to escape it with the command line escape character: ^
, therefore: ^|
.
for /f "tokens=*" %%a in ('sc \\192.168.1.1 query <ServiceName> ^| findstr STATUS') do set _CmdResult=%%a
Now, I'm not sure which version of Windows you're running, but my attempts at a sc
query on Windows 7 give the following output:
>sc query SamSs
SERVICE_NAME: SamSs
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 4 RUNNING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
This means a findstr STATE
would be required, which gives the output:
>sc query SamSs | findstr STATE
STATE : 4 RUNNING
Now, in the example above, tokens=*
means every token is set to the variable %%a
, where tokens are separated by spaces. In this case, you can use either the third token (4
) or fourth token (RUNNING
). By the way, with testing, 1
corresponds to STOPPED
for me.
To make things easier, I'll be using the string RUNNING
in this example. So we want the fourth token.
for /f "tokens=4" %%a in ('sc \\192.168.1.1 query <ServiceName> ^| findstr STATE') do set _CmdResult=%%a
Of course, depending on what your sc query
outputs, yours may be slightly different, so follow how I got there and modify as needed. Or post in a comment the output of your sc query
and I'll modify as needed.
To check the value, you can use:
if %_CmdResult%==STOPPED (
REM do something here
)
In your case, the loop would go something like this.
:loop
for /f "tokens=*" %%a in ('sc \\192.168.1.1 query <ServiceName> ^| findstr STATUS') do set _CmdResult=%%a
if %_CmdResult%==STOPPED (
sc \\192.168.1.1 start <ServiceName>
goto endloop
)
timeout /t 5
goto loop
:endloop
Note that timeout
is a utility only included in Windows Vista and later. Windows XP can use something like ping 1.1.1.1 -n 1 -w 5000 > nul
.
A More advanced example with higher complexity level
(but also higher usability)
- using several common application (
cURL
,GREP
,SED
) you can either download a Win32 pre-build versions of those or use cygwin's exe files in Windows- both works perfectly fine (for cygwin, better just putc:\cygwin\bin\
folder location in your system'sPATH
variable for easier access). - PIPE processing (STDOUT and STDERR are processed through).
- escaped symbols (
|
,>
,&
) - best practice / required on Windows7+. - no loops, no goto
- working with numeric data (
curl
's response headerContent-Length
) And.. NO TEMPORARY FILES!
@echo off
setlocal enableextensions
for /f "tokens=*" %%a in ('curl --head --ipv4 --sslv3 --silent --location-trusted --url "https://storage.googleapis.com/chromium-browser-continuous/Win_x64/362418/mini_installer.exe" 2^>^&1 ^| grep "Content-Length" 2^>^&1 ^| sed "s/\r\n$//g" 2^>^&1 ^| sed "s/content-length\:\ //gi" 2^>^&1') do ( set /a num=%%a )
set /a num=%num% / 1024 / 1024
echo it is %num%MB
endlocal
will output
it is 41MB
(original header is Content-Length: 43597312
)
took it from here: - CMD/Bash Script Ninja - cURL Response Header Number Manipulation