≡ Menu

Powershell: Find Services that failed to start after server reboot

Whenever a server reboot is performed, a big question comes into mind is, “All services started properly”? Let us discuss this topic a bit more in this post.

Normal approach to verify services status after server restart is looking for automatic status and their current state(start/stop). While this is good for Operating system related services, not up to the mark for any application based services. I have seen application services where the application startup is set to manual and the service is started via some scheduled task/startup task. Both in house developed applications and third party vendor applications come in this category. In some cases, I suggested the teams to use right state(automatic) to get their services started after the server reboot, but in other cases, it was a sort of dependency on the other components of the system that making developers to create such weird kind of start up procedures.

So, while checking for a more authentic way to verify a service start up status, I came across service exit codes. Each service will have exit code set when the service is attempted to start/stop. Examining these errors codes will cover all kinds of scenarios and more efficient way to check services startup status after the server reboot.

Each service will have a exit code and we can read by using WMI. Let us look at the below example.

Get-WMIObject -Class Win32_Service -Filter "Name='spooler'"
service-returncode-0

Here I am querying spooler service using WMI and the return code from this service is 0(zero). That means it started property.

Now let us look at another service which is in stopped state.

Get-WmiObject -Class Win32_Service -Filter "Name='Fax'"
service-returncode-1

The return code here is 1077. If you type net helpmsg 1077 in command prompt, you will know what is the meaning of this error.

1077-error

So, 1077 means, this service was never attempted to start so no scope of failures here.

Like this you can analyze the startup status of a service by looking at the exit codes. I wrapped my whole explanation into small powershell code for your usage. I haven’t completely tested this yet, but you know any false positives, do let me know and I will try to improve this.

Code : Get-ServicesFailedToStart.ps1

[cmdletbinding()]            
Param(            
[string[]]$ComputerName = $env:ComputerName            
)            

foreach($Computer in $ComputerName) {            
 if(Test-Connection -Computer $Computer -Count 1 -quiet) {            
  try {            
   $services = Get-WMIObject -Class Win32_Service -Filter "State='Stopped'" -ComputerName $Computer -EA stop            
   foreach($service in $services) {            
    if(!(($service.exitcode -eq 0) -or ($service.exitcode -eq 1077))) {            
     $Error = Invoke-Expression "net helpmsg $($service.Exitcode)"            
     $Service | select Name, Startmode, State, Exitcode,@{Label="Message";Expression={$Error[1]}}            
    }            
   }            
  } catch {            
   Write-Verbose "Failed to query service status. $_"            
  }            
 } else {            
  Write-Verbose "$Computer : OFFLINE"            
 }            
}

Output:

failed-tostart-services-output

You can download this script from Technet script gallery as well(http://gallery.technet.microsoft.com/Query-that-failed-to-start-01c610d4)

Hope this article helps and let me know if you have any feedback.

Comments on this entry are closed.

  • Chaitanya March 28, 2014, 2:48 pm

    Hi Sitaram,

    Nice and useful script. Good one.

    Chaitanya.

  • Balathimmareddy March 28, 2014, 3:37 pm

    [string[]]$ComputerName = $env:ComputerName
    In the above line you are declaring ComputerName variable as String Array and it is storing only one computer name.
    But how it is giving output for two computers. Where are you storing two computers.

    Can you please explain.

    Can you also please tell me why did you use [cmdletbinding()] what is the use of it.

    • Sitaram Pamarthi March 28, 2014, 5:15 pm

      Good question. Let me explain.

      How [string[]]$ComputerName = $env:ComputerName is working?

      If you notice I am declaring $ComputerName as array of string. When you assign a string variable directly to the array(not addition), it will overwrite the contents of the array with that single value but the data type(i.e array) remains same. Look at the below example for clarity.


      PS C:\Scripts> [array]$a = "Sitaram"
      PS C:\Scripts> $a.Count
      1
      PS C:\Scripts> $a
      Sitaram
      PS C:\Scripts> $a.GetType()

      IsPublic IsSerial Name BaseType
      -------- -------- ---- --------
      True True Object[] System.Array

      PS C:\Scripts> [array]$a = "pamarths"
      PS C:\Scripts> $a
      pamarths
      PS C:\Scripts>

      To answer your second question, when you define [cmdletbinding()] it becomes a advanced function/script so that you can use common parameters like -Verbose, -Debug and also allows you to parameter validation. Read more about by typing below commands in PS shell.

      get-help about_commonparameters

      Also read http://technet.microsoft.com/en-us/library/hh847743.aspx for list of parameter validations you can do.