Powershell 等待服务停止或启动
Powershell Wait for service to be stopped or started
我已经搜索过这个论坛和google,但找不到我需要的东西。
我有一个相当大的脚本,我正在寻找一些代码来检查服务是否启动或停止,然后再继续下一步。
它自己需要循环的函数,直到它停止或启动(将有一个用于停止的函数和一个用于启动的函数)。
一共有4个服务几乎同名,所以Service Bus *可以作为通配符。
以下将循环并验证给定服务的状态,直到具有 "Running" 状态的服务数量等于零(因此它们已停止),因此您可以在等待时使用它用于停止服务。
我已经添加了一个 $MaxRepeat
变量,这将永远阻止 运行ning。它将 运行 最大定义为 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)
我无法使用 Micky 发布的 'count' 策略,所以我是这样解决的:
我创建了一个函数,它接受一个 searchString(这可能是 "Service Bus *")和我期望服务应该达到的状态。
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."
除了 this one liner might be useful if you just want to wait for a single service (also inspired by a post from Shay Levy):
(Get-Service SomeInterestingService).WaitForStatus('Running')
我不得不用多个计数器对此进行一些调整,因为该服务有意缓慢启动和停止。原始脚本让我走上了正确的轨道。我必须等待服务处于完全停止状态才能继续,因为我实际上是在重新启动相同的服务。
您或许可以删除 "sleep,",但我不介意将其保留。
您可能会删除所有内容并只使用 $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)
在我的 Azure build/deployment 管道中,我像这样使用它来启动和停止服务(在之前已经异步发送 'Stop' 命令之后)并且它适用于所有过渡状态,例如 Starting
、Stopping
、Pausing
和 Resuming
(在状态中称为 StartPending
、StopPending
、PausePending
和 ContinuePending
枚举 ServiceControllerStatus
).
# 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 秒)。
为我对@Christoph 的回复添加更多详细信息
这是我最近创建的一个脚本,用于停止服务并确保进程也停止。在我们的案例中,过程是可预测的。如果您有多个服务 运行 来自同一个可执行文件,则可能需要做更多的工作才能获得 service/processid 映射。
$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
}
我已经搜索过这个论坛和google,但找不到我需要的东西。 我有一个相当大的脚本,我正在寻找一些代码来检查服务是否启动或停止,然后再继续下一步。
它自己需要循环的函数,直到它停止或启动(将有一个用于停止的函数和一个用于启动的函数)。
一共有4个服务几乎同名,所以Service Bus *可以作为通配符。
以下将循环并验证给定服务的状态,直到具有 "Running" 状态的服务数量等于零(因此它们已停止),因此您可以在等待时使用它用于停止服务。
我已经添加了一个 $MaxRepeat
变量,这将永远阻止 运行ning。它将 运行 最大定义为 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)
我无法使用 Micky 发布的 'count' 策略,所以我是这样解决的:
我创建了一个函数,它接受一个 searchString(这可能是 "Service Bus *")和我期望服务应该达到的状态。
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."
除了
(Get-Service SomeInterestingService).WaitForStatus('Running')
我不得不用多个计数器对此进行一些调整,因为该服务有意缓慢启动和停止。原始脚本让我走上了正确的轨道。我必须等待服务处于完全停止状态才能继续,因为我实际上是在重新启动相同的服务。 您或许可以删除 "sleep,",但我不介意将其保留。 您可能会删除所有内容并只使用 $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)
在我的 Azure build/deployment 管道中,我像这样使用它来启动和停止服务(在之前已经异步发送 'Stop' 命令之后)并且它适用于所有过渡状态,例如 Starting
、Stopping
、Pausing
和 Resuming
(在状态中称为 StartPending
、StopPending
、PausePending
和 ContinuePending
枚举 ServiceControllerStatus
).
# 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 秒)。
为我对@Christoph 的回复添加更多详细信息
这是我最近创建的一个脚本,用于停止服务并确保进程也停止。在我们的案例中,过程是可预测的。如果您有多个服务 运行 来自同一个可执行文件,则可能需要做更多的工作才能获得 service/processid 映射。
$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
}