PowerShell Problem Solver: Use PowerShell to Test if Windows Services are Running

Most of the time with my PowerShell Problem Solver articles I am addressing a problem I’ve come across in forums or through social media channels. But today’s problem is one of my own. I usually keep my computer running for days at a time, but I decided to reboot to start the day fresh. I then tried to run a WMI query using Get-CimInstance but got an error that the computer couldn’t be contacted. After scratching my head for a moment, I decided to check the WinRM service.

The CIM cmdlets use the WSMan protocol to query WMI, which means that PowerShell remoting must be enabled. Once enabled, the assumption is that the WinRM service is running. Although the WinRM service is configured to start automatically, it turns out that my service was not. Starting the service with Start-Service solved the problem, but I thought this is a potentially larger issue: how can I determine services that should be running that are not?

If you are new to PowerShell, you might think to first use Get-Service. You might even be smart and display all the properties.

When we use Get-Service, you can see that there’s a problem, which you can see in the following screenshot.

Using the Get-Service cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the Get-Service cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)

More accurately, there;s something that you don’t see in the screenshot. There’s nothing that indicates the service’s start mode, e.g. automatic, manual or disabled. The first lesson for today is that if there’s a limitation in the underlying .NET Framework class, then there will be a limitation in the related cmdlets. Fortunately, there’s almost always an alternative.

In this situation, we can also use WMI to discover information about services. We’ll use the Win32_Service class. It’s as easy as this:

Using the Get-CIMinstance cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)
Using the Get-CIMinstance cmdlet in Windows PowerShell. (Image Credit: Jeff Hicks)

As you can see in the output, there are properties to indicate the start mode and also the current state. If you are new to PowerShell and WMI, then you might be tempted to create an expression like this:

Don’t do that. Although the command will work and you will get a list of stopped services that are set to automatically start, this is a bad habit to get into. This is an example of late filtering. With this type of filtering, the Where-Object part of the expression can’t really run until the first part finishes. Although it isn’t that big a deal with services, you might run other queries that could return thousands of objects and you can’t filter until that step completes.

Instead, the recommended option is to use a cmdlet’s filter parameter whenever possible. You might also see parameters like include or exclude, which also provide a type of filtering. When using a filtering parameter, objects are filtered as they are collected and often at the source. If you were querying for services across 100 machines, the WMI service on each remote server will send you a filtered collection of service objects. This is much more efficient than getting all servers from 100 servers and then filtering at your end.

To filter with WMI, you can use the query parameter. WMI filters look like SQL-type queries. The class name is like a table. WMI queries also use the legacy operators, not the PowerShell operators.

You need to quote any string comparisons as I have done. I’ve also changed my state query to find anything that isn’t running. Services technically have other states beyond “Stopped’ and “Running” so I want to make sure I don’t miss any other potential issues.

Or, you can use the –Filter parameter, which takes a string. The value is essentially the where portion of your WMI query. This command will produce the same results.

That’s all I really need to run. Some of the stopped services are OK, but others I might decide to manually start. But I don’t want to have to try and type all of that, so I’ll spend a few minutes and create a re-usable tool that I can include in my PowerShell profile to make it much easier to find services that should be running but are not.

Because WMI can query remote computers, I included a Computername parameter. You might also want to check a specific service so there is a parameter to narrow your filter even further. I wanted the option to include a wildcard with –Name so that you can use * in the name. But, WMI queries don’t recognize * as a wildcard, it uses the % symbol. This means, if there is an * in the name value, I need to replace it with a %.

The * is a regular expression character, so I need to escape it in the –Match expression. WMI also uses the LIKE operator when using a wildcard.

There is one drawback to this command. If WinRM isn’t running, then it will fail.

An error is returned because WinRM isn't running. (Image Credit: Jeff Hicks)
An error is returned because WinRM isn’t running. (Image Credit: Jeff Hicks)

I suppose I could add a test in my function to verify the service is running and start it if it isn’t. But then I might be overlooking some other problem. So I’ll manually start WinRM and try again.

Much better.

My function can query a collection of computer names, and you can pipe names to it as well. If for some reason you need to use Get-WMIObject, the syntax should be identical to Get-CimInstance. You’ll simply need to replace commands in the function.

Once you solve a problem, I encourage you to take the time to record your solution in a script or function, because you will most likely run into the problem again. Being able to refer back to a simple command makes your life much easier.

Related Topics:

  • PowerShell

    Don't have a login but want to join the conversation? Sign up for a Petri Account