I have used several scripts posted in this forum unsuccesfully.
Script is as follows:
#echo off
for /f %%i in (computersTest.txt) do (
ping -n 1 %%i | find "TTL" >nul 2>nul
Echo %errorlevel%
)
Errorlevel is always 0 no matter if host is reachable or not. If I remove the >nul to see the output I get the following
Reply from 10.6.4.20: bytes=32 time<1ms TTL=64
0
0
Reply from 10.6.5.58: bytes=32 time<1ms TTL=126
0
Where the second host in the list is not reachable but errolevel is 0
If I execute in the command prompt
ping -n 1 XXXXXXXXX | find "TTL" >NUL 2>NUL
echo %errorlevel%
gives 1
I don't know what I am doing wrong
TIA
Ramon
Batch lines or blocks of lines (lines enclosed in parenthesis) are first parsed and then executed. During the parse phase, all read operations on variables are removed from code, replaced with the value inside the variable before starting to execute the line/block. So, if a variable is changed inside a line/block, this new value can not be retrieved from inside the same line/block, as there is not a read operation to retrieve the new value.
You can solve it using delayed expansion and changing (where needed) the syntax from %var% into !var!, to indicate to the parser that the read operation must be delayed until the command executes
In your case
#echo off
setlocal enabledelayedexpansion
for /f %%i in (computersTest.txt) do (
ping -n 1 %%i | find "TTL=" >nul 2>nul
Echo %%i - !errorlevel!
)
note: The correct test in ipv4 for response is to search for TTL=, as you can have a false positive in case of a TTL expired error.
But in the case of checking the errorlevel variable, there are more alternatives (if they are applicable).
You can use the native if errorlevel n where the condition will be evaluated to true for any errorlevel equal or greater than n
#echo off
for /f %%i in (computersTest.txt) do (
ping -n 1 %%i | find "TTL=" >nul 2>nul
if errorlevel 1 ( echo %%i offline ) else ( echo %%i online )
)
Or you can use conditional execution. The operators && and || will allow to include what to execute depending on the errorlevel (not set or set) from previous command
#echo off
for /f %%i in (computersTest.txt) do (
( ping -n 1 %%i | find "TTL=" >nul 2>nul ) && echo %%i online || echo %%i offline
)
Related
I want to get particular exit code for each output in for loop which I am printing(echo). I want to use that exit code and give particular output.
for /f "tokens=* delims=" %%i in (list.txt) do ping -n 3 %%i >nul && if /i "ERRORLEVEL" == "0" (
echo %%i Alive
) else (
echo %%i Failed
)
There is no need to get the errorlevel by literally specifying it for each result. The exitcode/errorlevel can be evaluated by using conditional operators && and ||
So all you need is:
#echo off
for /f "usebackq delims=" %%i in ("list.txt") do ping -n 3 %%i >nul 2>&1 && echo %%i Alive || echo %%i Failed
What happens is simple. The errorlevel or exit code is evaluated. If it the errorlevel is 0 it is a success and it will use the && operator to fire the next command. if it is 1 or larger, it will constitute as an error and it will use the or operator || and perform the relevent command.
If however you MUST use the errorlevel or %errorlevel literally:
#echo off
for /f "usebackq delims=" %%i in ("list.txt") do (
ping -n 3 %%i >nul 2>&1
if errorlevel 1 (
echo %%i Failed
) else (
echo %%i Alive
)
)
Obviously without needing delayedexpansion
The exact answer to your problem, as you stated it, is this:
#echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%i in (list.txt) do ping -n 3 %%i >nul 2>&1 & if "!ERRORLEVEL!" == "0" (
echo %%i Alive
) else (
echo %%i Failed
)
for /f "tokens=* delims=" %%i in (list.txt) do (
set "reported="
ping -n 3 %%i >nul
call echo %%i responded with errorlevel %%errorlevel%%
if errorlevel 2 set "reported=y"&echo errorlevel 2 actions&cd .
if errorlevel 1 set "reported=y"&echo errorlevel 1 actions&cd .
if not defined reported echo errorlevel 0 actions
)
The string "ERRORLEVEL" will never be equal to the string "0". You are looking for the value of errorlevel, which would normally be %errorlevel% BUT since you have used a code block (a parenthesised sequence of statements) %errorlevel%, like any variable would be replaced by its value at the time the code block is encountered, not as it changes when executed. See Stephan's DELAYEDEXPANSION link: https://stackoverflow.com/a/30284028/2128947
You can use if errorlevel? as shown, but you must interrogate errorlevel in reverse-order as if errorlevel n is true for errorlevel being n or greater than n.
The code shown will set errorlevel to 0 (using cd .) after whatever actions you choose to execute so any change to errorlevel made by those actions is overridden and will not cause any of the other errorlevel actions to be executed. If none of the actions is executed, reported will remain undefined, so the fact that it's undefined tells us that the original errorlevel was 0.
I need a way to either not use the for statement, or find a way to break out of the looping process if a condition is met.
Here's what I have now...
for /f "delims=" %%a in ('type pclist.txt') do (
ping -n 1 %%a | findstr /i "reply" >nul 2>nul
if %errorlevel% equ 0 (
if exist "\\%%a\c$\windows\temp\installed.txt" (
echo %%a - Already installed >>results.txt
)
if not exist "\\%%a\c$\windows\temp\installed.txt" (
echo %%a - Not installed >>results.txt
)
)
ping -n 1 %%a | findstr /i "timed" >nul 2>nul
if %errorlevel% equ 0 echo %%a - No PING response >>results.txt
ping -n 1 %%a | findstr /i "transmit" >nul 2>nul
if %errorlevel% equ 0 echo %%a - PING transmit failed >>results.txt
)
This gives me this kind of result...
192.168.144.1 - Already installed
192.168.144.1 - No PING response
192.168.144.1 - PING transmit failure
192 168.144.2 - Already installed
192.168.144.2 - No PING response
192.168.144.2 - PING transmit failure
192.168.144.3 - Not installed
192.168.144.3 - No PING response
192.168.144.3 - PING transmit failure
What I'd like to do is be able to exit the for loop when whatever first condition is met. So, I would have this kind of result instead...
192.168.144.1 - Already installed
192 168.144.2 - Already installed
192.168.144.3 - Not installed
I'm hoping I'm simply overlooking something simple and this will be just another one of those I-D-10-T errors for me. (lol)
Thanx in advance.
In plain English. Here's the goal:
Using FOR command, read list of IP addresses from text file.
For each IP address read, PING and check response.
If PING returns a reply, check for existence of file.
If file exists,
ECHO value 1 to results file, end FOR loop, proceed with next IP address in list.
If file does not exist,
ECHO value 2 to results file, end FOR loop, proceed with next IP address in list.
If PING does not return a reply, ECHO PING error text to results file, end FOR loop, proceed with next IP address in list.
I hope that's a bit more understandable.
Thanx again.
To avoid nested IF/Else code blocks you should use subs with calls. The use of C:\windows\temp might also be a problem when redirected to C:\Users\%USERNAME%\AppData\Local\Temp. TTL is a better indicator for the ping - less depending on the locale.
#Echo off
Set Res=^>^>Results.txt
Echo %date% %time% %Res:~1%
Set Inst=Windows\temp\installed.txt
for /f "delims=" %%a in ('type pclist.txt') do Call :TestPC %%a
Type %Res:~2%
Goto :Eof
:TestPC
ping -n 1 -w 500 %1|findstr "TTL">nul 2>&1||(Call :Check %1 &Goto :Eof)
:: A rights Problem might exist
if exist "\\%1\c$\%Inst%" echo %1 - Already installed %Res%
if not exist "\\%1\c$\%Inst%" echo %1 - Not installed %Res%
Goto :Eof
:Check
ping -n 1 -w 500 %1 | findstr /i "timed" >nul 2>nul
if %errorlevel% equ 0 %Res% echo %1 - No PING response
ping -n 1 -w 500 %1 | findstr /i "transmit" >nul 2>nul
if %errorlevel% equ 0 %Res% echo %1 - PING transmit failed
Goto :Eof
returns this output
Mi 10/26/2016 17:46:35,78
192.168.3.91 - Not installed
192.168.3.95 - No PING response
192.168.3.92 - Already installed
if %errorlevel% equ 0 (
(used multiple times) - %errorlevel% refers to the value of errorlevel at the time the FOR is parsed not at run-time. You need to substitute
if not errorlevel 1
in each case to provide the required functionality (if run-time errorlevel is not (1 or greater))
Hence, you "sample current output" is bogus - you cannot get that output with the code you've shown as %errorlevel% will not change with each loop. Furthermore, your sample shows "failure" whereas you code specifies "failed".
What do you mean by whatever first condition is met ? You could get your proposed output by simply removing or commenting-out the 4 lines following the closure of your if statement.
I'm trying to create a little batch file that checks multiple PCs read from a text file. For any PCs it finds are pingable, it writes a line in a "results" text file saying so. Here's what I've got:
#Echo off
set file=C:\logs\registercheck.txt
date /t >%file%
FOR /F %%I IN (C:\work\regnames.txt) DO (ping /n 1 %%I | ping /n 1 %%I | IF errorlevel 1 goto :nextreg | echo %%I is still on and has not been powered off! >>%file% | :nextreg)
PAUSE
So...when I run the file, I get multiple lines of "goto was unexpected at this time" and the only thing written in my output text file is the date. What am I doing wrong?
Thank you!
#Echo off
setlocal enableextensions disabledelayedexpansion
set "logFile=C:\logs\registercheck.txt"
set "inputFile=C:\work\regnames.txt"
>>"%logFile%" date /t
for /f "usebackq delims=" %%i in ("%inputFile%") do (
ping -n 1 %%i >nul 2>nul
if not errorlevel 1 (
>>"%logFile%" echo(%%i is still on and has not been powered off!
)
)
You have two errors.
The first is that to put all the commands in a single line, the separator is not the pipe character (|) but the ampersand (&)
The second is that inside the do code block of the for command, if one goto is executed, the for command is finished, independently of where the label is placed. And labels inside for code blocks usually generate errors (depends of its position).
If instead of the previous code, you want a single line loop, it can be written as
for /f "usebackq delims=" %%i in ("%inputFile%") do ( ping -n 1 %%i >nul 2>nul & if not errorlevel 1 >>"%logFile%" echo(%%i is still on and has not been powered off! )
or
for /f "usebackq delims=" %%i in ("%inputFile%") do ( ping -n 1 %%i >nul 2>nul && >>"%logFile%" echo(%%i is still on and has not been powered off! )
that makes use of the && construct. It is intended as a shortcut for the if not errorlevel 1 .... If the command at the left of the && does not raise an errorlevel, then the command on the right side is executed.
This for the batch sintax. Now the ping. There is a difference in how ping command behaves depending of the ip version. It is not the same to ping an ipv4 address than to ping an ipv6 address. If needed you can grab from here a subrotine to handle the differences.
I am working on setting up a LAN ping test using a batch file. The code i have works great for websites but it acts strange for local IPs. I am running the ping test on 3 computers that i know the IPs of. No matter which one i unplug, when i run the code below, the %errorlevel% is always 0 on all three computers. It never equals to 1 like it does on a website. How can i resolve this?
#echo off
cls
Set IPaddress=www.google.com
PING %IPaddress% -n 1
call :PingTest
Set IPaddress=www.yahoo.com
PING %IPaddress% -n 1
call :PingTest
Set IPaddress=www.unabletoping.com
PING %IPaddress% -n 1
call :PingTest
pause > null
exit
:PingTest
IF %errorlevel% EQU 1 (echo "Server is Offline") else (GOTO:EOF)
When you ping an non accesible address in your subnet, you get an "unreachable" answer, with 1 packet sent, 1 packed received, 0 packets lost. Errorlevel is not set.
When you ping an non accesible address out of your subnet, you get a "timeout" answer, with 1 packet sent, 0 packet received, 1 packet lost. Errorlevel is set.
And, you can ping an active machine, lost packets and get an errorlevel
And, you can ping an active/inactive machine, get TTL expired and get no errorlevel
Better, check for content of ping response.
ping -n 1 192.168.1.1 | find "TTL=" >nul
if errorlevel 1 (
echo host not reachable
) else (
echo host reachable
)
While I cannot replicate your issue, I do have a few recommendations for your script. (See my comment for questions regarding the issue)
When creating variables encapsulate the scope. setlocal and endlocal
When exiting a script, use the /b flag as to not kill the caller's command prompt.
nul not null.
Example ():
#echo off
setlocal
cls
set "IPaddress=www.google.com"
call :PingVerbose "%IPaddress%"
call :PingVerbose "www.yahoo.com"
call :PingVerbose "www.microsoft.com"
pause>nul
endlocal
exit /b 0
:Ping <Address>
ping "%~1" -n 1 >nul
exit /b %ErrorLevel%
:PingVerbose <Address>
call :Ping %1 && echo %~1 is Online || echo %~1 is Offline
exit /b %ErrorLevel%
Though I also cannot replicate your issue, and too have a suggestion to better your script -
#echo off & cls
set addresses=10.1.1.666 10.124.412.14 10.7.254.1
for %%a in (%addresses%) do ping %%a -n 1 > nul || echo %%a is offline
Note that the command after || will only be executed if an error level is set by the ping.
Taking what others have mentioned, I wanted to show how one may need to do everything shown above plus the use of modified variables such as a counter in a loop.
Note: using "setlocal enabledelayedexpansion" allows the use of modified variables in a loop etc..
#echo off
setlocal enabledelayedexpansion
REM List of systems to check
set list=www.google.com www.yahoo.com www.notasite.com
set /a failed=0
set /a passed=0
set /a count=0
echo PingTest Servers on %list% :
(for %%a in (%list%) do (
set /a "count+=1"
call :PingVerbose %%a && set /a "passed=!passed!+1" || set /a "failed=!failed!+1"
))
echo ------------
echo Result: %passed% of %count% systems are pingable
pause
endlocal
exit /b 0
:Ping <Address>
ping "%~1" -n 1 >NUL
exit /b %ErrorLevel%
:PingVerbose <Address>
call :Ping %1 && echo %~1 - [ONLINE] || echo %~1 - [OFFLINE]
exit /b %ErrorLevel%
Output:
PingTest Servers on www.google.com www.yahoo.com www.notasite.com :
www.google.com - [ONLINE]
www.yahoo.com - [ONLINE]
www.notasite.com - [OFFLINE]
------------
Result: 2 of 3 systems are pingable
Press any key to continue . . .
I've currently made this but there is a unexpected error in the for loop.
Please help.
#ECHO OFF
COLOR 1F
TITLE (Ash's Script) Server Ping Pong
rem ---------------------------------------------------------------------------------------------------------------
ECHO Started %time% %date% > X:\Scripts\ServerPing.txt
rem ---------------------------------------------------------------------------------------------------------------
FOR /f "tokens=*" %%i in (X:\Scripts\ComputerLists\ServerList.csv) DO (
PING %%i -n 1 -w 3
IF ERRORLEVEL 0 (
ECHO %%i ONLINE %time%>> X:\Scripts\ServerPing.txt
) ELSE (
ECHO %%i OFFLINE %time%>> X:\scripts\ServerPing.txt
)
)
rem ---------------------------------------------------------------------------------------------------------------
IF ERRORLEVEL 0 is always true.
Use this instead:
if not errorlevel 1
Also change the redirection on the echo to files:
>>X:\Scripts\ServerPing.txt ECHO %%i ONLINE %time%
This eliminates a problem when the last character is a number (of a stream)
Another issue is that %time% is evaluated when the loop starts - to get a dynamic time in the log then enable delayed expansion and use !time! instead of %time%