PowerShell Problem Solver: What’s Installed?

In this article, I’ll show you how to identify services that have IIS installed. I’m using IIS for the sake of my demonstrations, but you could apply this article to any product or service. One of the first questions to ask is what is an authoritative indicator? There could be more than one, but once you know what to look for, then it’s a simple matter of finding the corresponding PowerShell commands to retrieve that information.

In the case of IIS, the first thing I would check is if the Web-Server feature is installed using Get-WindowsFeature.

Get-WindowsFeature -Name Web* -ComputerName chi-web02

I picked a server that I already knew had this feature installed.

Listing web features
Listing web features (Image Credit: Jeff Hicks)

You can simplify this type of query by only getting features that are installed. Remember, this looks like fancy text, but there are objects backing it and one of the properties is Installed, which has a Boolean, or True/False value.

Get-WindowsFeature -Name Web* -ComputerName chi-web02 | where installed

Listing only installed web features
Listing only installed web features (Image Credit: Jeff Hicks)

So let’s take this idea and scale it out to filter a text list of computers. The only computer names I want to see at the end are those that have the Web-Server feature installed.

get-content c:\work\servers.txt | where { Get-WindowsFeature -Name Web-Server -ComputerName $_ | Where Installed}

This gets a little tricky because I have a nested Where-Object statement. If the computer does not have the Web-Server feature installed, then there will be nothing in the pipeline. The only names that come through will be those that have the feature installed, which in my list is three servers.

Filtering a list of computers where Web-Server is installed
Filtering a list of computers where Web-Server is installed (Image Credit:Jeff Hicks)

If you can use a Windows feature to identify what is installed, then I think that is the smart way to go.

But let’s say this approach won’t work for what you need to test, or in keeping with my IIS example, it won’t work on all platforms such as client machines. Then I’d ask if there is a particular service you can check? In my current example, of course there is.
Using Get-Service to identify an installed feature
Using Get-Service to identify an installed feature (Image Credit: Jeff Hicks)

You could try a command like this:

get-content C:\work\servers.txt | where {Get-Service w3svc -ComputerName $_}

By using this command, you’ll also get a lot of errors because Get-Service throws an exception if it can’t find the service. The easy solution is to temporarily turn errors off because we really don’t care about those computers.

get-content C:\work\servers.txt | where {Get-Service w3svc -ComputerName $_ -ErrorAction SilentlyContinue}

Filter a text list with Get-Service
Filter a text list with Get-Service (Image Credit: Jeff Hicks)

Or perhaps you want to include the service status:

get-content C:\work\servers.txt |
foreach {Get-Service w3svc -ComputerName $_ -ErrorAction SilentlyContinue} |
Select Machinename,Name,Status

In this case, I want to get the actual service.

Getting service details
Getting service details (Image Credit: Jeff Hicks)

Using Get-Service requires a legacy connection to the server. You could achieve similar results with WMI using Get-WmiObject or Get-CimInstance.

get-ciminstance -class Win32_service -filter "name='w3svc'" -computername (get-content c:\work\servers.txt)

Filtering with Get-CimInstance
Filtering with Get-CimInstance (Image Credit: Jeff Hicks)

In this example, I’m processing all the computer names at once with a nested pipeline.
The last way to check might be looking for a particular process. If I were searching for DNS, I could use either of these approaches:

get-content c:\work\servers.txt | where { get-process DNS -ComputerName $_ -ErrorAction SilentlyContinue}
get-ciminstance -ClassName win32_process -filter "name='dns.exe'" -ComputerName (get-content c:\work\servers.txt)

Multiple ways to list process information
Multiple ways to list process information (Image Credit: Jeff Hicks)

Unfortunately, IIS doesn’t work that way. I know from looking at the web server that the IIS process has a start command like this:
Getting process start information
Getting process start information (Image Credit: Jeff Hicks)

It will take a little work, but I should still be able to filter processes on multiple computers looking for a similar line.

Get-CimInstance -ClassName win32_process -filter "Commandline like '%iissvcs'" -ComputerName (get-content c:\work\servers.txt) |
select ProcessID,Name,Commandline,PSComputername

And sure enough I get the same servers:

Finding the IIS process
Finding the IIS process (Image Credit: Jeff Hicks)

Need to identify what is running where? With a little research and planning it shouldn’t be that difficult with PowerShell. Hopefully at least one of these techniques will work for you. If not, please let me know in the article comments below.