I have previously written a post about stopping and starting a service in Powershell. I have found an issue however, if the service fails to stop in time.
If you attempt to stop a service that is stuck (or waiting to finish a large task), then you may get the following error:
Windows could not stop the [Service name] service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
The same error occurs when attempting to stop a busy service using the Services window:
Detect if the script has stopped
To get around this, we should detect if the service has stopped successfully:
$serviceName = 'myService'
Stop-Service $serviceName
$arrService = Get-Service -Name $serviceName
while ($arrService.Status -ne 'Running')
{
# Attempt to restart service
}
Restart the service
When starting the service again, we should wait for a short period before checking if it started successfully. The service may be in a starting state for a while:
Start-Service $serviceName
Write-Host $serviceName $arrService.status
Write-Host $serviceName 'Starting'
# Wait a short period before checking the service
Start-Sleep -seconds 5
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host $serviceName $arrService.status
}
If the service hasn't started successfully, we should increase the wait time and try again:
Start-Service $serviceName
Write-Host $serviceName $arrService.status
Write-Host $serviceName 'Starting'
# Wait a short period before checking the service
Start-Sleep -seconds 5
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host $serviceName $arrService.status
}
else
{
Write-Host 'Failed to start the service'
# Wait a longer period before starting the service again
Start-Sleep -seconds 55
}
Wrapping it up into a function
Putting this into a function, and adding an attempt limit so we don't try indefinitely, we get:
Function RestartService
{
param
(
[Parameter(Mandatory=$true)][string]$serviceName, # A service name is required
[int]$initialWaitTime = '5', # Wait 5 seconds by default on the first attempt
[int]$recurringWaitTime = '60', # Wait 60 seconds by default on each subsequent attempt
[int]$maxAttempts = '10' # Make 10 attempts maximum
)
Write-Host $serviceName 'Stopping'
Stop-Service $serviceName
$arrService = Get-Service -Name $serviceName
$attempt = 1
while ($arrService.Status -ne 'Running' -and $attempt -le $maxAttempts)
{
Start-Service $serviceName
Write-Host $serviceName $arrService.status
Write-Host $serviceName 'Starting'
# Wait a short period before checking the service
Start-Sleep -seconds $initialWaitTime
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host $serviceName $arrService.status
}
else
{
Write-Host '(Attempt' $attempt') Failed to start' $serviceName '- Trying again in' $recurringWaitTime 'seconds.'
$initialWaitTime = $recurringWaitTime
$attempt++
}
}
}
This can then be called by passing the service name:
# With default parameters
RestartService 'MyService'
# With parameters set
RestartService 'MyService' -initialWaitTime 5 -recurringWaitTime 55 -maxAttempts 5
And hopefully, if it runs first time, you'll get something like this:
MyService Stopping
MyService Stopped
MyService Starting
MyService Running