Batch - "for /F loop" inside "for /L loop" - loops

I have following problem:
I want to create a batch file looping through an amount of ip addresses to stop a certain service on remote pc's.
Cause the stopping process takes some time I need to have a second loop to query the state of the service and waiting until the service reached the state STOPPED.
Set /p StartIP="Start IP (101): "
Set /p EndIP="End IP (199): "
for /L %%n IN (%StartIP%, 1, %EndeIP%) DO (
psservice -u username -p password \\192.168.8.&&n stop 'ServiceName'
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in ('psservice -u username -p password \\192.168.8.%%n query 'ServiceName' ^| findstr " STATE"') do (
if NOT %%H==STOPPED (
echo.
echo state: %%H
goto CHECK
)
echo.
echo state: %%H
)
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
Now the point I stuck to:
My range of numbers '%%n' from the /L loop is getting destroyed after passing the /F loop the first time.
With an example it looks like this:
Set /p StartIP="Start IP (101): 101"
Set /p EndIP="End IP (199): 105"
for /L %%n IN (101, 1, 105) DO (
psservice -u username -p password \\192.168.8.101 stop 'ServiceName'
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in ('psservice -u username -p password \\192.168.8.101 query 'ServiceName' ^| findstr " STATE"') do (
if NOT %%H==STOPPED (
echo.
echo state: %%H
goto CHECK
)
echo.
echo state: %%H
)
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
In this example I have the ip range 192.168.8.101 to 192.168.8.105.
The batch is running well until the /F loop is run trough the first time.
After this moment the %%n parameter from my /L loop is gone. The service can't start again, cause the %%n parameter already missing and my /L loop can't continue too -.-
Someone an idea what I can do to solve this problem?
Thank you already for reading this post.

As MC ND said in his comment, issuing a GOTO within a FOR loop will break the loop. Actually, the issue is more general than that - issuing a GOTO within any block of code (paranthesized, or concatenated via &) will terminate the remainder of the block.
The simple solution is to extract the code that needs GOTO and put it in its own subroutine, and then CALL the routine from within your loop.
Set /p StartIP="Start IP (101):"
Set /p EndIP="End IP (199):"
for /L %%n IN (%StartIP%, 1, %EndIP%) DO (
psservice -u username -p password \\192.168.8.%%n stop 'ServiceName'
call :check %%n
psservice -u username -p password \\192.168.8.%%n start 'ServiceName'
)
exit /b
:CHECK
echo 5 sek.
ping 127.0.0.1 -n 5 > nul
for /F "tokens=3 delims=: " %%H in (
'psservice -u username -p password \\192.168.8.%1 query 'ServiceName' ^| findstr " STATE"'
) do (
echo.
echo state: %%H
if not %%H==STOPPED goto CHECK
)
exit /b

Related

Batch Script ErrorLevel Output

I need help - I am trying to output any ErrorLevel that is 1 or greater into a log file. When I issue the command the log file never get's generated. Any help would be greatly appreciated.
Script:
for /f "delims=" %%i in (C:\_\Restart\Computer.txt) do (
start "%%i" \_\PStools\psexec \\%%i -u Administrator -p Password -i c:\restart.cmd
if not %errorlevel%==0 echo %errorlevel% > error.log
)
This script allows me to use PSEXEC and issue a restart command to all the computer at once. However several of them fail and I'd like to know which ones fail.
Thanks!
Is this the format I should use?
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\_\Restart\Computer.txt) do (
start "%%i" \_\PStools\psexec \\%%i -u Administrator -p Password -i c:\restart.cmd
if errorlevel 1 echo !errorlevel! > error.log
)
Script V3:
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\temp\list.txt) do (
start "" "shutdown" /m \\%%i -r -f -t 900
echo !errorlevel! && echo %%i
if errorlevel 1 echo !errorlevel! >> c:\temp\log.txt && echo %%i >> c:\temp\log.txt
)
-m = use remote computer
-r = reboot
-f = Force reboot
-t = delay of time before rebooting
you can use shutdown -? for more help on argument that can be passed to the reboot command.
Script v4 without the start command:
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (C:\temp\list.txt) do (
shutdown /m \\%%i -r -f -t 900
echo !errorlevel! && echo %%i
if errorlevel 1 echo !errorlevel! >> c:\temp\log.txt && echo %%i >> c:\temp\log.txt
)

Loop until variable != ""

I want to make a batch file that sends certain values to a output.txt. I have the following code:
for /F "delims=" %%a in ('adb logcat -v threadtime | grep -m 1 'VAC: App Name is:'') do set appName=%%a
echo App Name= %appName% > output.txt
The problem is that the grep statement doesn't immediately return a value--not until a user performs a certain action on the Android device. So I need to create a loop around the "for" statement. I'll make an attempt below, but I know it's wrong.
do
while
%appName% = ""
for /F "delims=" %%a in ('adb logcat -v threadtime | grep -m 1 'VAC: App Name is:'') do set appName=%%a
if "%appName% != "" leave
enddo
echo App Name= %appName% > output.txt
set "appName="
:loop
for /F "delims=" %%a in (
'adb logcat -v threadtime ^| grep -m 1 "VAC: App Name is:"'
) do set "appName=%%a"
if not defined appName goto loop
It just clears the variable and keep looping until it gets any value in it
Here you go (although MC ND's answers looks good too):
Please note pipe needs to be escaped by caret^, I added a 1 secs wait ping -n 1 -w 1000 1.1.1.1 >nul
:while_loop
for /F "usebackq delims=" %%a in (`adb logcat -v threadtime ^| grep -m 1 'VAC: App Name is:'`) do set appName=%%a
ping -n 1 -w 1000 1.1.1.1 >nul
if not "%appName% == "" goto exit_loop
goto while_loop
:exit_loop
echo App Name= %appName% > output.txt

Separate IP from text in ping output?

I'd like to be able to run a single batch file that would find the IP address of every device connected to my router, and then find their hostnames from it. What I have so far is below:
#echo off
set /a n=0
:repeat
set /a n+=1
echo 192.168.1.%n%
ping -n 1 -w 500 192.168.1.%n% | FIND /i "Reply">>devices.txt
if %n% lss 254 goto repeat
type devices.txt
goto :hostname
This finds all the possible addresses and writes them to a text file, devices.txt.
However, I now end up with the following:
Reply from 192.168.1.82: bytes=32 time=5ms TTL=255
The next part of the batch file goes:
:hostname
ping -a %ip% -l 1 -n 1 >> hostnames.txt
This pings the IPs found in devices.txt and returns the result in hostnames.txt - or at least, I'd like it to.
Somehow I need to separate the IP address from the other text when writing it to devices.txt, and then assign it as a variable so it can be used by the next part.
Is there a simple function I can use to do either of these things?
Try this:
#echo off
setlocal
set "p=ping -n 1 -w 500 192.168.1"
for /l %%a in (1,1,254) do (
for /f "Tokens=3 delims=: " %%b in (
'%p%.%%a^|Find /i "TTL="'
) do (
echo Pinging %%b
echo %%b>>devices.txt
for /f "tokens=2" %%c in (
'ping -a %%b -l 1 -n 1^|Find /i "pinging"') do (
echo %%c >>hostnames.txt
)
)
)
We start by creating a For /L loop that goes from 1 to 254 in increments of 1. Then we run a for loop on a ping command that takes the third token on the return line and puts it into a variable, %%b in this case. We then echo out pinging IP address contained in %%b and write it to devices.txt. Then, we run another ping to extract the second token which is the hostname of the computer we're pinging and write it out to hostnames.txt.

Batch File - Catching PSEXEC result

If I run a successful PSEXEC command, it says this...
"cmd exited on workstation.domain with error code 0."
Is there any way I can prevent this and do something like
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
if %errorlevel%==0 (
echo Success!
) else (
REM display psexec error here.
)
Since my edit's were rejected...
Is the original code posted part of a larger script? If so then do you set your errcode to match the ERRORLEVEL environment variable?
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
REM display psexec error here.
)
Whenever attempting to detemine IF / THEN in batch and you use == you need to surrond the variable and the valuecheck in single " ' " marks. The above code corrects that issue for you as well as replaces errcode with ERRORLEVEL, which is the default environment variable for Windows.
Also, in practice I always use the following before any ERRORLEVEL check to drop the initial value to properly catch the error.
verify >nul
In this case I would do the following:
verify >nul
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
echo.Error is %ERRORLEVEL%; please see http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx for more details.
)
I added a weburl for checking on the error received.
Alternatively you could open the URL to the corresponding page automatically:
#ECHO OFF
verify >nul
set ERRCODE=0
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "
IF '%ERRORLEVEL%'=='0' (
echo Success!
) else (
set ERRCODE=%ERRORLEVEL%
)
IF %ERRCODE% LEQ 499 set MSERROR=681382
IF %ERRCODE% GTR 500 set MSERROR=681388
IF %ERRCODE% GTR 1000 set MSERROR=681383
IF %ERRCODE% GTR 1300 set MSERROR=681385
IF %ERRCODE% GTR 1700 set MSERROR=681386
IF %ERRCODE% GTR 4000 set MSERROR=681387
IF %ERRCODE% GTR 6000 set MSERROR=681389
IF %ERRCODE% GTR 8200 set MSERROR=681390
IF %ERRCODE% GTR 9000 set MSERROR=681391
IF %ERRCODE% GTR 12000 set MSERROR=681384
IF ERRCODE NEQ 0 start http://msdn.microsoft.com/en-us/library/ms%MSERROR%(v=vs.85).aspx
IF ERRCODE NEQ 0 echo.This failed with ERROR: %ERRCODE%
pause
For reference to psexec http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx
The first step when determining program results is to identify all of the return values and if it sets errorlevel.
#echo off
:: Method 1, Handle a single line of output. No errorlevel support
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= " ^| find /v "error code 0"`) do (
rem Display the error
echo.%%A
goto Failed
)
echo.Success
:Failed
:: Method 2, Handle multiple lines of output. No errorlevel support
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "`) do (
rem Check the status
for /f "usebackq delims=" %%X in (`echo."%%~A" ^| find /v "error code 0"`) do (
echo.%%X
)
for /f "usebackq delims=" %%X in (`echo."%%~A" ^| find "error code 0"`) do (
echo.Success
)
)
:: Method 3, Supports error level variable; only works if the called program supports it.
verify > nul
psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "> nul
if %ERRORLEVEL% EQU 0 echo.Success
if %ERRORLEVEL% NEQ 0 echo.Error
:: Method 4, specific error message with error level, requires delayed expansion.
setlocal enabledelayedexpansion
verify > nul
for /f "usebackq delims=" %%A in (`psexec \\workstation.domain -u username -p password cmd /c "assoc.pdf= "`) do (
if !ERRORLEVEL! EQU 0 echo.Success
if !ERRORLEVEL! NEQ 0 echo.%%A
)
endlocal
pause

batch file - getting ip from ping command

i have this command.
ping -n 1 piratelufi.com | find /i "reply from"
i want to get the ip inside the ping response. i thought of using %var:~0,10% but i have no idea how to redirect the output to echo.
i even tried to use pipe
ping -n 1 piratelufi.com | find /i "reply from" | echo %1
but the %1 variable does not represent the output of the first two commands. i even tried to use &1 but i failed. What is the 'variable' needed to echo out the output from the first two commands?
Check out the FOR command it's really cool:
FOR /f "tokens=1,3 delims=: " %%A IN ('ping -n 1 piratelufi.com') DO IF %%A==Reply ECHO IP IS %%B
Try the following:
for /f "tokens=2 delims=[]" %f in ('ping -4 -n 1 piratelufi.com ^|find /i "pinging"') do echo IP=%f

Resources