如何为PowerShell中调用的PsExec命令设置超时以避免脚本阻塞
Solution: Add Timeout to PsExec Commands in PowerShell
Hey there, I totally get the frustration of your script getting stuck when users step away mid-install—let's fix that by adding a 2-minute timeout to each PsExec call. The trick here is to launch PsExec as a separate process using PowerShell's Start-Process, then monitor it with a timeout. If it exceeds the 2-minute window, we'll kill the process and keep the script moving.
Here's the revised script with full timeout handling:
$timeoutSeconds = 120 # 2 minutes converted to seconds foreach ($program in $programlist){ # Add timestamped logging for better tracking $logPrefix = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - " "$($logPrefix)Starting workflow for $program on $hostikname" | Out-File "$logpath\log.txt" -Append # 1. Copy program to remote machine with timeout $copyArgs = "\\$hostikname -u bla\bla -p $plainpwd cmd /c ""pushd $BucketPath & copy $program c:\programdata\""" $copyProcess = Start-Process -FilePath "psexec.exe" -ArgumentList $copyArgs -NoNewWindow -PassThru if (-not $copyProcess.WaitForExit($timeoutSeconds)) { $copyProcess.Kill() "$($logPrefix)Copy of $program timed out after $timeoutSeconds seconds; process terminated" | Out-File "$logpath\log.txt" -Append } else { "$($logPrefix)Successfully copied $program to $hostikname" | Out-File "$logpath\log.txt" -Append } # 2. Run interactive installer with timeout $installArgs = "\\$hostikname -i -u bla\bla -p $plainpwd -h cmd /c ""c:\programdata\$program""" $installProcess = Start-Process -FilePath "psexec.exe" -ArgumentList $installArgs -NoNewWindow -PassThru if (-not $installProcess.WaitForExit($timeoutSeconds)) { $installProcess.Kill() "$($logPrefix)Installation of $program timed out after $timeoutSeconds seconds; process terminated" | Out-File "$logpath\log.txt" -Append } else { "$($logPrefix)Installation of $program completed on $hostikname" | Out-File "$logpath\log.txt" -Append } # 3. Clean up remote file with timeout $cleanupArgs = "\\$hostikname -u bla\bla -p $plainpwd cmd /c ""del c:\programdata\$program""" $cleanupProcess = Start-Process -FilePath "psexec.exe" -ArgumentList $cleanupArgs -NoNewWindow -PassThru if (-not $cleanupProcess.WaitForExit($timeoutSeconds)) { $cleanupProcess.Kill() "$($logPrefix)Cleanup for $program timed out after $timeoutSeconds seconds" | Out-File "$logpath\log.txt" -Append } else { "$($logPrefix)Successfully cleaned up $program on $hostikname" | Out-File "$logpath\log.txt" -Append } }
Key Changes Breakdown:
Start-Process: Launches PsExec as an independent process instead of running it directly, which lets us monitor and control its execution. The-PassThruparameter gives us a process object to work with.WaitForExit($timeoutSeconds): This method waits for the process to finish, but stops waiting once the timeout is hit. It returns$trueif the process exited on its own,$falseif it timed out.- Process Termination: If the timeout triggers, we call
Kill()to shut down the PsExec process immediately, so the script can proceed to the next step without blocking. - Enhanced Logging: Added timestamps to every log entry, making it easy to track exactly when operations started, completed, or timed out.
Quick Notes:
- If
psexec.exeisn't in your system PATH, replace"psexec.exe"with the full path to the executable (e.g.,"C:\Tools\PsTools\psexec.exe"). - Remove the
-NoNewWindowparameter if you want PsExec to run in its own separate command window.
内容的提问来源于stack exchange,提问作者Shahar
相关产品推荐
相关产品推荐

