批处理命令以捕获所有可能的ping问题

时间:2015-01-02 17:34:04

标签: batch-file

我有一个关于验证ping是否在批处理命令中正确返回的问题。目前我必须检查ping 3种不同的方式,以了解服务器实际上已启动。我想将它们组合成一个单独的ping命令。我尝试使用不同的错误级别或不错误等级0等。他们都没有捕获所有可能的情况。这是我一直在使用的:

Set /p domain=Enter IP address:
set state=up

@ping.exe -n 1 %domain% | find "unreachable" > null && set state=down
if "%state%" == "down" goto :NoServer

@ping.exe -n 1 %domain% | find "TTL expired" > null && set state=down
if "%state%" == "down" goto :NoServer

@ping.exe -n 1 %domain%
if errorlevel 1 goto :NoServer

2 个答案:

答案 0 :(得分:4)

有两种方法可以检查ping命令的成功或失败:执行后测试errorlevel或测试命令的输出。对于这两种情况,检查ipv4或ipv6地址是不一样的。

问题是:ping如何表现?它的输出是什么?什么时候设置errorlevel

errorlevel

如果我们使用ipv6,规则是

  • errorlevel在没有回复所有已发送的数据包(所有数据包丢失)时设置

  • 如果对任何已发送的数据包有回复,则
  • errorlevel未设置

ipv6具有一致的行为,检查errorlevel是了解机器是否在线的可靠方法。

在ipv4中,规则是不同的

    当没有回复至少一个已发送的数据包时,
  • errorlevel被设置

  • 当回复所有已发送的数据包(没有数据包丢失)时,
  • errorlevel未设置

但是,在ipv4中,ping同一子网上的一台不可用的机器没有设置errorlevel,你得到一个"无法访问"使用n packets sent, n packed received, 0 packets lost回答,所有数据包都会从发送数据包的同一台机器获得回复。

当机器在同一子网中时,ipv4中的此行为会导致错误级别检查失败。

如何解决ipv4中的问题?输出检查

可以检查ping命令的输出,如果输出中存在字符串TTL=,则目标计算机处于联机状态。

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

但这种在ipv4中工作的方法将因ipv6而失败,因为此字段未包含在ping输出中(并重命名,在ipv6中称为跳限制


对于"将军"解决方案,这(改编自以前的答案)可以使用(似乎很多代码,但几乎所有都是评论)。 ping操作和输出处理包含在子例程中,该子例程使用作为批处理文件的第一个参数传递的地址/主机名进行调用。

@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%

答案 1 :(得分:0)

ping.exe -n 1 %domain% >tempfile
if not errorlevel 1 (
 findstr /i /c"unreachable" /c:"TTL expired" > null
 if errorlevel 1 goto :OK
)

:Noserver

应该使用单个ping复制您的测试。我不确定ping是否为所有错误条件返回errorlevel非零,或者可能是您的目标字符串和errorlevel 0之一。您需要指定。