I am trying to create an automated ping test using a .cmd file that pulls the ip addresses from a file called computers. It looks like it works for the most part but all the ping test after the first come back negative or dead.
#echo off
set fnm=C:\Users\jelliott\Desktop\computers.txt
set lnm=C:\Users\jelliott\Desktop\results.txt
if exist %fnm% goto Label1
echo.
echo Cannot find %fnm%
echo.
Pause
goto :eof
:Label1
echo PingTest STARTED on %date% at %time% > %lnm%
echo ================================================= >> %lnm%
echo.
for /f %%i in (%fnm%) do call :Sub %%i
echo.
echo ================================================= >> %lnm%
echo PingTest ENDED on %date% at %time% >> %lnm%
echo ... now exiting
goto :eof
:Sub
echo Testing %1
set state=alive
ping -n 1 %1
if errorlevel 1 set state=dead
echo %1 is %state% >> %lnm%
I don't know if this is the source of the problem but the errorlevel after a ping request is not reliable: it is not always set on 0 after a successful ping. The most reliable way to check a successful ping is to search for "TTL=" in the output of the ping command. The output of a successful ping always contains the TTL of the ping answer. In other cases, the output won't conain "TTL=".
Check the errorlevel of this command instead:
ping -n 1 %1 | find "TTL="
find allows to search for a literal string in some text. It will set the errorlevel on 0 if it is found and 1 otherwise. You can also use findstr instead of find.
EDIT: This is only in case the addresses you're pinging to are IPv4. For IPv6 addresses, the errorlevel is set correctly. For IPv6 no TTL is printed so the errorlevel must be used to check if the ping succeeded or not. [Here] you can find a general way to check if the ping was successful or not (either it is IPv4 or IPv6). Thank you MC ND for the remark and the link. If you ever want to force IPv4 or IPv6, you can use respectively the -4 or the -6 flags of ping.
Related
I have a little script to ping several IP addresses that are located in a text file called computers.txt:
The output currently looks like this:
I would like to add a description of where the IP addresses are like so:
What would be the best way to do this?
#echo off
set fnm=C:\Users\jelliott\Desktop\computers.txt
set lnm=C:\Users\jelliott\Desktop\results.txt
if exist %fnm% goto Label1
echo.
echo Cannot find %fnm%
echo.
Pause
goto :eof
:Label1
echo PingTest STARTED on %date% at %time% > %lnm%
echo ================================================= >> %lnm%
echo.
for /f %%i in (%fnm%) do call :Sub %%i
echo.
echo ================================================= >> %lnm%
echo PingTest ENDED on %date% at %time% >> %lnm%
echo ... now exiting
goto :eof
:Sub
echo Testing %1
set state=alive
ping -n 1 %1 | find "TTL="
if errorlevel 1 set state=dead
echo %1 is %state% >> %lnm%
When adding the titles to your computers.txt like this:
1.2.3.4 Clinic
12.13.14.15 Registration
78.79.251.123 Somwhere else with spaces
You can alter your script a bit:
The for loop gets altered to: for /f "tokens=1*" %%i in (%fnm%) do call :Sub %%i "%%j"
Tokens specifies what part of the line you want to have. The default delimiters are spaces and new lines. So with this the first token of one line gets saved to %%i and the rest of the line (*) get saved to %%j as j is after i in the alphabet. The %%j need to get enclosed in double quotes to have multiple words together as one parameter.
Now change your subfunction to use the second parameter as well:
echo Testing %1 %~2
REM Other stuff to ping...
echo %~2: %1 is %state% >> %lnm%
The ~ removes the surrounding quotes again.
Example output:
PingTest STARTED on 11.01.2017 at 7:48:52,69
=================================================
Clinic: 1.2.3.4 is alive
Registration: 12.13.14.15 is dead
Somwhere else with spaces: 78.79.251.123 is alive
=================================================
PingTest ENDED on 11.01.2017 at 7:49:04,70
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.
is there a way to check if a link gets a signal using the "ping" command and go to that website, and if it does not get a signal, test it for a different website and so on? This is using a batch (.bat) file. Thank you!
You can use ERRORLEVEL after your ping command
ping -n 1 yoursite
if ERRORLEVEL 0 do-something-with yoursite
Then you need a loop so your batch file could look like
#echo off
for /F "tokens=*" %%A in (domains.txt) do (
ping -w 1000 -n 1 %%A > NUL
if ERRORLEVEL 0 if not ERRORLEVEL 1 echo %%A did reply
if ERRORLEVEL 1 if not ERRORLEVEL 2 echo %%A did not reply
)
ping -n 1 www.google.com && iexplore www.google.com || echo no ping.
NOTE: some sites (for example www.hp.com) don't reply to ping. This would give false negatives.
I want to ping an IP address every 5 seconds.
If the ping fails, write the date and time to a file.
Here is my non-working attempt... the loop works as intended, but I can't get it to write to a file if the ping fails.
#ECHO OFF
set IPADDRESS=172.30.1.36
set INTERVAL=5
:PINGINTERVAL
ping %IPADDRESS% -n 1
if errorlevel 1 echo %date% %time% >> failurelog.txt
timeout %INTERVAL%
GOTO PINGINTERVAL
In ipv4, ping command only raises errorlevel if there are packets lost. But in you are pinging a machine in your same subnet, you get no packets lost.
The easier way to test for ping success is to test for the "TTL=" string in the output of the ping
ping -n 1 %ipaddress% | find "TTL=" > nul
if errorlevel 1 echo %date% %time% >> failurelog.txt
This will ping with no intervals until connection is lost. When it does, it records the failed ping "time and date" on a file to the Desktop. Then, it tries to ping again in 1 second and so on until connection is reestablished, at which point it stops, until next ping is missed. Copy code, change the "set IPADDRESS", and save as a .bat file. Good luck
#ECHO OFF
set IPADDRESS=172.16.100.30
set INTERVAL=1
:PINGINTERVAL
ping -n 1 %ipaddress% | find "TTL=" >nul
if errorlevel 1 (
echo %date% %time% >> C:\Users\%username%\Desktop\failping.txt
echo %date% %time%
timeout %INTERVAL% >nul
)
GOTO PINGINTERVAL
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 . . .