I'm writing a Windows Powershell script that stops a service, then I want to print the service's status when it's finally stopped. I've tried the following, but it just hangs
$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
}
}
I know I can probably write a for{}
loop instead that counts 0-9, and breaks when my condition is met, but is there a better way?
CodePudding user response:
You need to re-check your service within the loop.
$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
}
}
CodePudding user response:
tanstaafl's helpful answer addresses your immediate problem:
- The
.Status
property value of a[System.ServiceProcess.ServiceController]
instance (as returned byGet-Service
) is a static value that only reflects the status of the service at the time of theGet-Service
call.[1] - To update the value to reflect the then-current status, call the
.Refresh()
method.
However, there is no need to explicitly wait for a service to stop, because Stop-Service
is synchronous, i.e.:
- It waits for the service to finish stopping before returning, unless you explicitly pass
-NoWait
. - If that doesn't happen within a fixed, 2-second timeout:[2]
- A warning is issued if the service last reported that stopping is pending - potentially, stopping will eventually finish.
- Otherwise, a non-terminating error occurs - this suggests that the service is stuck.
Thus, you can simplify your code as follows:
# Report a script-terminating error if stopping doesn't finish
# within the timeout period.
Stop-Service -Name *MyService* -ErrorAction Stop -WarningAction Stop
More work is needed if you want to implement a retry mechanism.
[1] There is one exception, although the behavior is undocumented and should be considered an implementation detail: If you pipe a preexisting ServiceController
instance to Stop-Service
/ Start-Service
, these cmdlets refresh the instance for you; e.g., after executing ($service = Get-Service Bits) | Stop-Service
, $service.Status
is current (reflects Stopped
).
[2] As of PowerShell Core 7.3.0-preview.2 - see the source code.