1 command-line batch-file windows-server-2008
我正在尝试编写一个脚本,在运行脚本的其余部分之前检查计算机是否在我的 LAN 上。这是一个使用robocopy的简单备份脚本,但我希望它根据是否成功输出一个文件。这就是我所拥有的。
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
Run Code Online (Sandbox Code Playgroud)
现在,脚本不会检测系统是否打开,而是假设系统已打开并继续执行脚本,就好像计算机能够被 ping 通一样。
有人可以指出为什么错误没有通过,或者也许有人有更好的方法来确定系统是否在线。
提前致谢。
您的代码的“问题”是确定errorlevel机器是否在线的管理。
问题是:行为如何ping?何时errorlevel设置?
如果我们使用 ipv6,规则是
errorlevel当所有发送的数据包都没有回复时设置(所有数据包都丢失)
errorlevel如果对任何发送的数据包有回复,则不设置
ipv6 具有一致的行为,检查错误级别是了解机器是否在线的可靠方法。
在 ipv4 中,规则有所不同
errorlevel当至少一个发送的数据包没有回复时设置
errorlevel当所有发送的数据包都有回复时不设置(没有数据包丢失)
但是 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
)
Run Code Online (Sandbox Code Playgroud)
对于“通用”解决方案,可以使用这个(改编自之前的答案)(似乎有很多代码,但几乎都是注释)
@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%
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
26281 次 |
| 最近记录: |