Skip to content

Filtering PowerShell Output as Text

The PowerShell command-line shell is very powerful, and for people coming from *nix backgrounds (like me), it is the closest thing in Windows to the *nix command line. Today, I wanted to find if I had installed one service in my computer, and instead of going through all the required clicks in the UI, I decided to try and do this using PowerShell.

Fetching all the services is very simple, using the Get-Service cmdlet. Now I want to filter them for specific text (as I would have done in *nix with grep). A quick Google search returned the Select-String cmdlet as the best way to do this. So I naively wrote Get-Service | Select-String "Family" (using the Family Safety service for this example). No output… What am I doing wrong?

What happened here is that PowerShell is an Object-Oriented shell, which in lay-terms means that it doesn’t treat input and output as strings, but as Objects. In this specific case, the Get-Service cmdlet return an array of System.ServiceProcess.ServiceController objects, and when they are passed to Select-String they are transformed to their type, so what Select-String is filtering is a list of elements with the text System.ServiceProcess.ServiceController (no idea why this happens, because if I store the value of Get-Service into a variable and apply toString() to it, I get the name of the service and not it’s type).

So in order to transform the output of the cmdlet to a string, we have to invoke Out-String. I executed Get-Service | Out-String | Select-String "Family" and… wrong again! Got a list of all the services in my computer. The problem now is that Out-String not only transforms the output of the previous command to a string, but if the result is an array, it will also concatenate ALL the outputs into one big string. So Select-String is not lying, I’m just giving it wrong input. Again, a quick search returned that I needed to use Out-String -stream for the output to be sent to Select-String one by one.

To conclude, the working on-liner is:

Get-Service  | Out-String -stream | Select-String "Family"

Which gives me this nice output:

Stopped  WPCSvc             Family Safety

And as it turns out, I could also have done this using a parameter to Get-Service:

Get-Service -DisplayName "Family*"

Oh… the joys of automation… XKCD is always right

Published inProgramming


    • Do you really think I am not aware of Cygwin? :-). But I like knowing the tools that best work in my platform, and PowerShell is VERY powerful, and you can do incredible stuff. And learning new things is always good for the brain.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.