Mastering PowerShell Where-Object: A Comprehensive Guide

Published:11 January 2021 - 7 min. read

Bill Kindle Image

Bill Kindle

Read more tutorials by Bill Kindle!

When you work with PowerShell property values in a collection of objects, sometimes you will need a way to filter out all the things you do not need. Knowing how to use the PowerShell Where-Object cmdlet is an important skill to have in your PowerShell toolbox.

Not a reader? Watch this related video tutorial!
Not seeing the video? Make sure your ad blocker is disabled.

The Where-Object cmdlet is a handy way to filter objects. In this tutorial, you will learn different ways to construct a Where-Object command, it’s available parameters, syntax, as well as how to use multiple conditions like a pro!

Prerequisites

There is only one prerequisite for this article. You should have some basic familiarity with PowerShell commands and syntax.

All examples in this article will be based on the current stable release of PowerShell (7.1.0 at the time of writing). But as long as you have Windows PowerShell 4.0 and higher, the commands will work the same.

Understanding How PowerShell Where-Object Works

The PowerShell Where-Object cmdlet’s only goal is to filter the output a command returns to only return the information you want to see.

In a nutshell, the Where-Object cmdlet is a filter; that’s it. It allows you to construct a condition that returns True or False. Depending on the result of that condition, the cmdlet then either returns the output or does not.

You can craft that condition in one of two ways; the “old” way with scriptblocks and the “new” way using parameters or comparison statements.

Creating Filter Conditions with Scriptblocks

Scriptblocks are a key component in PowerShell. Scriptblocks are used in hundreds of places throughout the language. A scriptblock is an anonymous function. It’s a way to compartmentalize code and execute it in various places. You can build a filter for Where-Object via a scriptblock.

To use a scriptblock as a filter, you’d use the FilterScript parameter. This parameter allows you to create and pass a scriptblock to the FilterScript parameter which is then executed.

If the scriptblock returns a value other than a boolean False or null variable, it’s considered True. If not, it’s considered False.

For example, let’s say you need to find all of the Windows services which currently have a startup type of Automatic. You’d first gather all of the current services with Get-Service . Get-Service then returns many different service objects with various properties.

Using the PowerShell pipeline, you could then pipe those objects to the Where-Object cmdlet and use the FilterScript parameter. Since the FilterScript parameter accepts a scriptblock, you could create a condition to check whether or not the StartType property of each object is equal to Automatic like below.

{$_.StartType -EQ 'Automatic'}

Once you have the filtering scriptblock, you’d then provide that scriptblock to the FilterScript parameter. Where-Object would then execute that scriptblock for every object coming over the pipeline and evaluate each StartType property. If the property equals Automatic, Where-Object would pass the object though. If not, the object would be dropped.

You can see a simple example of this methodology below.

Get-Service | Where-Object -FilterScript {$_.StartType -EQ 'Automatic'}
Script Block construct
Script Block construct

Many people use positional parameters with the Where-Object cmdlet and don’t include the FilterScript parameter name. Instead, they simply provide the scriptblock alone like Where-Object {$_.StartType -eq 'Automatic'}.

While this type of construct works for this particular scenario. The concept of a scriptblock with the curly braces or even the pipeline variable $_ makes the code less readable and more difficult for less experienced PowerShell users. This readability issue is what caused the PowerShell team to introduce parameters or comparison statements.

Comparison Statements

Introduced in Windows PowerShell 3.0, comparison statements have more of a natural flow to how they are constructed. Using the same scenario as the previous example, let’s use the comparison statement construct to find all of the Windows services with an Automatic startup type:

Get-Service | Where-Object -Property StartType -EQ 'Automatic'

Notice above that instead of using a scriptblock, the command specifies the object property as a parameter value to the Property parameter. The eq operator is now a parameter as well allowing you to pass the value of Automatic to it.

Using parameters in this manner now eliminates the need for a scriptblock entirely.

A scriptblock is a better choice when defining more complex filtering conditions. The Property parameter may not always be the best choice. If using a scriptblock, just remember to document your code using comments!

In the next section, you’ll learn about the available comparison operator types that can be used with Where-Object to filter all the things.

Filtering Basics

Using parameters, Where-Object filters collections of objects using common comparison operators. Let’s dive into some examples of how they work.

Containment Operators

Containment operators are useful when working with collections. Containment operators allow you to define a condition if a collection contains an item or not.

As an example, let’s say you want to filter for a particular property value in a collection. You could use containment operators.

In PowerShell, you’ll find a few different containment operators:

  • -contains / -ccontains – Filter a collection containing a property value.
  • -notcontains / -cnotcontains – Filter a collection that does not contain a property value.
  • -in / -cin – value is in a collection, returns property value if a match is found.
  • -notin / -cnotin – value is not in a collection, null/$false if there is no property value.

For case sensitivity, use containment operators that begin with -c[operator]

Let’s say you’d like to check the status of the BITS Windows service. You can do so using the contains parameter (operator) by passing the value of BITS to it like below.

Get-Service | Where-Object -Property Name -Contains 'BITS'

And below is what you would expect to see:

Where-Object equivalent to Get-Service -ServiceName 'BITS'
Where-Object equivalent to Get-Service -ServiceName ‘BITS’

Always remember to filter left! The previous example is the equivalent to running Get-Service -ServiceName 'BITS' .

Perhaps you’d like to get fancier and find all services with a Status that is not Running and a StartType that is in a single string (or could be an array) called Manual. Using a scriptblock below, the command is using the FilterScript parameter to pass a scriptblock that evaluates on both of those conditions.

Get-Service |
	Where-Object {($_.Status -notcontains 'Running') -and ($_.StartType -in 'Manual')}

When you run the above command, you will only see services that are stopped and have a StartType of Manual.

More advanced filtering of a collection of objects
More advanced filtering of a collection of objects

Filtering with containment operators works well with collections that contain many property values. Given the number of properties that Get-Service returns, filtering through all of these properties is made easier when you combine containment and logical operators.

Matching Operators

Similar to how you use contaimment operators with Where-Object, you can also use mathcing operators. Matching operators allow you to match strings inside of strings. For example, 'foofoo' -like '*foo*' returns True or 'foofoo' -match 'foo' returns True. Matching operators match strings in strings.

In PowerShell, you have a few different matching operators that you can use within Where-Object.

  • -like / -clike – string matches a wildcard pattern.
  • -notlike / -cnotlike – string does not match wildcard pattern.
  • -match / -cmatch – string matches regex pattern.
  • -notmatch / -cnotmatch – string does not match regex pattern

For case sensitivity, use matching operators that begin with -c[operator]

Almost identical in form to containment operators, you can use matching operators as shown below. The below example is finding all services which have Windows in the DisplayName property value.

Get-Service | Where-Object { $_.DisplayName -match 'Windows'}
The match operator uses regular expressions to match on certain values.
The match operator uses regular expressions to match on certain values.

You can also use the like operator to use common matching techniques like using a wildcard (*) to match any character or perhaps a ? to match a single character.

Get-Service | Where-Object {($_.Name -like 'Win*')}

The results are filtered now to just those service names with ‘Win‘ as the first three characters:

service names with 'Win'
service names with ‘Win

Using the wildcard means you don’t have to know the full name of the service. A few letters of the string are all that’s needed. These operators can also be combined with logical operators to enhance filtering even further.

Equality Operators

Similar to how to use containment and comparison operators, you can also use equality operators with Where-Object. Equality operators are useful when needing to compare numeric values.

For example, 1 -eq 1 would be True while 1 -gt 2 would be False. PowerShell has many different equality operators that you can use as Where-Object parameters or inside of condition scriptblocks.

  • -eq / -ceq – value equal to specified value.
  • -ne / -cne – value not equal to specified value.
  • -gt / -cgt – value greater than specified value.
  • -ge / -cge – value greater than or equal to specified value.
  • -lt / -clt – value less than specified value.
  • -le / -cle – value less than or equal to specified value.

For example, perhaps you’d like to find all running processes that are taking up between two and 10 percent of your CPU. Not a problem with the Get-Process and Where-Object PowerShell cmdlets.

Using a scriptblock, you can combine two conditions together using the and operator which will evaluate them both. If they both return True, Where-Object returns the process object passed over the pipeline. If at least one of the conditions returns False, Where-Object drops the object.

Get-Process | Where-Object {($_.CPU -gt 2.0) -and ($_.CPU -lt 10)}

Here’s what you would expect to see:

Filtering with greater than and less than
Filtering with greater than and less than

Filtering using Where-Object equality operators will help you in building system reports or for comparing values.

Next Steps

Now that you know more about how to use the PowerShell Where-Object cmdlet to filter all the things, what else can you do? Try some more complex filtering tasks using multiple conditions and operators on collections to filter out property values and formatting the output to your liking.

Hate ads? Want to support the writer? Get many of our tutorials packaged as an ATA Guidebook.

Explore ATA Guidebooks

Looks like you're offline!