我的 Windows 服务器通过两个默认网关连接到远程办公网络。
默认网关
172.20.0.1 Primary
172.20.0.254 Secondary
// Secondary connected with
// 4G SIM card VPN
服务器的初始配置
172.20.0.10 IP Address
255.255.255.0 Subnet Mask
172.20.0.1 Default Gateway
我想在服务器上运行一个批处理脚本,检测主网关何时172.20.0.1
出现故障并自动将服务器切换到辅助网关172.20.0.254
,反之亦然。
我想通过定期 ping 当前网关来检测故障。
Pinging 172.20.105.1 with 32 bytes of data:
Reply from 172.20.0.1: bytes=32 time<1ms TTL=255
Reply from 172.20.0.1: bytes=32 time=1ms TTL=255
Reply from 172.20.0.1: bytes=32 time=1ms TTL=255
当 ping 失败时,它不会返回“TTL=”并且脚本会假定网关已关闭并切换到另一个网关。
@echo off
setlocal enableextensions enabledelayedexpansion
:loop
ping 172.20.0.1 -n 2
timeout /t 10
set "str1=%~1"
if not "%str1:"TTL="=%" == "%str1%" (
echo "Primary Gateway NOT reachable"
netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254
)
echo "Primary Data UP"
goto loop
有没有更好的方法在服务器端完成这个任务?
答案1
@echo off && setlocal enabledelayedexpansion
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Primary Gateway NOT reachable"
set "_msg#002=Primary Data UP"
mode.com con: cols=60 lines=5
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j"
%:^)
title <nul
set "_dns=" <nul
echo/!_$E![1F!_$E![0J
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"
title Gateway: !_dns!
echo/!_bs!!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Primary=Secondary!
); else 2>nul =;(
echo; !_msg#001:Primary=Secondary!
!_gtw#001!
echo; !_msg#002!
);=
);=
timeout /t 00010 /nobreak >nul
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)
或者...
@echo off && setlocal enabledelayedexpansion
set "_gtw#254=static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_msg#001=Primary Gateway NOT reachable"
set "_msg#002=Primary Data UP"
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" !_gtw#254!"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5
%:^)
title <nul & set "_dns=" <nul & echo/!_$E![1F!_$E![0J
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^<nul ^| find /v " "')do set "_dns=!_dns!%%~n"
title Gateway: !_dns! & echo/!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^) || =;(
if "!_dns!" == "172.20.0.1" 2>nul =;(echo; !_msg#001! & !_gtw#254! & echo; !_msg#002:Primary=Secondary!
); else 2>nul =;( echo; !_msg#001:Primary=Secondary! & !_gtw#001! & echo; !_msg#002! );=
);= & timeout /t 00010 /nobreak >nul & echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E! & goto %:^)
有没有更好的方法在服务器端完成这个任务?
- 是的,如果我考虑以下几点:
1.问题中的代码并未识别当前网关是否为主网关,也未识别是否已对辅助网关进行更改。
2.如果辅助网关发生故障,则永远不会将网关从辅助网关更改为主网关。
3.如果您的主要网关正在使用并且相应失败,则您的echo
和netsh
命令将被执行,但仅限于第一个网关正在使用并且第一次进入循环的情况,之后,第二个网关将始终被重复配置以供使用,即使在离线时也是如此。
4.这%~1
在set "str1=%~1"
由于缺乏关于所使用的参数的引用和/或比较的目的,您的问题毫无意义,其中参数%~1
定义一个变量str1
并且比较它的子字符串("%str1:"TTL="=%"
):
set "str1=%~1"
if not "%str1:"TTL="=%" == "%str1%"
附言从现在开始,参考你的answer...
5.上述项目中观察到/指出的项目1.,2.和3.在你的行动/效果中重复出现,也出现在你当前回答。
6.使用重定向重定向 ping 命令时无需创建文件,使用省略输出的替换>nul
并将重定向到运算符&&
(return 0), ||
(return non 0) 可以带来相同的结果,而无需额外的ìfs
,请记住,在关闭洗澡 脚本,创建的文件将保留在那里而不会被使用。
ping 172.20.0.1 -n 2 > pingtest.txt
if %errorlevel%==0 goto waiting
ping 172.20.0.1 -n 2 >nul && goto waiting
附言从现在起,请参考此答案的第 1 版
将来会进行编辑并添加动作/命令描述,但这会在我的空闲/空闲时间尽快完成。
A)定义变量,并允许在此定义或命令中使用子字符串,从而允许相关更改网关 .1和网关.254和:
set "_gtw#254=netsh interface ipv4 set address name="Ethernet" static 172.20.0.10 255.255.255.0 172.20.0.254"
set "_gtw#001=!_gtw#254:172.20.0.254=172.20.0.1!"
set "_msg#001=Primary Gateway NOT reachable"
set "_msg#002=Primary Data UP"
...
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Primary=Secondary!
);= else =;(
echo; !_msg#001:Primary=Secondary!
!_gtw#001!
echo; !_msg#002!
);=
b)首先在循环中获取命令的输出,并使用适当的令牌/分隔符获取当前正在使用的 DNS/网关的 IP,然后在第二个循环中,使用以下命令过滤/删除任何空格:netsh interface ipv4 show config
for /f
for /f
find /aVoid " " ...
for /f tokens^=2*delims^=: %%i in ('netsh interface ipv4 show config ^| findstr "DNS.*DHCP.*[0-9]"
')do for /f %%n in ('%ComSpec% /u /c echo="%%~i"^>nul ^| find /v " "')do set "_dns=!_dns!%%~n"
C)使用的命令ping
将花费大约 10 秒,因此显示已获得的 DNS / 网关的标题以及在此期间显示的一些消息可用于向用户发出正在运行活动的信号:
title Gateway: !_dns!
echo/!_bs!!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m
d)对于在:loop
,据我推测它的使用不是偶尔的,而且它的执行将持续一段时间,没有理由不进行一些额外的阐述,比如使用文本颜色美国国家标准而不是用cls
,只在相关的行上执行此操作,此外还要保持屏幕尺寸“已调整” mode
要显示的文本:
for /f tokens^=1*delims^=#skip^=4 %%i in ('echo;prompt $E#$H^|cmd.exe
')do set "_$E=%%~i" & set "_bs=%%~j" & mode.com con: cols=60 lines=5
:: $E set _$E [%%~i] to ESC Character
:: $H set _bs [%%~j] to BackSpace Character
:: Display size/buffer - number of columns wide and number of lines deep:
:: MODE CON[:] [COLS=c] [LINES=n]
:: mode.com con: cols=60 lines=5
title >nul & ... echo/!_$E![1F!_$E![0J
...
title Gateway: ... echo/!_$E![1;33m Please^^! Wait for few seconds...!_$E![0m
e)建立一个ping
数字(-n 6
)并计算()出现的次数find /Count
“ TTL
“使用重定向器进行输出|
并省略屏幕上的输出(>nul
),在此命令处理中,也可以充分利用运算符&&
和||
return 0
根据和定义相关行动retunr non 0
:
ping !_dns! -n 6 | find /c "TTL" | find "6" <nul && .. || ...
your ping cmd && (
echo/ Retuned 0
) || (
echo/ Retuned non 0
)
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul && goto %:^)
ping !_dns! -n 6 -w 500 | find /c "TTL" | find "6" >nul || if condition() else()
F)使用条件中的运算符return 0
,返回以重新DNS/Gateway
开始获取操作,并ping
以timeout
适当的间隔再次执行,如果“TTL”计数不匹配,则if
假设条件为return non 0
,并DNS/Gateway
使用varible:substrings=?
与条件相关的文本和命令编写当前假设:
if "!_dns!" == "172.20.0.1" 2>nul =;(
echo; !_msg#001!
!_gtw#254!
echo; !_msg#002:Primary=Secondary!
);= else =;(
echo; !_msg#001:Primary=Secondary!
!_gtw#001!
echo; !_msg#002!
);=
G)在上述项目中处理完操作之后,timeout
还需要执行命令循环以进行新的诊断,并根据命令返回执行相关操作,然后等待,然后清理(echo/ ESC[ANSI codes
)使用的行并重定向到启动新循环的goto
标签%:^)
,完美满足这些操作:
timeout /t 00010 /nobreak >nul
echo/!_$E![1F!_$E![0J!_$E![1F!_$E![0J!_$E!
goto %:^)
阅读更多:
答案2
谢谢大家。我找到了一个更简单的方法。方法如下。
@echo off
cls
:starting
ping 172.20.0.1 -n 2 > pingtest.txt
c:\windows\system32\findstr.exe "TTL=" pingtest.txt
if %errorlevel%==0 goto waiting
echo "DATA is DOWN switching to BACKUP Network"
netsh interface ipv4 set address name="Ethernet" static 172.20.0.2 255.255.255.0 172.20.0.254
timeout /t 60
:waiting
echo "DATA is working witing for delay"
timeout /t 60
goto starting