我们公司的员工经常让电脑 24/7 全天候运行,甚至周末也不例外。我们的公司政策是不使用时关闭电脑,但这并不总是会发生。因此,我们一直在做的是使用 PsInfo 运行一个简单的脚本来恢复电脑的正常运行时间。我们将 AD 中的计算机列表导出到文本文件中,然后使用批处理文件浏览该列表,提取正常运行时间信息,并将其保存到另一个文本文件中:
For /F "tokens=*" %%i in (ComputerList.txt) do psinfo uptime -nobanner \\%%i 1>>UptimeResults.txt
效果很好,但如果计算机不在线,默认超时时间似乎是 60 秒,这可能会导致脚本在数百台计算机上运行很长时间。PsExec 本身有一个超时开关,您可以使用,但 PsInfo 似乎没有考虑到这一点。有没有其他方法可以强制它在 10 秒后超时,或者使用其他程序来做同样的事情?可能直接使用 PsExec 和超时开关以及其他命令?顺便说一句,我们已经禁用了 fastboot,因此正常运行时间结果是准确的。
我们讨论过但希望有一个更简单的解决方案:使用 PsExec 并运行,systeminfo | find "Boot Time"
然后分析启动时间并进行一些计算以获得运行时间。获取 uptime.exe 的旧副本,将其部署到计算机,并将其输出与 PsExec 一起使用。然后切换到 powershell 命令,该命令将轮询 WMI 以获取上次启动时间并再次进行计算。所有这些似乎都过于复杂,除非其他人有更好的建议,否则宁愿采用简单但缓慢的解决方案。
答案1
我喜欢Greg 的建议获取上次启动时间。
但我相信下面的方法可以满足您的要求。我使用 WMIC 在新的 cmd.exe 会话中启动 PSINFO。FOR /F 用于捕获新 CMD 会话的 PID。然后我调用一个例程来监视该进程长达 10 秒。如果它不再运行,则立即返回。但 10 秒后,我会在返回之前终止该进程。
我使用虚拟 TIMEOUT 进程测试了启动和监控进程。但我无法使用 PSINFO 进行测试,因为我没有 PSINFO,也没有您的环境。
@echo off
setlocal
set "timeout=10"
set "log=UptimeResults.txt"
:: Start with an empty result file
copy /y nul %log% >nul
:: Loop through the list of computers
for /f "tokens=*" %%i in (ComputerList.txt) do (
%= For each computer, launch PSINFO via wmic and use FOR /F to capture the parent cmd.exe session PID =%
%= The cd argument is the location where the process should run (current directory) =%
for /f "tokens=2 delims=;= " %%P in (
'wmic process call create 'cmd /c "psinfo uptime -nobanner \\%%i 1>>%log%"'^, "%cd%" ^| find "ProcessId"'
) do call :monitor %%P 2>nul 1>nul
)
exit /b
:monitor PID
:: Monitor up to %timeout% seconds and return immediately if process no longer running
for /l %%N in (1 1 %timeout%) do (
timeout 1
tasklist /fi "pid eq %1" | find "cmd.exe" || exit /b
)
:: It has been longer than %timeout% seconds, so kill the process
taskkill /pid %1 /f /t
exit /b