Powershell script to check if service is started, if not then start it

I have built a small powershell script to check if a service is started. If it is not started, try to start it then wait one minute and check again. Keep repeating this process until the service start successfully. I have found the loop does not behave the way I expected in that I seem to have to re-assign the service variable within the loop in order to get the updated status. Here is my code:

$ServiceName = 'Serenade' $arrService = Get-Service -Name $ServiceName if ($arrService.Status -ne 'Running') < $ServiceStarted = $false>Else while ($ServiceStarted -ne $true) < Start-Service $ServiceName write-host $arrService.status write-host 'Service started' Start-Sleep -seconds 60 $arrService = Get-Service -Name $ServiceName #Why is this line needed? if ($arrService.Status -eq 'Running')< $ServiceStarted = $true>> 

enter image description here

If I run the code without the third last line (the one with the comment), I get the following output. I can check in the Windows service manager and the service was clearly started after the first loop. Why is that third last line required? Given this behavior, is there a better way to write this code? Thank you

asked Jan 28, 2016 at 15:05 6,721 3 3 gold badges 25 25 silver badges 43 43 bronze badges

Its because the variable status of the service is stored, for you to have it work it needs to get the status of the service again.

Commented Jan 28, 2016 at 15:18 Aren't I checking the status on the second last line? The one with if($arrService.Status. ? Commented Jan 28, 2016 at 15:21

You are but you are checking it from a variable that is already set, that variable is not called again without that line to update that variable.

Commented Jan 28, 2016 at 15:23

Sorry to be thick, but I'm a ps newbie. I'm intending to look up the service's status, and if it is 'Running', change the $ServiceStarted variable to true. Once that is done, the initial loop condition will be re-evaluated and that $ServiceStarted variable will be checked again, so wouldn't it find the updated value of true?

Commented Jan 28, 2016 at 15:28

What is it your trying to accomplish? check that the service is running and then start if its not running. Stop re-evaluating until it's started?

Commented Jan 28, 2016 at 15:40

11 Answers 11

I think you may have over-complicated your code: If you are just checking to see if a service is running and, if not, run it and then stop re-evaluating, the following should suffice:

$ServiceName = 'Serenade' $arrService = Get-Service -Name $ServiceName while ($arrService.Status -ne 'Running') < Start-Service $ServiceName write-host $arrService.status write-host 'Service starting' Start-Sleep -seconds 60 $arrService.Refresh() if ($arrService.Status -eq 'Running') < Write-Host 'Service is now Running' >> 
426k 68 68 gold badges 686 686 silver badges 882 882 bronze badges answered Jan 28, 2016 at 15:43 Nick Eagle Nick Eagle 1,178 8 8 silver badges 8 8 bronze badges in my PC "service" class members have this values State : Running Status : OK Commented Jun 19, 2018 at 14:52

Made a gist with a slightly altered version, making it easier to setup multiple services that should be started: gist.github.com/JohnyWS/6d0df355bfa63b05e5405c1c3939c69b

Commented Jan 3, 2019 at 15:10

are we 100% sure this works - how does arrService get updated ? The comment below alludes to the idea that its a static property as well.

Commented Jun 30, 2021 at 18:18 @jayunit100 that's what the .Refresh() is for Commented Sep 26, 2022 at 13:01

A potentially simpler solution:

get-service "servicename*" | Where | start-service 
7,399 6 6 gold badges 37 37 silver badges 47 47 bronze badges answered May 12, 2020 at 17:59 91 2 2 silver badges 4 4 bronze badges

The question was if service is not running. Checking for "Stopped" instead of "Running" is not correct. There are more statuses than these two.

Commented May 5, 2022 at 13:01

Given $arrService = Get-Service -Name $ServiceName , $arrService.Status is a static property, corresponding to the value at the time of the call. Use $arrService.Refresh() when needed to renew the properties to current values.

MSDN ~ ServiceController.Refresh()

Refreshes property values by resetting the properties to their current values.

1 1 1 silver badge answered Jan 28, 2016 at 15:42 1,620 1 1 gold badge 16 16 silver badges 30 30 bronze badges Thanks, that is exactly what I didn't understand. Commented Jan 28, 2016 at 15:47

Combining Alaa Akoum and Nick Eagle's solutions allowed me to loop through a series of windows services and stop them if they're running.

# stop the following Windows services in the specified order: [Array] $Services = 'Service1','Service2','Service3','Service4','Service5'; # loop through each service, if its running, stop it foreach($ServiceName in $Services) < $arrService = Get-Service -Name $ServiceName write-host $ServiceName while ($arrService.Status -eq 'Running') < Stop-Service $ServiceName write-host $arrService.status write-host 'Service stopping' Start-Sleep -seconds 60 $arrService.Refresh() if ($arrService.Status -eq 'Stopped') < Write-Host 'Service is now Stopped' >> > 

The same can be done to start a series of service if they are not running:

# start the following Windows services in the specified order: [Array] $Services = 'Service1','Service2','Service3','Service4','Service5'; # loop through each service, if its not running, start it foreach($ServiceName in $Services) < $arrService = Get-Service -Name $ServiceName write-host $ServiceName while ($arrService.Status -ne 'Running') < Start-Service $ServiceName write-host $arrService.status write-host 'Service starting' Start-Sleep -seconds 60 $arrService.Refresh() if ($arrService.Status -eq 'Running') < Write-Host 'Service is now Running' >> > 
answered Dec 12, 2019 at 13:58 1,089 1 1 gold badge 14 14 silver badges 24 24 bronze badges

The below is a compact script that will check if "running" and attempt start service until the service returns as running.

$Service = 'ServiceName' If ((Get-Service $Service).Status -ne 'Running') < do < Start-Service $Service -ErrorAction SilentlyContinue Start-Sleep 10 >until ((Get-Service $Service).Status -eq 'Running') > Return "$($Service) has STARTED" 
answered Aug 19, 2020 at 1:25 GuyWhoLikesPowershell GuyWhoLikesPowershell 29 1 1 bronze badge
$ServiceName = 'Serenade' $arrService = Get-Service -Name $ServiceName while ($arrService.Status -ne 'Running') < Start-Service $ServiceName write-host $arrService.status write-host 'Service starting' Start-Sleep -seconds 60 $arrService.Refresh() if ($arrService.Status -eq 'Running') < Write-Host 'Service is now Running' >> 

Can we use the same script for multiple services and send a single email if services are down.

1,008 1 1 gold badge 12 12 silver badges 20 20 bronze badges answered Apr 25, 2021 at 9:32 Dipak Lanjewar Dipak Lanjewar 21 2 2 bronze badges
[Array] $servers = "Server1","server2"; $service='YOUR SERVICE' foreach($server in $servers)
answered Apr 6, 2017 at 12:09 Alaa Akoum Alaa Akoum 11 1 1 bronze badge

While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value.

Commented Apr 6, 2017 at 12:17 how could one allow multiple services to be checked? Commented Jun 4, 2018 at 22:18 nest a second for loop and have a second array of services Commented Mar 2, 2019 at 14:58

Trying to do things as smooth as possible - I here suggest modifying GuyWhoLikesPowershell's suggestion slightly.

I replaced the if and until with one while - and I check for "Stopped", since I don't want to start if status is "starting" or " Stopping".

$Service = 'ServiceName' while ((Get-Service $Service).Status -eq 'Stopped') < Start-Service $Service -ErrorAction SilentlyContinue Start-Sleep 10 >Return "$($Service) has STARTED" 
answered Aug 28, 2020 at 15:04 11 2 2 bronze badges

Context

We have a product that has many variations and we work on them at once. Each variations has its own service. When multiple people work on the same version and one person manages to crash the service then someone needs to connect on the machine remotely and fix it.

Solution

So I made something that could manage multiple instances. Luckily all of them have the same prefix and Get-Service can take a "wildcard".

$ServiceName = 'ASService_*'; # Your wildcard goes here. while ($true) < Get-Service $ServiceName | Where | Foreach-Object < Start-Service $_; # Logging it so that you know it was you. Get-Date; Write-Output "``$($_.Name)`` has stopped running."; >Start-Sleep -Seconds 1; > 

This can be further simplified if you don't care about logs.

$ServiceName = 'ASService_*'; # Your wildcard goes here. while ($true) < Get-Service $ServiceName | Where | Foreach-Object < Start-Service $_ >; Start-Sleep -Seconds 1; > 
answered Jan 24, 2023 at 15:53 720 8 8 silver badges 16 16 bronze badges

In the spirit of Enterprise FizzBuzz, I wrote a version with extensive logging and handling for errors and Pending service states. It's likely over-engineered for most use cases. Please note this version is specifically intended be invoked by a Windows Scheduled Task on an interval. It runs for a specified number of tries on each run before stopping.

 param ( # Specifies the service name [Parameter(Mandatory = $true)] [string]$serviceName, # Specifies the directory for the log file [Parameter(Mandatory = $false)] [string]$logPath = 'C:\Scripts\Logs', # Specifies the max number of service Start attempts per run [Parameter(Mandatory = $false)] [int]$maxTries = 3, # Specifies the number of seconds to wait before trying again after a failed start attempt or before rechecking a Pending status [Parameter(Mandatory = $false)] [int]$secondsBeforeRetry = 30 ) $service = Get-Service $serviceName $logName = $serviceName + 'AutoRestartLog.txt' $logFullPath = Join-Path -Path $logPath -ChildPath $logName if(!(Test-Path -Path $logFullPath)) < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) New-Item -Path $logPath -Name $logName -ItemType "file" -Value "## Log file for $serviceName auto-start script ##`n## Created [$timestamp] ##`n" -Force Start-Sleep -s 1 >if ($service.Status -eq 'Stopped') < $tries = 0 while (($tries -lt $maxTries) -and ($service.Status -ne 'Running')) < if ($tries -eq 0) < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStoppedMsg = "[$timestamp] $serviceName service status is $($service.Status), attempting to Start. Will try up to $maxTries times." Add-Content -Path $logFullPath -Value $logSvcStoppedMsg >try < Start-Service $ServiceName -ErrorAction Stop # Throws exception if command fails, for example if the service is Disabled $tries += 1 Start-Sleep -s 10 $service.Refresh() if ($service.Status -eq 'Running') < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStartSuccessMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)" Add-Content -Path $logFullPath -Value $logSvcStartSuccessMsg >> catch < $errorMsg = $_ $tries += 1 Start-Sleep -s 10 $service.Refresh() $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStartExceptionMsg = "[$timestamp] Attempt #$tries - $serviceName service status is $($service.Status) and failed to start with error:`n $errorMsg" Add-Content -Path $logFullPath -Value $logSvcStartExceptionMsg if ($tries -ne $maxTries) < Start-Sleep -s $secondsBeforeRetry >> $service.Refresh() if (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending')) < $maxStateChecks = 3 $stateChecks = 0 while (($stateChecks -lt $maxStateChecks) -and (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending'))) < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStillPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status is $($service.Status). This may indicate the service is hung in the Starting or Stopping state. Waiting another $secondsBeforeRetry seconds before checking again." Add-Content -Path $logFullPath -Value $logSvcStillPendingMsg $stateChecks += 1 if ($stateChecks -ne $maxStateChecks) < Start-Sleep -s $secondsBeforeRetry >$service.Refresh() if ($service.Status -eq 'Running') < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStartSuccessMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)" Add-Content -Path $logFullPath -Value $logSvcStartSuccessMsg >elseif ($service.Status -eq 'Stopped') < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStoppedAfterPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status). If any Start attempts remain the script will try again on the next loop." Add-Content -Path $logFullPath -Value $logSvcStoppedAfterPendingMsg >> $service.Refresh() if (($stateChecks -eq $maxStateChecks) -and (($service.Status -eq 'StartPending') -or ($service.Status -eq 'StopPending'))) < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStuckPendingMsg = "[$timestamp] Attempt #$tries - $serviceName service status appears stuck in a Pending (Starting or Stopping) state. Attempting to force kill process." Add-Content -Path $logFullPath -Value $logSvcStuckPendingMsg $servicePID = Get-CimInstance -Class Win32_Service -Filter "Name LIKE '$serviceName'" | Select-Object -ExpandProperty ProcessId $resultMsg = taskkill /pid $servicePID /f $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcTaskKillMsg = "[$timestamp] Attempt #$tries - taskkill result:`n $resultMsg" Add-Content -Path $logFullPath -Value $logSvcTaskKillMsg Start-Sleep -s 10 $service.Refresh() $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logSvcStatusMsg = "[$timestamp] Attempt #$tries - $serviceName service status is now $($service.Status)" Add-Content -Path $logFullPath -Value $logSvcStatusMsg >> if (($tries -eq $maxTries) -and ($service.Status -ne 'Running')) < $timestamp = (Get-Date -Format yyyy-MM-dd--HH-mm-ss) $logNoMoreAttemptsMsg = "[$timestamp] $serviceName service status is $($service.Status) after $maxTries Start attempts. This run of the script will not continue trying to Start the service." Add-Content -Path $logFullPath -Value $logNoMoreAttemptsMsg >> # Add line break at end of log file entry Add-Content -Path $logFullPath -Value "`n" > 

It outputs a log file that looks like this:

## Log file for Netman auto-start script ## ## Created [2022-07-11--22-55-38] ## [2022-07-11--23-25-53] Netman service status is Stopped, attempting to Start. Will try up to 3 times. [2022-07-11--23-26-03] Attempt #1 - Netman service status is Stopped and failed to start with error: Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'. [2022-07-11--23-26-43] Attempt #2 - Netman service status is Stopped and failed to start with error: Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'. [2022-07-11--23-27-23] Attempt #3 - Netman service status is Stopped and failed to start with error: Service 'Network Connections (Netman)' cannot be started due to the following error: Cannot start service Netman on computer '.'. [2022-07-11--23-27-53] Netman service status is Stopped after 3 Start attempts. This run of the script will not continue trying to Start the service. [2022-07-12--01-46-15] Netman service status is Stopped, attempting to Start. Will try up to 3 times. [2022-07-12--01-46-25] Attempt #1 - Netman service status is now Running