Learn What IT Pros Need to Know About Windows 11 - August 26th at 1 PM ET! Learn What IT Pros Need to Know About Windows 11 - August 26th at 1 PM ET!
PowerShell

Filtering PowerShell

tool-keyboard-hero-img

PowerShell is all about working with objects. (If you are fairly new to PowerShell objects, read Introduction to Objects in PowerShell on Petri.) The commands you run in PowerShell such as Get-Service or Get-ADUser are designed to connect to something and create an object that represents something you care about such as a service or user account. Most of the time we don’t care how these commands work, only what the output looks like and what we can do with it. Some commands can return hundreds if not thousands of objects and often you only really need small subset. To get the small subset, you need to perform some type of filtering. For many PowerShell users, that means using the Where-Object, which has an alias of where.

There is nothing wrong with using Where-Object as long as you understand the implications. Without going into the intricate details of the PowerShell pipeline, consider that Where-Object can’t really do anything until the preceding command finishes. This means that if the first command takes 30 seconds to complete and then you want to filter, you have to wait. Depending on the preceding command you may not have any choice. But when I train IT pros in PowerShell, I always stress the importance of filtering as early in your pipelined expression as you can. This is often referred to as filter left.

Filtering Parameters

The interesting thing about filtering is that it doesn’t require a –filter parameter like you see with Get-CimInstance or Get-WmiObject.  There are many cmdlets that provide other parameters you can use to limit or restrict output. For example, many cmdlets have a –Name parameter. Sometimes you can even use a wildcard. You might also look for parameters such as –Include or –Exclude. The syntax for these parameters varies depending on the cmdlet so you need to read full cmdlet help and look at the examples. Sometimes it takes old-fashioned trial and error experimentation. But it matters.

Sponsored Content

Read the Best Personal and Business Tech without Ads

Staying updated on what is happening in the technology sector is important to your career and your personal life but ads can make reading news, distracting. With Thurrott Premium, you can enjoy the best coverage in tech without the annoying ads.

In fact, let’s look at a PowerShell example that has nothing to do with our day job so we can focus on the concepts and not get distracted. Here’s a command called Get-Vegetable that writes vegetable type objects to the pipeline.

getting vegetable objects with PowerShell

The vegetable object has a boolean property you don’t see by default called IsRoot to indicate if the item is a root vegetable. Let’s say we wanted to filter out everything that wasn’t a root vegetable. You could run a command like this and it would work just fine.

filtering with Where-Object

This took 7 milliseconds to complete. Granted that isn’t much, but we’re only working with 16 vegetables. Imagine if it were 1600 or 16000 then the time spent starts adding up. In this example, being the pro-active IT pro that you are, you decide to see if there is a better way. Looking at help for Get-Vegetable you discover a few parameters.

looking for filtering parameters

Trying the parameter works and takes less than 2 milliseconds.

filtering with a parameter

However. depending on what you need to get, you may still need to use Where-Object. For example, let’s say we need to get all root vegetables that are still raw.

Get-Vegetable -RootOnly | where {$_.cookedstate -eq 'raw'}

This is preferable, and faster than an expression like this:
Get-Vegetable | where {$_.IsRoot -AND $_.cookedstate -eq 'raw'}

Both commands will give you the same result but the first one will be faster. You’ll hopefully also noticed that the filtering expression used the CookedState property. That’s because the actual property name is CookedState and not Status. Many commands have default formatting that use custom headings. You filter with any property you see with Get-Member.

Viewing properties with Get-Member

Finally, lets consider this with a more real-world example.

Using Get-CimInstance, let’s find all the services that have a start mode of Auto.

get-ciminstance -ClassName win32_service | where {$_.startmode -eq 'Auto'}

On my computer this takes about 200 milliseconds. But WMI has a filtering mechanism that we can use with Get-Ciminstance.
get-ciminstance -ClassName win32_service -filter "Startmode='Auto'"

This was slightly faster at 160 milliseconds. The major difference is that filtering is done at the source or at the point of collection. If you are querying a remote computer that means that the only results that come back across the wire are the filtered results. Contrast this with the first example that has to send all service objects back and then filtering occurs. Now imagine doing this for 50 servers and the performance implications begin to add up.

However, there are always exceptions. Let’s say I want to find all .ps1 files in my Scripts directory that are larger than 50KB. Beginners might be tempted to use an expression like this:

dir c:\scripts -Recurse | where {$_.Extension -eq '.ps1' -AND $_.Length -gt 50KB}

This will work but takes about 850 milliseconds. Based on what I’ve been discussing, you might expect this version to be faster.
dir c:\scripts\ -include *.ps1 -Recurse  | where {$_.Length -gt 50kb}

On my computer it is slower. This version takes 1050 milliseconds to complete. That’s why PowerShell has the Measure-Command cmdlet to test for yourself.
measure-command { dir c:\scripts\ -include *.ps1 -Recurse  | where {$_.Length -gt 50kb} }

Most of the time the differences with different filtering techniques might appear insignificant. But once you gain more experience and begin to manage more and more of your enterprise with PowerShell, you’ll come to appreciate the benefits of filtering early so you might as well get in the habit and do it now.

Here are a few other filtering topics related to this article: More PowerShell Filtering Options and Filtering PowerShell with the Where Method.

Related Topics:

BECOME A PETRI MEMBER:

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

Register
Comments (0)

Leave a Reply

Register for Advanced Microsoft 365 Day!

GET-IT: Advanced Microsoft 365 1-Day Virtual Conference - Live August 24th!

Join us on Tuesday, August 24th and hear from Microsoft MVPs and industry experts about how to take advantage of Microsoft 365 at a technical level and dive deep into the features and functionality that will make your environment more secure and compliant.

RSVP Now

Sponsored By