如何使用PsExec同步在多台PC上运行EXE程序?
刚好之前帮团队解决过类似的多机精准同步启动程序的问题,PsExec本身的串行执行逻辑确实会因为网络延迟、目标机启动速度差异导致不同步,给你几个经过验证的方案,从简单到进阶都有:
核心思路是先让所有目标机的系统时间精确同步,然后让它们在同一个预设时间点启动程序,完全规避命令发送的延迟问题。
第一步:批量同步所有目标机的系统时间
在控制机上执行命令,强制每台目标机同步到时间服务器:@echo off setlocal enabledelayedexpansion for /f %%i in (machines.txt) do ( w32tm /resync /computer:%%i /force echo 已同步 %%i 的时间 )其中
machines.txt是你的目标机IP/主机名列表,每行一个。第二步:创建定时启动任务
先计算一个未来的时间点(比如当前时间加30秒,给所有机器足够的任务创建时间),然后在每台机器上创建一次性定时任务:@echo off :: 获取当前时间并计算30秒后的时间(格式HH:MM:SS) for /f "tokens=1-3 delims=:" %%a in ("%time%") do ( set /a "sec=%%c+30" set /a "min=%%b+sec/60" set /a "sec=sec%%60" set /a "hour=%%a+min/60" set /a "min=min%%60" set "starttime=!hour!:!min!:!sec!" ) :: 确保时间格式补零(比如9秒变成09) set starttime=%starttime: =0% :: 批量创建定时任务 for /f %%i in (machines.txt) do ( schtasks /create /s %%i /tn "TempSyncStart" /tr "C:\路径\你的程序.exe" /sc once /st %starttime% /f echo 已为 %%i 设置启动任务 )第三步:清理临时任务(可选)
程序启动后,可以批量删除这个临时任务避免残留:for /f %%i in (machines.txt) do ( schtasks /delete /s %%i /tn "TempSyncStart" /f echo 已清理 %%i 的临时任务 )
如果需要毫秒级的同步精度,可以用「先加载程序到内存挂起,再统一发送启动信号」的方式,完全消除启动延迟差异。
步骤1:编写一个简单的同步启动辅助程序
用C#写一个小工具,负责启动目标程序但先挂起,等待全局信号后再恢复运行:
using System; using System.Diagnostics; using System.Threading; namespace SyncStarter { class Program { static void Main(string[] args) { if (args.Length == 0) { Console.WriteLine("请传入目标程序路径"); return; } // 启动目标程序并立即挂起 ProcessStartInfo startInfo = new ProcessStartInfo(args[0]) { CreateNoWindow = false, // 根据你的程序需求调整 UseShellExecute = false }; Process targetProcess = Process.Start(startInfo); targetProcess.Suspend(); // 等待全局同步信号 using (EventWaitHandle syncEvent = new EventWaitHandle( false, EventResetMode.ManualReset, "Global\\MultiMachineSyncEvent")) { syncEvent.WaitOne(); } // 恢复目标程序运行 targetProcess.Resume(); } } }
编译成SyncStarter.exe,放到所有目标机的同一个路径下(比如C:\Tools\)。
步骤2:批量加载程序到内存
用PsExec在所有目标机上启动辅助程序,此时你的目标程序已经被加载但处于挂起状态:
psexec @machines.txt -c C:\Tools\SyncStarter.exe "C:\你的程序.exe"
步骤3:发送全局启动信号
用PsExec在所有机器上触发全局事件,所有挂起的程序会瞬间恢复运行:
psexec @machines.txt powershell -Command "New-EventWaitHandle -Name 'Global\\MultiMachineSyncEvent' -InitialState $true -ResetMode ManualReset"
如果只是想最小化PsExec串行执行的延迟,可以用PowerShell并行启动多个PsExec进程,让命令几乎同时发送到所有目标机:
# 读取目标机列表 $machineList = Get-Content "machines.txt" # 你的程序路径 $targetExe = "C:\路径\你的程序.exe" # 并行启动PsExec命令 foreach ($machine in $machineList) { Start-Process -FilePath "psexec.exe" -ArgumentList "\\$machine $targetExe" -NoNewWindow -PassThru }
这种方式比传统的串行批处理时间差小很多,但精度不如前两种方案,适合对同步要求不是特别极端的场景。
额外注意事项
- 确保所有目标机的防火墙允许PsExec的通信(默认用445端口),避免网络延迟过大。
- 测试时可以用一个显示当前时间戳的测试程序,来验证同步效果。
- 时间同步是所有方案的基础,建议把目标机配置为自动同步企业内部时间服务器。
内容的提问来源于stack exchange,提问作者Sebastián Pellegrino

