[powershell] 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{$ServiceStarted = $true}

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}
}

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?

enter image description here

Given this behavior, is there a better way to write this code?

Thank you

This question is related to powershell

The answer is


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:

Good point on the refresh.

$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'
    }

}

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"

[Array] $servers = "Server1","server2";
$service='YOUR SERVICE'

foreach($server in $servers)

{
    $srvc = Get-WmiObject -query "SELECT * FROM win32_service  WHERE   name LIKE '$service' " -computername $server  ;
    $res=Write-Output $srvc | Format-Table -AutoSize $server, $fmtMode, $fmtState, $fmtStatus ;  
   $srvc.startservice() 
   $res
}

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'
        }
    }
}

A potentially simpler solution:

get-service "servicename*" | Where {$_.Status -eq 'Stopped'} | start-service

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.


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"