Comando por lotes para detectar todos los problemas de ping posibles

Tengo una pregunta sobre la verificación de que un ping está regresando correctamente en un comando por lotes. Actualmente tengo que verificar un ping de 3 formas diferentes para saber que el servidor está realmente activo. Quiero combinarlos en un solo comando de ping. He intentado usar diferentes niveles de error o no errorlevel 0 etc. Ninguno de ellos captura todos los escenarios posibles. Esto es lo que he estado usando:

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 

Hay dos maneras de verificar el éxito o el fracaso del comando ping: pruebe el nivel de error después de la ejecución o pruebe la salida del comando. Para ambos casos, no es lo mismo verificar una dirección ipv4 o ipv6.

Las preguntas son: ¿cómo se comporta el ping ?, ¿cuál es su resultado? ¿Cuándo se establece errorlevel ?

El nivel de errorlevel

Si estamos trabajando con ipv6, las reglas son

  • errorlevel se establece cuando no hay respuesta para todos los paquetes enviados (se pierden todos los paquetes)

  • errorlevel no se establece si hay una respuesta a cualquiera de los paquetes enviados

ipv6 tiene un comportamiento constante y la comprobación del errorlevel es una forma confiable de saber si la máquina está en línea.

En ipv4 las reglas son diferentes

  • errorlevel se establece cuando no hay respuesta a al menos uno de los paquetes enviados

  • errorlevel no se establece cuando hay una respuesta a todos los paquetes enviados (no se pierde ningún paquete)

Pero, en ipv4, hacer ping a una máquina no disponible en la misma subred no establece el nivel de errorlevel , se obtiene una respuesta “inalcanzable”, con n packets sent, n packed received, 0 packets lost , todos los paquetes obtienen una respuesta del mismo máquina que envía los paquetes.

Este comportamiento en ipv4 cuando la máquina está en la misma subred hace que falle la comprobación de errorlevel.

¿Cómo resolver el problema en ipv4? Control de salida

La salida del comando ping puede verificarse, si la cadena TTL= está presente en la salida, la máquina objective está en línea.

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

Pero este enfoque que funciona en ipv4 fallará con ipv6 ya que este campo no se ha incluido en la salida de ping (y se le ha cambiado el nombre, en ipv6 se llama límite de salto )


Para una solución “general”, esto (adaptado de una respuesta anterior) se puede utilizar (parece mucho código, pero casi todos son comentarios). La operación de ping y el manejo de salida se envuelven dentro de una subrutina a la que se llama con la dirección / nombre de host pasado como el primer argumento del archivo por lotes.

 @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% 
 ping.exe -n 1 %domain% >tempfile if not errorlevel 1 ( findstr /i /c"unreachable" /c:"TTL expired" > null if errorlevel 1 goto :OK ) :Noserver 

debe replicar su prueba con un solo ping. No estoy seguro si ping devuelve errorlevel distinto de cero para todas las condiciones de error, o posiblemente una de sus cadenas de destino y errorlevel 0. Debería especificar.