在 Windows Powershell 中,如何在继续之前等待事件为真?

In Windows Powershell, how can I wait for an event to be true before proceeding?

我正在编写一个 Windows 停止服务的 Powershell 脚本,然后我想在它最终停止时打印该服务的状态。我尝试了以下方法,但它只是挂起[=13​​=]

$service = Get-Service | Where-Object {$_.name -like "*MyService*"}
Stop-Service -Name $service.name
$wait=true
while ($wait) {
  if($service.Status -eq "Running") {
    Start-Sleep -Seconds 1
  }
  else {
    $wait=$false
  }
}

我知道我可能可以写一个 for{} 循环来代替计数 0-9,并在满足我的条件时中断,但是有更好的方法吗?

您需要re-check循环内的服务。

$service = Get-Service | Where-Object {$_.name -like "*MyService*"}
Stop-Service -Name $service.name
$wait=true
while ($wait) {
  if($service.Status -eq "Running") {
    Start-Sleep -Seconds 1
    # ADD THIS BELOW. Need to re-check service in loop.
    $service = Get-Service | Where-Object {$_.name -like "*MyService*"}
  }
  else {
    $wait=$false
  }
}

解决您眼前的问题:

但是,不需要显式地等待服务停止,因为Stop-Service同步的,即:

  • 等待 服务在返回之前完成停止,除非您明确传递 -NoWait
  • 如果在固定的 2 秒超时内没有发生这种情况:[2]
    • 如果服务上次报告停止待定,则会发出警告 - 可能会最终停止完成。
    • 否则,会出现non-terminating错误 - 这表明服务被卡住了。

因此,您可以简化代码如下:

# Report a script-terminating error if stopping doesn't finish
# within the timeout period.
Stop-Service -Name *MyService* -ErrorAction Stop -WarningAction Stop

如果要实现重试机制,还需要做更多的工作。


[1] 有一个例外,虽然该行为没有记录并且应该被视为一个实现细节:如果你 pipe a 预先存在的 ServiceController 实例到 Stop-Service / Start-Service,这些 cmdlet 会为您刷新实例;例如,执行 ($service = Get-Service Bits) | Stop-Service 后,$service.Status 当前(反映 Stopped)。

[2] 从 PowerShell Core 7.3.0-preview.2 开始 - 请参阅 the source code.