close

Windows

Cloud

Microsoft 365

PowerShell

Active Directory

Security

Windows Server

Video

Microsoft Teams Day is back!

Home

PowerShell

Filtering with PowerShell Where-Object: Easy Examples

Michael Reinders

|
PowerShell

In this article, I’ll explain how to use the PowerShell Where-Object cmdlet to filter objects and data. I’ll provide a series of easy examples showing you how to filter files by name or date, how to filter processes by status or CPU usage, and more.

When using PowerShell, you will often receive an extremely large amount of data when querying your environment. For example, If you run the Get-AzureADUser cmdlet against an Azure Active Directory database with 100,000 users, you will get…well, 100,000 results. That may take some time to output to your console!

Normally you won’t need to get all that information. The Where-Object cmdlet is an extremely helpful tool that will allow you to filter your results to pinpoint exactly the information you’re looking for.

What is the PowerShell Where-Object command?

PowerShell Where-Object is by far the most often-used tool for filtering data. Mostly due to its power and, at the same time, simplicity. It selects objects from a collection based on their property values.

There are other cmdlets that allow you to filter data. The Select-Object cmdlet selects objects (!) or object properties. Select-String finds text in strings and files. They both are valuable and have their niche in your tool belt.

Here are some brief examples for you. Select-Object commands help in pinpointing specific pieces of information. This example returns objects that have the Name, ID, and working set (WS) properties of process objects.

Get-Process | Select-Object -Property ProcessName, Id, WS

This other example does a case-sensitive (not default) match of the text sent down the pipeline to the Select-String cmdlet.

'Hello', 'HELLO' | Select-String -Pattern 'HELLO' -CaseSensitive -SimpleMatch

‘Hello’, ‘HELLO’ | Select-String -Pattern ‘HELLO’ -CaseSensitive -SimpleMatch

How to filter an array of objects with PowerShell Where-Object

The task at hand is filtering a large pool of data into something more manageable. Thankfully, there are several methods we have to filter said data. Starting with PowerShell version 3.0, we can use script blocks and comparison operators, the latter being the more recent addition and the ‘preferred’ method.

With the Where-Object cmdlet, you’re constructing a condition that returns True or False. Depending on the result, it returns the pertinent output, or not.

Building filters with script blocks

Using script blocks in PowerShell goes back to the beginning. These components are used in countless places. Script blocks allow you to separate code via a filter and execute it in various places.

To use a script block as a filter, you use the FilterScript parameter. I’ll show you an example shortly. If the script block returns a value other than False (or null), it will be considered True. If not, False.

Let’s show this via an example: You have been assigned a task from your manager to determine all the services on a computer that are set to Disabled.

We will first gather all the services with Get-Service cmdlet. This pulls all the attributes of all the services on the computer in question. Using the PowerShell pipeline, we can then ‘pipe’ the gathered results using the FilterScript parameter. We can use this example below to find all the services set to Disabled.

($_.StartType -EQ 'Disabled')

First off, if we just use the Get-Service cmdlet, we get the full list of services. And there were quite a few more screens of services beyond the image below.

We used the Get-Service cmdlet to show all services running on Windows 11
There are a LOT of services on Windows 11…

Not exactly what we’re looking for. Once we have the script block, we pass it right on to the FilterScript parameter.

We can see this all come to fruition with this example. We are using the Get-Service cmdlet to gather all the disabled services on our computer.

Get-Service | Where-Object -FilterScript ($_.StartType -EQ 'Disabled')
We used the Get-Service cmdlet to gather all the disabled services on our computer.
That’s better. Our list of disabled services.

There we go. Now, we have the 15 services that are set to Disabled, satisfying our request.

Filtering objects with comparison operators

The issue with the prior method is it makes the code more difficult to understand. It’s not the easiest syntax for beginners to get ramped up with PowerShell. Because of this ‘learning curve’ issue, the engineers behind PowerShell produced comparison statements.

These have more of a flow with them. We can produce some more elegant, efficient, and ‘easier-to-read’ code using our prior example.

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

See? A little more elegant and easier to read. Using the Property parameter and the eq operator as a parameter allows us to also pass the value of Disabled to it. This eliminates our need to use the script block completely!

Containment operators

Containment operators are useful when working with collections. These allow you to define a condition. There are several examples of containment operators we can use. Here are a few:

  • -contains – Filter a collection containing a property value.
  • -notcontains – Filter a collection that does not contain a property value.
  • -in – Value is in a collection, returns property value if a match is found.
  • -notin – Value is not in a collection.

For case sensitivity, you can append ‘c’ at the beginning of the commands. For example, ‘-ccontains’ is the case-sensitive command for filtering a collection containing a property value.

Equality operators

There are a good number of equality operators. Here are a few:

  • -eq / -ceq – Value equal to specified value / case-sensitive option.
  • -ne – Value not equal to specified value.
  • -gt – Value greater than specified value.
  • -ge – Value greater than or equal to specified value.
  • -lt – Value less than specified value.
  • -le – value less than or equal to specified value.

Matching operators

We also have matching operators to use. These allow you to match strings inside of other strings, so that ‘Windows World Wide’ -like ‘World*’ returns a True output.

Here are some examples of matching operators:

  • -like – String matches a wildcard-type pattern
  • -notlike – String does NOT match a wildcard pattern
  • -match – String matches regex pattern
  • -notmatch – String does NOT match regex pattern

You use these just like when using containment operators.

Can you use multiple filter conditions with both methods?

Come to think of it, yes, you certainly can use both methods in your scripts. Even though comparison operators are more modern, there are times when working with more complex filtering requirements will dictate you to use script blocks. You’ll be able to find the balance yourself as you learn and become more proficient with your scripts.

Filtering with PowerShell Where-Object: Easy Examples

Let’s go through some simple examples of using the Where-Object cmdlet to determine pieces of information. Eventually, we’ll be able to accomplish tasks with ease.

Filtering files by name

We can certainly filter a directory of files that match specific criteria. We can use the Get-ChildItem cmdlet to first gather the list of files in my Downloads folder. Then, I use the Where-Object cmdlet with the ‘BaseName‘ parameter to find all files that have ‘Mail’ in the filenames.

We can use also wildcard characters here. Let’s give it a whirl:

Get-ChildItem -path 'c:\users\sovit\downloads' | Where-Object {$_.BaseName -match 'Mail*'}
Using the PowerShell Where-Object cmdlet to filter files in a folder matching a specific filename wildcard.
Filtering files in a folder matching a specific filename wildcard.

Piece of cake. So, imagine a scenario where you have a folder with 25,000 files in it, and all the filenames are just strings of alphanumeric characters. Being able to quickly find the file(s) with an exact character match is ideal and a HUGE timesaver!

Filtering files by date

We can use the same commands, Get-ChildItem and Where-Object, to find files based on dates, too. Let’s say we want to find all files that were created or updated in the last week. Let’s do this!

Get-ChildItem | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-7)}
Using the PowerShell Where-Object cmdlet to filter files in a directory by last saved time - wonderful tool!
Filtering files in a directory by last saved time – wonderful tool!

We are using the LastWriteTime property and the Get-Date and AddDays parameters to make this work. It works wonderfully.

Filtering processes by name

Because it is SO much fun working with Windows Services, let’s continue in this lovely realm. We are trying to determine the name of the ‘WWW’ service. We can use the ‘Property‘ parameter again.

Get-Service | Where-Object -Property Name -Contains 'W3SVC'
Using the PowerShell Where-Object cmdlet to locate the www publishing service
Locating the WWW Publishing Service

Filtering processes by status

There are several properties with each service, so we can also use a containment operator to gather a list of all services that are in a Running state.

Get-Service | Where-Object -Property Status -Contains 'Running'
Using the PowerShell Where-Object cmdlet to list all running services
Listing all Running Services

Filtering processes by name and status

Remember what I said about script blocks? Let’s use one here to accomplish to filter processes by name and status. We will get all the services that are running but also have a StartType parameter set to Manual. Here we go!

Get-Service | Where-Object {($_.Status -contains 'Running') -and ($_.StartType -in 'Manual')}
We used the Where-Object cmdlet with a script block to filter services by status and StartTypr
Filtering Services by Status and StartType

Pretty slick. And we’re just starting here…

Filtering processes by CPU usage

You can also use equality operators with Where-Object to compare values. Here, we’ll use an operator and the Get-Process command to filter all running processes on our computer based on CPU usage.

Let’s use a script block to find all processes that are using between 4 and 8 percent of the CPU.

get-process | Where-Object {($_.CPU -gt 4.0) -and ($_.CPU -lt 8)}
Displaying all Processed using between 4 and 8% CPU time
Displaying all Processed using between 4 and 8% CPU time

Here is an example that also helps us find all the local services that have ‘Windows’ in their DisplayName.

Get-Service | Where-Object {$_.DisplayName -match 'Windows'}
Showing all Services that have 'Windows' in their DisplayName parameter
Showing all Services that have ‘Windows’ in their DisplayName parameter

In addition, we can also use a wildcard character to find the Name of all services that start with ‘Win’.

Get-Service | Where-Object {($_.Name -like 'Win*')}
All the Services that have 'Win' starting their Name parameter
All the Services that have ‘Win’ starting their Name parameter

Finding PowerShell commands with a specific name

Our cmdlet also lets you use logical operators to link together multiple expressions. You can evaluate multiple conditions in one script block. Here are some examples.

  • -and – The script block evaluates True if the expressions are both logically evaluated as True
  • -or – The block evaluates to True when one of the expressions on either side are True
  • -xor – The script block evaluates to True when one of the expressions is True and the other is False.
  • -not or ‘!’ – Negates the script element following it.

Let me show you an example that illustrates this concept.

get-command | Where-Object {($_.Name -like '*import*') -and ($_.CommandType -eq 'cmdlet')}
Showing all the commands locally that have 'Import' in their name and are PowerShell cmdlets
Showing all the commands locally that have ‘Import’ in their name and are PowerShell cmdlets

Very useful!

Finding files of a specific type with a specific size

You’ve already seen a few examples of the ‘-filter‘ command above. This is the main example of using filter parameters in your commands and scripts. It lets you home in on the precise data you’re looking for. Let me show you an example.

Get-ChildItem -Path c:\users\sovit\Downloads -filter *.pdf | where-Object {*_.Length -ge 150000}
Viewing all PDF files 150K or larger!

This command filters out all the files in the folder for PDF files. It then pipes that to the Where-Object cmdlet, which will further narrow the list down to PDF files that are 150K or larger. Very useful!

Conclusion

The ‘Where-Object’ cmdlet is very powerful in helping you quickly pinpoint exactly the data points you are looking for. Being able to check all Services that are set to Automatic yet are not Running can be extremely helpful during troubleshooting episodes. And using it to find errant, high-CPU processes in a programmatic way can also help you with scripting these types of needs.

If you have any comments or questions, please let me know down below. Thank you for reading!

Most popular on petri

Article saved!

Access saved content from your profile page. View Saved