为什么在 PowerShell 脚本中可能需要暂停或延迟
PowerShell 中的 Start-Sleep cmdlet 会暂停脚本的执行,并等待指定的时间。适当地、策略性地使用暂停,可以帮助确保功能运行顺畅并防止错误,尤其适用于依赖外部系统或事件的脚本。
以下是您可能需要使用 PowerShell 暂停命令的三个主要原因:
- 等待资源 等待资源 — 许多脚本会与外部资源交互,例如文件、网络共享、数据库和 API。脚本开始运行时,这些资源可能尚不可用,或者可能需要一定时间才能响应。例如,如果脚本触发了后台作业,您可能需要暂停脚本执行,给该作业完成的时间,然后再允许脚本继续运行。
- 限制脚本运行速度(节流) — 调用 API、发起网络请求或在远程服务器上执行命令的 PowerShell 脚本,可能会让相关系统不堪重负,从而导致连接中断以及其他错误。在脚本中加入适当的暂停,可以帮助您避免这些问题。在处理大型数据集或执行批量操作时,限制(节流)脚本的执行尤其重要。
- 同步流程 — 在许多自动化场景中,一个流程的成功可能取决于另一个流程的完成情况。例如,您的脚本可能需要等到另一个流程完成对该数据的处理后,才能访问数据;或者需要延迟后续操作,以便让另一个服务有机会完全启动。
PowerShell Start-Sleep Cmdlet 的语法
核心参数
PowerShell 等待命令 Start-Sleep 的语法取决于你希望如何指定暂停 PowerShell 脚本执行的时长。下面是两个基本选项:
- -Seconds — 使用此参数可让 PowerShell 暂停指定的秒数。该值可以是整数;如果你希望暂停例如 2.5 秒,也可以使用浮点数。语法如下:
Start-Sleep -Seconds <number>
- Milliseconds — 如果你希望在脚本中以毫秒指定 PowerShell 的延迟,请使用下面的语法。在这种情况下,值必须是整数。
Start-Sleep -Milliseconds <integer>
用于简写用法的别名
Windows PowerShell 的 sleep 命令支持针对这些参数的简写别名,可用来替代完整的参数名:
- -s 用于 -Seconds 参数
- -ms 用于 -Milliseconds 参数
例如,下面介绍如何执行“PowerShell wait 5 seconds”命令:
Start-Sleep -s 5
下面是如何暂停 500 毫秒:
Start-Sleep -ms 500
-Duration 参数(PowerShell 7.3 及更高版本)
除了指定秒数或毫秒数之外,你还可以使用 -Duration 参数来指定时间间隔。下面是基本语法:
Start-Sleep -Duration <TimeSpan>
你可以用两种主要方式创建时间间隔:
- 使用字符串格式(hh:mm:ss, dd.hh:mm:ss, 等)
- 使用 New-TimeSpan cmdlet
例如,假设你想为 PowerShell 设置 1 分钟 30 秒的休眠计时器。一个选项是使用 hh:mm:ss 这种格式:
Start-Sleep -Duration '00:01:30'
另一个选项是使用 New-TimeSpan cmdlet,如下所示:
$duration = New-TimeSpan -Minutes 1 -Seconds 30
Start-Sleep -Duration $duration
PowerShell 中 Start-Sleep Cmdlet 的示例
下面的示例演示如何使用每个参数暂停 PowerShell 脚本。
使用秒
该脚本会获取当前日期和时间,暂停 5 秒,然后获取新的日期和时间:
Get-Date; Start-Sleep -Seconds 5; Get-Date
使用小数秒
以下命令会暂停脚本执行 1.5 秒:
Start-Sleep -S 1.5
使用毫秒
以下命令会暂停脚本执行 500 毫秒:
Start-Sleep -Milliseconds 500
使用时间间隔
以下 PowerShell 暂停脚本使用 -Duration 参数将脚本暂停 2 分钟:
Write-Host "The script will pause for 2 minutes..."
Start-Sleep -Duration (New-TimeSpan -Minutes 2)
Write-Host "The pause is over, and the script continues."
Start-Sleep
在循环的每次迭代之间暂停
您可以在循环的每次迭代之间通过使用 Start-Sleep 来暂停。尤其在需要等待外部资源、模拟诸如 API 请求之类的行为,或限制脚本执行速度时,这会非常有用。
例如,下面的脚本会执行 while 循环 5 次,并在每次迭代结束后暂停 10 秒:
$counter = 1 # Initialize a counter
$maxIterations = 5 # Define the maximum number of iterations
while ($counter -le $maxIterations) {
Write-Host "Iteration $counter: Working on the task..."
# Add a 10-second pause between iterations
Start-Sleep -Seconds 10
$counter++ # Increment the counter
}
Write-Host "All iterations are complete."
为了更好地观察脚本的执行情况,我们在 PowerShell ISE 中运行了它:
睡眠到指定时间
有时需要让任务在一天中的特定时间执行。在这种情况下,您可以将 Start-Sleep 和 Get-Date 这两个 cmdlet 一起使用。
例如,下面的脚本如果是在下午 6 点之后就会立即执行;否则,它会等到下午 6 点再运行:
# Get the current date and time
$currentTime = Get-Date
# Define the target time for 6 PM
$targetTime = Get-Date -Hour 18 -Minute 0 -Second 0
# Check if the current time is already past 6 PM
if ($currentTime -ge $targetTime) {
Write-Host "It's already past 6 PM. No need to pause."
} else {
# Calculate the time difference until 6 PM
$timeToSleep = $targetTime - $currentTime
# Convert the time difference to total seconds
$secondsToSleep = [math]::Ceiling($timeToSleep.TotalSeconds)
Write-Host "The script will pause for $secondsToSleep seconds until 6 PM."
# Sleep until 6 PM
Start-Sleep -Seconds $secondsToSleep
}
Write-Host "It's now 6 PM or later. Continuing execution."
下面的输出是在上午 4:22 运行此脚本生成的:
交互式暂停技术(Read-Host)
有时需要暂停脚本,直到用户按下特定按键或提供某些输入,例如他们的密码或对问题的回答。在这些情况下,请使用 Read-Host cmdlet,而不是 Start-Sleep.
暂停,直到按下某个按键
下面介绍如何使用 Read-Host ,在按下 Enter 键之前暂停脚本:
Write-Host "The script is running. Press Enter to continue..."
Read-Host # Waits for the user to press Enter
Write-Host "You pressed Enter. Continuing the script..."
提示用户输入
在执行可能具有破坏性或不可逆的操作之前(例如删除文件或进行系统更改),先向用户确认是很常见的做法。
下面的脚本会提示用户回答 Yes 或 No ,并在输入响应之前暂停:
# Prompt user for confirmation
$userInput = Read-Host "Do you want to continue? (Yes/No)"
# Check the user's response
if ($userInput -eq "Yes" -or $userInput -eq "Y") {
Write-Host "You chose to continue. Proceeding with the script..."
# Insert the next steps of your script here
} elseif ($userInput -eq "No" -or $userInput -eq "N") {
Write-Host "You chose not to continue. Exiting the script."
# Optionally, you can exit the script or perform other actions
exit
} else {
Write-Host "Invalid input. Please enter 'Yes' or 'No'."
# You can loop back and ask again or exit
}
显示进度条和倒计时计时器Start-Sleep
为用户提供有关 PowerShell 脚本执行情况的可视化反馈会很有帮助,尤其是长时间运行的操作和循环。两个选项分别是进度条和倒计时计时器。
进度条
要在脚本执行耗时操作时显示进度条,请使用 Write-Progress cmdlet,并结合 Start-Sleep 。下面的脚本演示了在 20 秒的 PowerShell 延迟期间如何显示进度条:
# Total duration for the operation in seconds
$totalDuration = 20
# Loop to simulate a long-running process
for ($i = 1; $i -le $totalDuration; $i++) {
# Calculate the percent complete
$percentComplete = ($i / $totalDuration) * 100
# Display the progress bar
Write-Progress -Activity "Processing..." -Status "Please wait..." -PercentComplete $percentComplete
# Simulate work being done with Start-Sleep
Start-Sleep -Seconds 1 # Sleep for 1 second
}
# Final message after the loop
Write-Host "Process complete!"
如果在 PowerShell ISE 中执行该脚本,效果如下:
从命令行执行脚本会得到以下结果:
倒计时计时器
倒计时计时器会显示脚本完成之前还剩多少时间。下面的脚本演示如何创建倒计时计时器,并同时显示进度条:
# Total duration for the countdown in seconds
$totalDuration = 20
# Loop to simulate countdown with progress feedback
for ($i = $totalDuration; $i -ge 1; $i--) {
# Calculate the percent complete
$percentComplete = (($totalDuration - $i) / $totalDuration) * 100
# Display the progress bar and countdown
Write-Progress -Activity "Countdown Timer" -Status "Time remaining: $i second(s)" -PercentComplete $percentComplete
# Simulate a 1 second delay
Start-Sleep -Seconds 1
}
# Final message after the countdown
Write-Host "Countdown complete! Time's up."
如果在 PowerShell ISE 中执行脚本,我们会看到以下内容:
下面是一张显示从命令行执行结果的截图:
在 PowerShell 脚本中使用 Start-Sleep 的最佳实践
以下最佳实践可帮助你更有效地使用 PowerShell 延迟命令 Start-Sleep:
- 仅在必要时使用 Start-Sleep。常见示例包括等待服务或资源。此外,暂停还可以帮助避免进行 API 调用时触发速率限制或导致服务器过载。
- 不要使用过长的睡眠(等待)时间。 将长时间的 PowerShell 暂停拆分为更短的间隔,并使用 Write-Progress 让用户保持知情。
- 不要把 Start-Sleep 当作条件检查的替代方案。 例如,没必要暂停脚本来检查文件是否存在,或某个进程是否已经完成。
使用 Start-Sleep 时常见的陷阱与注意事项 Start-Sleep
下面是使用 Start-Sleep 时需要留意的一些常见问题:
- 中断暂停 — 使用 Start-Sleep 时,在暂停期间按 Ctrl + C 进行中断,可能会使资源处于不一致的状态。为管理此类中断并执行必要的清理任务,请使用诸如 try-catch 块或 $ErrorActionPreference 之类的错误处理。
- 暂停时长不精确 — 与 Start-Sleep 相关的计时可能会因系统开销而变化,从而导致轻微延迟。请避免在对时间要求极高的操作中依赖此 cmdlet,或考虑使用更短的间隔并结合重复检查。
- 无限循环 — 在无限循环中包含 Start-Sleep 命令可能会导致资源耗尽。为防止过度的 CPU 和内存使用,请为循环定义清晰的退出条件,使用合适的休眠间隔,并添加超时。
结论
在 PowerShell 脚本中有策略地添加暂停,是控制执行时机、避免资源过载并处理任务之间依赖关系的有效方法。Start-Sleep cmdlet 可帮助你避免诸如资源节流(throttling)、过多的 API 请求或不必要的脚本错误等问题。如果你需要在用户按下特定按键或提供某些输入之前暂停脚本,请使用 Read-Host cmdlet。
请务必将这些 cmdlet 与诸如并行处理、异步脚本编写和事件驱动自动化等技术结合起来进行实验,以找到针对特定任务的最佳方案。
全面掌握 PowerShell 活动情况
使用 Netwrix Auditor 在 PowerShell 中检测可疑活动并确保合规
常见问题
如何在 PowerShell 脚本中暂停 10 秒?
你可以使用 PowerShell cmdlet Start-Sleep 来暂停脚本指定的秒数或毫秒数。例如,此命令会将脚本执行暂停 10 秒:
Start-Sleep -Seconds 10
如何在恢复 PowerShell 脚本之前等待用户输入?
你可以使用 Write-Host cmdlet 提示用户输入,并使用 Read-Host cmdlet 在提供响应之前暂停脚本执行。此策略常用于收集用户的密码,或收集其确认以继续执行某项操作。
下面的示例展示了如何在用户按下 Enter 键之前暂停你的脚本:
Write-Host "The script is running. Press Enter to continue..."
Read-Host # Waits for the user to press Enter
Write-Host "You pressed Enter. Continuing the script..."
如何在 PowerShell 中设置超时(timeouts)?
对于简单的延迟,你可以使用 PowerShell cmdlet Start-Sleep 。但如果要进行真正的超时处理,尤其是针对长时间运行的任务、后台作业或远程命令,更好的选择包括 Wait-Job 和 System.Threading.Timer 。
请尝试这些方法,以适应你的特定使用场景!
分享到
了解更多
关于作者
Tyler Reese
产品管理副总裁,CISSP
凭借在软件安全行业超过二十年的经验,Tyler Reese 对当今企业面临的快速演变的身份与安全挑战非常熟悉。目前,他担任 Netwrix Identity and Access Management 组合的产品总监;他的职责包括评估市场趋势、确定 IAM 产品线的发展方向,并最终满足终端用户的需求。他的职业经历从为财富 500 强公司提供 IAM 咨询,到在一家大型直销面向消费者(direct-to-consumer)的公司担任企业架构师,涵盖范围十分广泛。 目前,他持有 CISSP 认证。