【问题标题】:Powershell Wait for service to be stopped or startedPowershell 等待服务停止或启动
【发布时间】:2015-01-28 07:33:55
【问题描述】:

我已经搜索了这个论坛和谷歌,但找不到我需要的东西。 我有一个相当大的脚本,我正在寻找一些代码来检查服务是否已启动或停止,然后再继续下一步。

它自己需要循环的函数,直到它停止或启动(将有一个用于停止的函数和一个用于启动的函数)。

一共有 4 个服务几乎同名,所以 Service Bus * 可以用作通配符。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    除了answer of mgarde,如果您只想等待一项服务(也受到post from Shay Levy 的启发),这一班轮可能会很有用:

    (Get-Service SomeInterestingService).WaitForStatus('Running')
    

    【讨论】:

    • 我从 Shay Levy 的帖子中了解到,您还可以选择为等待状态添加 TimeSpan:(Get-Service SomeInterestingService).WaitForStatus('Running', ,'00:00:10 ')
    【解决方案2】:

    我无法让 Micky 发布的“计数”策略起作用,所以我是这样解决的:

    我创建了一个函数,它接受一个 searchString(这可能是“服务总线 *”)和我期望服务应该达到的状态。

    function WaitUntilServices($searchString, $status)
    {
        # Get all services where DisplayName matches $searchString and loop through each of them.
        foreach($service in (Get-Service -DisplayName $searchString))
        {
            # Wait for the service to reach the $status or a maximum of 30 seconds
            $service.WaitForStatus($status, '00:00:30')
        }
    }
    

    现在可以使用

    调用该函数
    WaitUntilServices "Service Bus *" "Stopped"
    

    WaitUntilServices "Service Bus *" "Running"
    

    如果达到超时时间,则抛出一个不太优雅的异常:

    Exception calling "WaitForStatus" with "2" argument(s): "Time out has expired and the operation has not been completed."
    

    【讨论】:

    • 最好的答案,到目前为止,对于这种情况,更容易理解。
    【解决方案3】:

    以下将循环并验证给定服务的状态,直到“正在运行”状态的服务数量等于零(因此它们已停止),因此如果您正在等待服务停止,则可以使用它.

    我添加了一个$MaxRepeat 变量,这将阻止它永远运行。它将按照定义最多运行 20 次。

    $services = "Service Bus *"
    $maxRepeat = 20
    $status = "Running" # change to Stopped if you want to wait for services to start
    
    do 
    {
        $count = (Get-Service $services | ? {$_.status -eq $status}).count
        $maxRepeat--
        sleep -Milliseconds 600
    } until ($count -eq 0 -or $maxRepeat -eq 0)
    

    【讨论】:

    • 我没有手动停止或启动任何服务。脚本中的命令将停止和启动服务。我只想查看服务是否已启动或停止,以便脚本可以继续,该函数不应尝试启动或停止服务。
    • 这就是这个循环的作用。它只是检查给定服务的状态。我在答案中澄清了
    • 似乎有效。当运行一些与服务总线相关的命令时,它会在控制台窗口上的灰色字段中提供输出,如“停止农场”等。这些在脚本完成之前不会释放并阻止一些输出。有什么办法可以确保他们在完成后消失。否则,一切都会像魅力一样发挥作用。
    • 稍作修改,就可以完美满足需求。如果您想在继续执行脚本之前确保服务已停止或运行,WaitForStatus 根本就不够用。
    【解决方案4】:

    我不得不用多个计数器稍微调整一下,因为该服务故意启动和停止缓慢。原来的剧本让我走上了正轨。我必须等待服务处于完全停止状态才能继续,因为我实际上正在重新启动相同的服务。 您可能可以删除“睡眠”,但我不介意将其留在里面。 您可能可以删除所有内容并仅使用 $stopped 变量。 :)

        # change to Stopped if you want to wait for services to start
        $running = "Running" 
        $stopPending = "StopPending"
        $stopped = "Stopped"
        do 
        {
            $count1 = (Get-Service $service | ? {$_.status -eq $running}).count
            sleep -Milliseconds 600
            $count2 = (Get-Service $service | ? {$_.status -eq $stopPending}).count
            sleep -Milliseconds 600
            $count3 = (Get-Service $service | ? {$_.status -eq $stopped}).count
            sleep -Milliseconds 600
        } until ($count1 -eq 0 -and $count2 -eq 0 -and $count3 -eq 1)
    

    【讨论】:

      【解决方案5】:

      在我的 Azure 构建/部署管道中,我像这样使用它来启动和停止服务(在之前已经异步发送了“停止”命令之后),它适用于所有过渡状态,如 StartingStopping、@ 987654324@和Resuming(在状态枚举ServiceControllerStatus中分别称为StartPendingStopPendingPausePendingContinuePending)。

      # Wait for services to be stopped or stop them
      $ServicesToStop | ForEach-Object {
        $MyService = Get-Service -Name $_ -ComputerName $Server;
        while ($MyService.Status.ToString().EndsWith('Pending')) {
          Start-Sleep -Seconds 5;
          $MyService.Refresh();
        };
        $MyService | Stop-Service -WarningAction:SilentlyContinue;
        $MyService.Dispose();
      };
      

      这需要传统的powershell在远程服务器上运行,pwsh.exe的cmdlet不包含参数-ComputerName

      在我看来,不需要计数器,因为只有过渡状态会导致 cmdlet 失败,并且它们会在不久的将来更改为受支持的状态之一(Stop 命令最多需要 125 秒)。

      【讨论】:

      • 最后的说法不一定准确,如果服务“降级”,它可能会在“StopPending”中停留数小时甚至数天。不幸的是,我们在某些意外情况下在生产中看到了这种情况。
      • 太棒了!认为只有Scheduled Tasks 才会发生这种情况。你做了什么?官方2分5秒后拨打Taskkill.exe
      • 我们使用了停止进程,在我们的例子中,我们通常会停止所有服务,因此我们可以杀死任何在我们“拥有”的时间范围内没有停止的服务,否则你需要找到停止服务之前的服务/进程 ID 映射,具体取决于服务的距离,它们可能会断开链接,但进程不会停止。
      • 我已经用我最近创建的脚本发布了一个答案。我没有做完整的服务/流程映射,但是使用 get-ciminstance 而不是 get-service 可以做到这一点。
      【解决方案6】:

      在我对@Christoph 的回复中添加更多详细信息

      这是我最近创建的一个脚本,用于停止服务并确保进程也停止。在我们的案例中,过程是可预测的。如果您有多个服务在同一个可执行文件上运行,则可能需要做更多的工作来获取服务/进程 ID 映射。

      $MaxWait = 180 #seconds
      
      $ServiceNames = "MyServiceName*"
      $ProcName = 'MyServiceProcName' #for the services
          
      $sw = [System.Diagnostics.Stopwatch]::StartNew() # to keep track of 
      $WaitTS = (New-TimeSpan -Seconds $MaxServiceWait) #could also use a smaller interval if you want more progress updates
          
      $InitialServiceState = get-service $ServiceNames | select Name,Status,StartType
          
      
          
      write-Host "$ENV:COMPUTERNAME Stopping $ServiceNames"
          
      $sw.Restart()
      $Services = @()
      $Services += Get-Service $ServiceNames | where Status -EQ Running | Stop-Service -PassThru -NoWait #nowait requires powershell 5+
      $Services += Get-Service $ServiceNames | where Status -Like *Pending
      
      #make sure the processes are actually stopped!
      while (Get-Process | where Name -Match $ProcName)
      {
          #if there were services still running
          if ($Services) {
              Write-Host "$ENV:COMPUTERNAME ...waiting up to $MaxServiceWait sec for $($Services.Name)"
              #wait for the service to stop
              $Services.WaitForStatus("Stopped",$WaitTS)
               
          }
          #if we've hit our maximum wait time
          if ($sw.Elapsed.TotalSeconds -gt $MaxServiceWait) {
              Write-Host "$ENV:COMPUTERNAME Waited long enough, killing processes!"
              Get-Process | where name -Match $ProcName | Stop-Process -Force
          }
          Start-Sleep -Seconds 1
      
          #get current service state and try and stop any that may still be running
          #its possible that another process tried to start a service while we were waiting
          $Services = @()
          $Services += Get-Service $ServiceNames | where Status -EQ Running | Stop-Service -PassThru  -NoWait #nowait requires powershell 5+
          $Services += Get-Service $ServiceNames | where Status -Like *Pending
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-25
        • 1970-01-01
        • 1970-01-01
        • 2018-12-04
        • 2015-06-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多