batch-file - print - date format windows bat
Batch Script en el servidor de 2008: si Ping es exitoso, entonces (3)
Intento escribir un script que compruebe si hay una computadora en mi LAN antes de ejecutar el resto de mi script. Es un script de copia de seguridad simple que utiliza robocopy, pero me gustaría que muestre un archivo en función de si fue exitoso o no. Esto es lo que tengo.
set machine=userbox
ping -n 1 %machine% > nul
if errorlevel 1 goto BAD
goto GOOD
:GOOD
robocopy source destination
echo "backup complete" > c:/scripts/backupgood-%machine%.log
shutdown /s /m //%machine% /t 600
goto END
:BAD
echo "Computer not on" > c:/scripts/%machine%-offline.log
:END
En este momento, el script no detecta si el sistema está encendido o no y está asumiendo que está activado y continúa con el script como si la máquina pudiera conectarse.
¿Puede alguien señalar por qué el error no está pasando o quizás alguien tiene una mejor manera de determinar si un sistema está en línea?
Gracias por adelantado.
Puede verificar la presencia de su directorio remoto:
IF EXIST "//%machine%/Share/To/Check" (
ECHO %machine% is available.
) ELSE (
ECHO %machine% is not available.
)
El "problema" con su código es la gestión del errorlevel
para determinar si la máquina está o no en línea.
Las preguntas son: ¿cómo se comporta el ping
?, ¿cuándo se establece 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 enviadoserrorlevel
no se establece cuando hay una respuesta a todos los paquetes enviados (no se pierde ningún paquete)
Pero 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 de la misma 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?
La salida del comando ping
puede verificarse, si la cadena TTL=
está presente en la salida, la máquina objetivo está en línea.
ping -n 1 10.0.0.1 | find "TTL=" >nul
if errorlevel 1 (
echo offline
) else (
echo online
)
Para una solución "general", esto (adaptado de una respuesta anterior) se puede usar (parece mucho código, pero casi todos son comentarios)
@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%
Gracias a ambos. Intenté ambos, pero al final esto es lo que funcionó para mí
set machine=userbox
ping -n 1 %machine% | find "TTL=" >nul
IF errorlevel 1 (
echo "Computer Not On" %date% %time% > c:/scripts/%machine%-computeroff.log
) ELSE (
robocopy source destination
shutdown.exe /s /m //%machine% /c "Mandatory Shutdown in progress. You have 10 minutes" /t 600
echo "shutdown command given" %date% %time% > c:/scripts/shutdown-%machine%.log
Aclamaciones