【发布时间】:2015-01-28 07:33:55
【问题描述】:
我已经搜索了这个论坛和谷歌,但找不到我需要的东西。 我有一个相当大的脚本,我正在寻找一些代码来检查服务是否已启动或停止,然后再继续下一步。
它自己需要循环的函数,直到它停止或启动(将有一个用于停止的函数和一个用于启动的函数)。
一共有 4 个服务几乎同名,所以 Service Bus * 可以用作通配符。
【问题讨论】:
标签: powershell
我已经搜索了这个论坛和谷歌,但找不到我需要的东西。 我有一个相当大的脚本,我正在寻找一些代码来检查服务是否已启动或停止,然后再继续下一步。
它自己需要循环的函数,直到它停止或启动(将有一个用于停止的函数和一个用于启动的函数)。
一共有 4 个服务几乎同名,所以 Service Bus * 可以用作通配符。
【问题讨论】:
标签: powershell
除了answer of mgarde,如果您只想等待一项服务(也受到post from Shay Levy 的启发),这一班轮可能会很有用:
(Get-Service SomeInterestingService).WaitForStatus('Running')
【讨论】:
我无法让 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."
【讨论】:
以下将循环并验证给定服务的状态,直到“正在运行”状态的服务数量等于零(因此它们已停止),因此如果您正在等待服务停止,则可以使用它.
我添加了一个$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 根本就不够用。
我不得不用多个计数器稍微调整一下,因为该服务故意启动和停止缓慢。原来的剧本让我走上了正轨。我必须等待服务处于完全停止状态才能继续,因为我实际上正在重新启动相同的服务。 您可能可以删除“睡眠”,但我不介意将其留在里面。 您可能可以删除所有内容并仅使用 $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 构建/部署管道中,我像这样使用它来启动和停止服务(在之前已经异步发送了“停止”命令之后),它适用于所有过渡状态,如 Starting、Stopping、@ 987654324@和Resuming(在状态枚举ServiceControllerStatus中分别称为StartPending、StopPending、PausePending和ContinuePending)。
# 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 秒)。
【讨论】:
Scheduled Tasks 才会发生这种情况。你做了什么?官方2分5秒后拨打Taskkill.exe?
在我对@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
}
【讨论】: