尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Windows批量路由追踪脚本:tracert自动化与无乱码日志实践

Windows批量路由追踪脚本:tracert自动化与无乱码日志实践 做运维的兄弟应该都有这种经历网络割接完老板问“新链路稳不稳”你手里只有一条 ping 的结果或者多个分支分公司同时反馈“上业务系统卡”你得一个个远程登录过去跑 tracert。这些场景下单条命令敲一次两次还行目标一多、次数一多手工操作不仅低效还特别容易漏记结果。我自己就是因为一次割接验证凌晨三点还在手动一条条跑 tracert回来后痛定思痛写了一个 Windows 批量路由追踪脚本读一个目标列表文件逐行执行 tracert结果自动落盘成带日期时间的日志文件同时解决了中文乱码问题在记事本里打开干干净净。今天把完整脚本和踩坑记录分享出来适合网络运维、桌面支持、SRE 这些需要经常验证路由连通性的同学直接抄作业。1. 为什么运维日常离不开批量路由追踪1.1 tracert 能告诉运维什么信息tracert 是 Windows 自带的网络诊断工具原理并不复杂它通过递增 TTLTime To Live的方式向目标地址连续发送 ICMP 回显请求每一跳转发设备在 TTL 减到 0 时会返回一个“超时”消息请求方据此记录下路径上每一跳的 IP 和响应时间。说白了它就是在帮你把数据包从本机到目标之间走过的“每个路口”都画出来。对运维来说tracert 最值钱的信息不是“通不通”而是“在哪一跳不通”。比如办公网访问云上业务系统很慢ping 说不清问题tracert 跑一次可能就会发现前面十几毫秒都很稳定到了某一跳突然 100ms 起步甚至丢包那问题大概率就出在这条链路或者这个节点上。举个例子某次用户反馈访问总部 ERP 特别慢。我远程过去跑了一条 tracert前面几跳到网关都是 1ms中间一跳突然变成 80ms后面几跳继续维持在高延迟最后目标端倒是通的。结合这个结果可以直接把排查方向锁定在中间那一跳所在的链路段而不是盲目去抓后端服务器。这种定位能力是 ping 完全给不了的。再比如割接后要确认流量是否真的走了新路径跑一次 tracert 对比路径上的中继 IP 是否符合预期比单纯 ping 通有意义得多。路径对比这件事恰恰是 tracert 最核心的运维价值。1.2 单条命令与批量脚本的差距在哪里很多人会说tracert 一条命令谁不会敲无非是 tracert 加个 IP。但实际运维场景里真正的瓶颈往往不在命令本身而在三个问题。第一个问题是目标数量。一个割接验证单涉及十几个业务系统 IP手工一个个敲每条 tracert 可能要等十几秒甚至更久默认 4 秒超时、30 跳敲完十几条十几分钟就过去了。第二个问题是结果留存。手工敲的结果在屏幕上滚过去就没了事后要做对比报告还得重新截屏或者复制非常痛苦。第三个问题是耗时控制。tracert 默认每个节点等 4000 毫秒批量场景下这个等待时间会成倍放大脚本里把等待时间调成 1000 毫秒甚至更低20 个目标能节约一半以上的时间。批量脚本的价值就是把“逐条敲命令、逐屏看结果、逐个保存”这三件事一次性自动化目标列表放文件里脚本循环去跑输出全部重定向到日志文件每跑完一个目标记录一条标记跑完整个列表再汇总一行。这样即使人不在电脑前回来打开日志就能看到完整的执行记录。1.3 这个脚本适用的三类使用场景我自己用下来这个脚本最值得推荐给下面三类场景。第一类是网络割接和变更验证。上线新链路、调整路由策略之后需要同时对多个关键业务地址做路径验证确认流量走的是预期路由这条链路各跳延迟是否正常。脚本一遍跑完日志就是验证凭证后续出报告或者复盘都有据可查。第二类是日常链路巡检。每周或者每月定期检查从本机到总部机房、云上网关、分支机构出口等若干固定目标的路径质量重点关注响应时间波动和丢包情况。配合 Windows 计划任务可以让它凌晨自动跑早上来直接看日志完全不占用白天的操作窗口。第三类是故障上报的初步定位。业务方反馈“到某个系统很卡”运维可以先拿这个脚本批量测一批相关目标业务服务器、数据库网关、公网出口快速判断问题是集中在某个目标、某个段还是整体出口链路的问题缩小排查范围。这三类场景有一个共同点都需要“多目标 留痕 可对比”这正是批量脚本的舒适区。2. 脚本设计思路与编码难题的拆解2.1 三层结构输入列表、循环追踪、日志落盘这个脚本我设计成非常典型的批处理三段式结构这个结构本身也是很多 Windows 运维脚本的通用模板。第一层是输入层。所有要测的目标地址统一放在一个文本文件里每行一个 IP 或域名支持用井号开头写注释支持空行。这样做的好处是改需求的时候完全不用碰脚本本体只需要编辑文本文件业务同事也可以很轻松地维护这个列表。第二层是处理层也就是 for /f 循环。脚本逐行读取目标文件跳过注释和空行对每个目标执行一次带参数的 tracert 命令。这里我用了延迟变量扩展setlocal enabledelayedexpansion因为循环体内要对计数器做自增如果不开启延迟扩展!n! 在循环里取到的就永远是初值这个坑很多人踩过。第三层是输出层。所有结果统一追加到日志文件日志文件名里带上日期时间戳避免多次运行互相覆盖命令执行的状态开始、完成、失败也一并写进日志方便事后对照。2.2 中文乱码的根源代码页与文本编码不匹配这个标题里我特意写了“无乱码”因为我第一次写这个脚本的时候确实被乱码折磨过。Windows 批处理涉及中文乱码根源通常不在脚本逻辑而是两个东西没对上cmd 当前使用的代码页codepage和脚本文件本身的文本编码。cmd 默认在简体中文 Windows 上是代码页 936对应 GBK/GB2312。如果脚本文件被保存成 UTF-8 编码那么 cmd 在执行到中文字符串时就会按 GBK 去解析 UTF-8 的字节结果就是控制台上一堆看不懂的字符也就是俗称的乱码。反过来脚本用 GBK 保存你又手动执行了 chcp 65001 切到 UTF-8一样会乱。更隐蔽的是日志文件的编码问题。tracert 输出的结果里有中文提示比如“通过最多 30 个跃点跟踪”、“请求超时”这些内容重定向到日志文件时会以 cmd 当前代码页对应的编码写入。也就是说如果你在 GBK 代码页下跑日志就是 GBK 编码如果你在 65001 代码页下跑日志才是 UTF-8。后续用什么编辑器打开日志编码匹配就无乱码不匹配就乱码。提示判断日志编码是否匹配可以用记事本打开中文显示正常说明编码匹配如果出现方块、问号或者一堆不认识的字符说明编码和查看器不匹配换一种编码方式打开再试。2.3 两套无乱码方案怎么选针对上面的乱码根源我整理了两套都能做到无乱码的方案。方案 A脚本文件保存为 ANSI/GBK 编码脚本内不主动切换代码页保持 cmd 默认的 936。这样脚本里的中文注释、echo 输出、tracert 的中文提示全部以 GBK 编码写入日志在 Windows 的记事本、Notepad默认代码页设置为 ANSI 时里打开都不乱码。缺点是日志拿到 Linux 上或者用某些只认 UTF-8 的编辑器打开会乱跨平台性一般。方案 B脚本文件保存为 UTF-8 with BOM脚本开头执行 chcp 65001 nul把代码页切到 UTF-8。这样脚本解析正常日志也以 UTF-8 编码落盘跨平台查看都没问题。缺点是个别老系统Windows 7 部分版本、精简版系统下 chcp 65001 配合批处理 for 循环存在兼容性怪癖可能出现光标错位、for 读取中文异常之类的问题。我个人推荐如果你是给自己公司内网用后续主要在本机或 Windows 服务器上看日志直接选方案 A 最省心零兼容性风险。如果日志要发给异地同事、要归档到 Linux 日志平台或者要配合日志采集工具做后续分析就选方案 B。下面脚本里给的是方案 A 的写法这也是我在多个 Windows Server 和 Win10/11 上实测最稳的版本。3. 完整脚本实现与 tracert 参数调优3.1 目标列表文件支持注释与空行脚本同目录下需要创建一个 targets.txt格式很简单每行一个目标 IP 或域名井号开头的行会被当作注释跳过空行也会被跳过。下面给一个示例# 内网核心资源 192.168.10.1 192.168.10.2 # 云上业务系统 223.5.5.5 www.example.com有两个细节值得注意。一是目标域名也可以写tracert 会自动解析成 IP二是如果想精确验证某个域名解析后的路径建议先手工 nslookup 一下把解析出来的 IP 写进列表因为域名解析结果可能随 DNS 策略变化导致两次追踪路径不一致对比时容易误判。3.2 脚本全量代码与逐段讲解完整的脚本如下我这里用的是 GBK/ANSI 方案直接复制保存为 batch_tracert.bat 就能用保存时记得选 ANSI 编码。echo off rem rem Windows 批量路由追踪脚本 rem 功能: 批量 tracert 检测目标路由输出日志 rem 编码: 保存为 ANSI/GBK, 使用 cmd 默认 936 代码页 rem 用法: 与 targets.txt 同目录运行 rem setlocal enabledelayedexpansion rem ---------- 可调参数 ---------- set TARGET_FILEtargets.txt set LOG_DIRlogs set MAX_HOPS30 set TIMEOUT1000 rem ---------------------------- if not exist %TARGET_FILE% ( echo [错误] 未找到 %TARGET_FILE% echo 请创建该文件, 每行一个 IP 或域名, # 开头为注释 goto :end ) if not exist %LOG_DIR% mkdir %LOG_DIR% set DATE_STAMP%date:~0,4%%date:~5,2%%date:~8,2% set TIME_STAMP%time:~0,2%%time:~3,2%%time:~6,2% set LOG_FILE%LOG_DIR%\tracert_%DATE_STAMP%_%TIME_STAMP%.log echo 批量路由追踪开始 %LOG_FILE% echo 时间: %date% %time% %LOG_FILE% echo 目标列表: %TARGET_FILE% %LOG_FILE% echo -------------------------------------------- %LOG_FILE% set /a n0 for /f usebackq delims %%i in (%TARGET_FILE%) do ( set line%%i if not !line:~0,1!# if not !line! ( set /a n1 echo [!n!] 开始: %%i echo [目标] %%i %LOG_FILE% tracert -d -h %MAX_HOPS% -w %TIMEOUT% %%i %LOG_FILE% 21 echo. %LOG_FILE% ) ) echo -------------------------------------------- %LOG_FILE% echo 全部完成, 共追踪 %n% 个目标 %LOG_FILE% echo. echo 追踪完成, 共 %n% 个目标, 日志: %LOG_FILE% echo. :end endlocal pause代码不长但每个细节都是踩坑换来的我逐段说下。顶部的 setlocal enabledelayedexpansion 必须要有循环体里的 !n!、!line! 依赖延迟变量展开。如果不加计数器不会递增判断注释的 !line:~0,1! 也取不到值脚本看起来“没反应”。日期时间戳这里用 %date% 和 %time% 做截取。%date:~0,4% 取年份%date:~5,2% 取月份%date:~8,2% 取日期拼出来是 20250101 这种 8 位日期。%time:~0,2% 是小时%time:~3,2% 是分钟%time:~6,2% 是秒。这里有个小坑当小时是个位数时%time:~0,2% 取到的可能是“ 9”前面带空格拼出的文件名里会带个空格。介意的话可以在 TIME_STAMP 里加个替换set TIME_STAMP%TIME_STAMP: 0%把空格替换成 0实测大多数系统上不影响使用但替换后样式更统一。for /f usebackq delims 这一行“usebackq”允许用双引号包裹文件名避免路径带空格时解析错误“delims”意思是不要按空格或 Tab 做列拆分把整行作为一个变量。如果不加 delims遇到 IP 后面的行尾空格或者域名行可能被截断。循环体里判断注释行用了 if not !line:~0,1!# 和 if not !line! 两个条件并列。注意这里不能用 %line:~0,1%因为在括号代码块里 %var% 是在解析时展开的而不是执行时展开必须用 !var! 延迟展开才能取到当前这一次循环的值。这是批处理最容易踩的坑。tracert 命令执行时用 追加写入日志21 把标准错误也合并进去。这样即使 tracert 报错比如目标不可达错误信息也能留在日志里不至于屏幕上有日志里没有。3.3 tracert 三个关键参数-d、-h、-w我脚本里给 tracert 带上了 -d -h 30 -w 1000 三个参数简单说下每个参数的作用和调优思路。-d 是“不将 IP 地址解析为主机名”。默认情况下 tracert 会对每一跳的 IP 做反向 DNS 查询把 202.97.x.x 解析成类似很长一串域名。这个解析过程每跳都要等一次 DNS 超时非常拖慢速度。批量场景下加 -d 能显著提速而且对大多数故障排查场景来说看 IP 已经足够。只有当你需要确认某个节点属于哪个运营商、哪个机房才需要去掉 -d 看完整主机名。-h 指定最大跳数默认 30。绝大多数场景下 30 已经足够内网路径通常十跳以内公网跨运营商也很少超过 30。如果你只关心前 20 跳把 -h 改成 20 可以更快结束相反如果遇到迂回路径可能要加大到 40。脚本里保留 30兼顾通用性。-w 是每个节点等待回复的超时时间单位毫秒默认 4000。tracert 对每一跳要发 3 个探测包每个都要等 -w 指定的超时。如果链路中有一段丢包默认 4 秒超时会让单条命令耗时大幅拉长。批量场景下我建议用 1000大多数正常响应都在几十毫秒内1000 毫秒足够判定“无响应”。再低可以试 500但可能误伤一些正常但高延迟的卫星链路或跨国链路。三个参数合起来的实际效果单目标从默认的“30跳 * 3包 * 可能4秒超时”最坏情况压缩到最多“30跳 * 3包 * 1秒超时”批量目标越多节省的时间越明显。注意如果目标网络禁 ICMPtracert 大概率全超时这不代表业务不可达一定要结合端口连通性测试综合判断别被日志里的“超时”吓到。3.4 日志命名与追加策略日志文件命名用了“tracert_日期_时间.log”的格式例如 tracert_20250101_093015.log。这样做的直接好处是多次运行互不覆盖每一次追踪记录是独立文件方便按时间回溯。落在 logs 子目录里也不至于跟脚本文件混在一起。有一点要提醒如果同一天内同一秒运行两次文件名可能冲突对日常人工运维来说概率极低但如果要挂在计划任务里又不小心配了每分钟执行就可能产生覆盖。对策是把时间戳精度做到秒或者干脆按“日期序号”递增命名我实测秒级时间戳在人工使用场景下够用计划任务按天跑更没问题。日志内部是“追加”逻辑而不是“覆盖”脚本每次运行先写一行开始时间和目标列表路径然后每个目标执行前写一行 [目标]执行结果紧跟其后目标与目标之间用空行分隔。这种格式下即使日志文件在运行中被中断已经写入的部分也完整可读排查问题时不至于因为尾部缺失而丢失前面所有数据。4. 日志管理与运维落地经验4.1 从追踪日志里快速定位关键信息tracert 输出落到日志文件后光靠肉眼慢慢翻效率太低。Windows 自带的 findstr 命令就是查看这类日志最好的工具。比如想找出所有带“请求超时”的节点可以这样findstr /C:请求超时 logs\tracert_*.log想统计每个目标最后是否到达也就是日志里“跟踪完成”的行findstr /C:跟踪完成 logs\tracert_*.log这里要提醒一句中文 Windows 上 tracert 输出“请求超时”和“跟踪完成”而英文系统是 Request timed out. 和 Trace complete.。如果你的生产环境是英文系统上面的中文搜索词要对应替换。这也是为什么有些团队干脆让脚本在英文环境下跑配一个英文关键词速查表反而减少混乱。另外如果日志是 GBK 编码在 bash 或者某些工具里 findstr 搜索中文关键词没问题findstr 原生支持 ANSI 代码页但如果日志将来被转成 UTF-8findstr 的中文关键词可能对不上那时候用 PowerShell 的 Select-String 更稳。4.2 与计划任务整合实现定期巡检这个脚本最实用的一种玩法是配合 Windows 任务计划程序做定时巡检。步骤很简单。先准备好 targets.txt里面放上你日常要盯的固定目标。然后在任务计划程序里新建一个任务触发器设为每天凌晨比如 02:00操作选择“启动程序”程序填 cmd.exe参数填 /c D:\scripts\batch_tracert.bat。注意如果脚本路径带空格要写成 /c D:\scripts\batch_tracert.bat 这种双引号套双引号的格式或者干脆把脚本放到不带空格的路径下省很多麻烦。还有一个细节脚本最后一行是 pause挂在计划任务里运行时 pause 会让 cmd 窗口挂着等待按键导致任务一直不结束。正确做法是给脚本增加一个判断当检测到传入参数时跳过 pause。我一般这样处理if not %1-silent pause然后在计划任务的参数里带上 -silent即 /c D:\scripts\batch_tracert.bat -silent。这样一个脚本既能人工双击运行最后等待按键看结果又能被计划任务静默执行互不干扰。任务计划跑起来以后想确认任务本身有没有正常执行可以在任务计划程序里看上次运行结果也可以直接看脚本生成的日志文件时间和大小。这两个证据结合基本能判断巡检链路有没有正常运行。如果发现任务没跑优先检查计划任务的“使用密码”和登录状态Windows 注销状态下部分任务默认不触发。4.3 日志保留策略与自动清理日志文件一天一个甚至一天多个时间长了会占不少空间尤其 tracert 日志如果目标多每条能到几十 KB。运维上建议给日志加一个简单的保留策略。最粗暴但有效的做法是脚本内建清理逻辑在运行前扫描 logs 目录删除超过 N 天的旧文件。用 forfiles 命令一行就能实现forfiles /p %LOG_DIR% /s /m *.log /d -%KEEP_DAYS% /c cmd /c del path 2nul把 KEEP_DAYS 设成 30日志最多保留一个月。-d -30 表示“修改时间早于 30 天前”。这个命令我第一次用的时候没加 2nul结果目录为空时报 “ERROR: No files found”看着像脚本出错实际不是加个错误重定向就干净了。如果日志还要进一步上报到日志采集系统建议在脚本里再输出一份 CSV 或者只包含关键字段的摘要文件因为完整 tracert 日志里的多行格式对采集解析不太友好。字段提取的思路我在后面扩展部分会细说。5. 常见问题与排查技巧实录5.1 脚本闪退、窗口瞬间消失这是批处理脚本最经典的问题双击运行窗口一闪就不见了根本来不及看报错。原因十有八九是语法错误、路径不对或者引号问题。排查分两步。第一步脚本开头加 pause或者在 for 循环前临时加一行 echo test先把执行停住看输出。第二步用命令行手动运行而不是双击按 WinR 输入 cmd在命令行里切到脚本目录直接敲 batch_tracert.bat 运行这样就算报错窗口也不会消失报错信息全部留在屏幕上。还有一个很隐蔽的原因脚本文件保存成了 UTF-8 with BOM但脚本里没有 chcp 65001这时 cmd 第一行会遇到 BOM 字符可能报 锘?不是内部或外部命令。解决方案是另存为 ANSI/GBK 编码方案 A或统一用方案 BUTF-8 with BOM chcp 65001不要混用。注意脚本文件保存编码必须和 cmd 代码页一致最稳妥的做法是文本编辑器保存时选 ANSIGBK不要在同一个文件里混用 UTF-8 和 GBK。5.2 日志出现乱码、显示问号乱码问题我在第二部分详细解释过根源实操中常见的三种情况再复述一遍。一是脚本内中文输出正常日志里的中文却变问号。通常是重定向到日志时cmd 用的是非 Unicode 代码页写入而日志查看工具假设 UTF-8。解决办法是统一编码方案要么全部 GBK要么全部 UTF-8不要脚本是 GBK 但日志非要拖到 UTF-8 的编辑器里看。二是日志在记事本打开正常但发到钉钉、企业微信或者 Linux 上就乱。这是 GBK 编码的跨平台通病临时应急可以先把文件用记事本打开另存为时选择 UTF-8 编码再发。长期方案是脚本改用方案 B输出 UTF-8 日志。三是在 for 循环里拼接中文路径时莫名多出特殊字符。这个坑在方案 B 下更明显原因是 UTF-8 下 cmd 对某些多字节字符的逐字节处理不完善。我的建议是脚本内部尽量少拼接含中文的路径路径变量单独定义、单独引用减少在循环体里做字符串截取。5.3 大量“请求超时”的排查思路脚本跑完日志里全是“请求超时”先别急着下结论说链路断了。tracert 的“请求超时”有两种截然不同的含义必须区分。一种是真的丢包或设备不响应。中间某一跳持续超时而后续跳数仍然有回复这通常只是那一跳设备做了限速或禁 ping数据包实际还是过去的。另一种是目标设备本身禁 ICMP比如很多云服务器默认禁 ping那么从某一段开始就会连续超时但这不代表业务访问有问题。判断方法是看最后一个可达跳之后是否还有回复最靠谱的还是直接配合端口连通性测试比如 telnet 目标端口、Test-NetConnection。还有一种情况是防火墙策略。某些安全设备会对 tracert 的递增 TTL 包做拦截表现为路径中途某跳开始全部超时但业务端口其实是通的。这种情况下别浪费时间调脚本直接找网络部门核实安全策略。5.4 脚本还能怎么扩展这个脚本的骨架完全可以扩展到很多相邻场景。最常见的三个扩展方向。第一个方向是“ping tracert”联动。在 tracert 前先 ping 一次目标ping 不通的直接标记失败不再浪费时间做路径追踪。脚本里加一行 ping -n 2 -w 1000 %%i nul 判断 errorlevel 就能实现。第二个方向是输出摘要 CSV。在循环体里用 findstr 从 tracert 结果中提取“跟踪完成”或“不可达”标记把目标、结果、耗时写到一个 CSV 文件后续用 Excel 透视或者接入监控平台都方便。批处理做文本提取比较笨但简单标记还是可以实现的。第三个方向是换用 PowerShell 重写一版。PowerShell 原生支持 UTF-8、对象操作和并行执行ForEach-Object -Parallel需要 PowerShell 7在处理几百个目标、需要精细解析输出时会顺手非常多。我目前这个 bat 版适合快速部署、双击即用的场景如果要接入自动化平台我更推荐在 bat 验证逻辑后再用 PowerShell 工程化封装一遍。写这个脚本的过程里我最大的体会是批处理看似“老古董”但在 Windows 运维的应急场景里它仍然是部署最快、依赖最少、任何机器上都能跑的工具。你不需要装 Python、不需要申请权限一个 .bat 文件加一个 txt 列表就能解决一大类实际问题。我也曾经纠结要不要直接上 PowerShell但后来想明白一点——工具的选择要看使用现场给值班同事用双击就能跑、日志不乱码的 bat比高配但需要维护的 PS 脚本可靠得多。如果你也经常被“到哪个系统卡”“链路到底通没通”这类问题困扰建议现在就复制脚本建个 targets.txt 跑一轮把基线数据留一份下次再有人问甩日志比解释半天管用。
返回列表