Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
768 views
in Technique[技术] by (71.8m points)

command line - Batch Script on 2008 server - If Ping successful then

I am attempting to write a script that will check to see if a computer is on my LAN before running the rest of my script. It is a simple backup script using robocopy but I would like it to output a file based on whether it was successful or not. This is what I have.

set machine=userbox
ping -n 1 %machine% > nul
if errorlevel 1 goto BAD
goto GOOD
:GOOD
robocopy source destination
echo "backup complete" > c:scriptsackupgood-%machine%.log
shutdown /s /m \%machine% /t 600
goto END
:BAD
echo "Computer not on" > c:scripts\%machine%-offline.log
:END

Right now the script is not detecting whether the system is on or not and it is assuming it is on and continues with the script as if the machine was able to be pinged.

Can someone point out why the error is not passing or perhaps someone has a better way of determining if a system is online.

Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The "problem" with your code is the management of the errorlevel to determine if the machine is or not online.

The questions are: how does ping behave?, when is errorlevel set?

If we are working with ipv6, the rules are

  • errorlevel is set when there is no reply for all of the sent packets (all packets are lost)

  • errorlevel is not set if there is a reply to any of the sent packets

ipv6 has a consistent behaviour and checking the errorlevel is a reliable way to know if the machine is online.

In ipv4 the rules are different

  • errorlevel is set when there is no reply to at least one of the sent packets

  • errorlevel is not set when there is a reply to all of the sent packets (no packet lost)

But pinging an non available machine on the same subnet does no set the errorlevel, you get an "unreachable" answer, with n packets sent, n packed received, 0 packets lost, all the packets get a reply from the same machine sending the packets.

This behaviour in ipv4 when the machine is in the same subnet makes the errorlevel check fail.

How to solve the problem in ipv4?

The output of the ping command can be checked, if the string TTL= is present in the output, the target machine is online.

ping -n 1 10.0.0.1 | find "TTL=" >nul 
if errorlevel 1 ( 
    echo offline 
) else (
    echo online
)

For a "general" solution, this (adapted from a previous answer) can be used (seems a lot of code, but almost all are comments)

@echo off

    setlocal enableextensions disabledelayedexpansion

    if "%~1"=="" goto :eof

    call :isOnline "%~1"
    if not errorlevel 1 ( echo ONLINE ) else ( echo OFFLINE )

    endlocal
    exit /b

:isOnline address pingCount
    setlocal enableextensions disabledelayedexpansion

    :: send only one ping packed unless it is indicated to send more than one
    set /a "pingCount=0", "pingCount+=%~2" >nul 2>nul 
    if %pingCount% lss 1 set "pingCount=1"

    :: a temporary file is needed to capture ping output for later processing
    set "tempFile=%temp%\%~nx0.%random%.tmp"

    :: ping the indicated address getting command output and errorlevel
    ping -w 1000 -n %pingCount% "%~1" > "%tempFile%"  && set "pingError=" || set "pingError=1"

    ::
    :: When pinging, the behaviours of ipv4 and ipv6 are different
    ::
    :: we get errorlevel = 1 when
    ::    ipv4 - when at least one packet is lost. When sending more than one packet
    ::           the easiest way to check for reply is search the string "TTL=" in 
    ::           the output of the command.
    ::    ipv6 - when all packet are lost.
    ::
    :: we get errorlevel = 0 when
    ::    ipv4 - all packets are received. BUT pinging a inactive host on the same  
    ::           subnet result in no packet lost. It is necessary to check for "TTL=" 
    ::           string in the output of the ping command
    ::    ipv6 - at least one packet reaches the host
    ::
    :: We can try to determine if the input address (or host name) will result in 
    :: ipv4 or ipv6 pinging, but it is easier to check the result of the command
    ::
    ::                          +--------------+-------------+
    ::                          | TTL= present |    No TTL   | 
    ::  +-----------------------+--------------+-------------+
    ::  | ipv4    errorlevel 0  |      OK      |    ERROR    |
    ::  |         errorlevel 1  |      OK      |    ERROR    | 
    ::  +-----------------------+--------------+-------------+ 
    ::  | ipv6    errorlevel 0  |              |      OK     |
    ::  |         errorlevel 1  |              |    ERROR    |
    ::  +-----------------------+----------------------------+
    ::
    :: So, if TTL= is present in output, host is online. If TTL= is not present,  
    :: errorlevel is 0 and the address is ipv6 then host is online. In the rest 
    :: of the cases host is offline.
    ::
    :: To determine the ip version, a regular expresion to match a ipv6 address is 
    :: used with findstr. As it will be only tested in the case of no errorlevel, 
    :: the ip address will be present in ping command output.

    set "exitCode=1"
    >nul 2>nul (
        find "TTL=" "%tempFile%" && ( set "exitCode=0" ) || (
            if not defined pingError (
                findstr /r /c:" [a-f0-9:][a-f0-9]*:[a-f0-9:%%]*[a-f0-9]: " "%tempFile%" && set "exitCode=0"
            )
        )
        del /q "%tempFile%"
    )

    :: cleanup and return errorlevel: 0=online , 1=offline 
    endlocal & exit /b %exitCode%

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...