Table of Contents
Using Where-Object
Cmdlet with Multiple Conditions
In PowerShell, we have various comparison and logical operators that we can use with the Where-Object
cmdlet to apply multiple conditions. Let’s explore a few scenarios below.
1 2 3 4 5 6 |
Get-ChildItem | Where-Object { ($_.extension -eq ".txt") -and ($_.length -eq 42) } |
1 2 3 4 5 6 7 |
Directory: E:\Test Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 12/30/2022 10:51 AM 42 File1.txt |
The above command returned an item where the extension of the selected item is .txt
, and its length is equal to 42
. Now, how is this command working? It is essential to learn to move ahead in this article.
The Get-ChildItem
cmdlet retrieves the items and child items in one or multiple locations we specified (if not specified, it will use the current directory). On the other hand, the Where-Object
cmdlet chooses objects from the collection based on their property values that are passed to it.
For instance, we can use this cmdlet to choose files with a specific size or extension, just like we did in the above example code. The point is how we can construct the Where-Object
command.
There are two ways of constructing it that are given below. Note that we can only use any of these approaches if our PowerShell version is 3.0 or greater (to check the version of your PowerShell, open up a PowerShell console (or the ISE), type $PSVersionTable
and hit Enter. Now, look for the value of PSVersion
that is your PowerShell version).
Script Block
These are the virtual components in Windows PowerShell, used in multiple places within the scripting language. It is an anonymous function which can categorize code and runs it in different places. For example, we can use a script block to specify a comparison operator, property name, and property value.
1 2 3 |
{$_.StartType -EQ 'Automatic'} |
The Where-Object
will return all objects for which a script block statement is True
. So, for instance, the following command gets that item whose name is File1.txt
and length is 42
.
1 2 3 4 5 6 |
Get-ChildItem | Where-Object { ($_.name -eq "File1.txt") -and ($_.length -eq 42) } |
1 2 3 4 5 6 |
Directory: E:\Test Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 12/30/2022 10:51 AM 42 File1.txt |
In PowerShell, we can pipe the objects to the Where-Object
and use the FilterScript
parameter since it accepts a script block, so we can create single or multiple conditions to assess the property of every object is equal to a particular value or not. See the following example to understand.
1 2 3 |
Get-Service | Where-Object -FilterScript {$_.StartType -eq 'Automatic'} |
Note that we can also omit the -FilterScript
parameter name to write scripts faster and more cleanly, but this makes it hard to understand for Windows PowerShell beginners, specifically when we will have multiple conditions.
One important thing while using script block with multiple conditions is to wrap around your subexpression with ()
in a filtering syntax. Why? It is because by wrapping our comparisons in {}
, we are creating script blocks, so a PowerShell interpreter views it as Where-Object { <ScriptBlock> -and <ScriptBlock>}
.
Since the -and
operator performs its operator on Boolean values, PowerShell casts the <ScriptBlock>
to Boolean values. Remember, in PowerShell, everything excluding not empty
, null
, and zero
is True
. So, the following statement:
1 2 3 4 |
Where-Object { <scriptblock> -and <scriptblock>} </scriptblock></scriptblock> |
will look like as follows, which will always be True
:
1 2 3 |
Where-Object { $true -and $true} |
This is why we use parentheses ()
instead of {}
for sub-expression. See the following example:
1 2 3 4 5 6 |
Get-ChildItem | Where-Object { ($_.extension -eq ".txt") -and ($_.length -eq 42) } |
Comparison Statements
We can also use comparison statements with Where-Object
where we are getting processes using Get-Process
that has the priority class of Normal
. We can use both statements interchangeably.
1 2 3 4 |
Get-Process | Where-Object -Property PriorityClass -eq -Value "Normal" Get-Process | Where-Object -Property PriorityClass -eq "Normal" |
Remember that comparison statements are supported if you have PowerShell version 3.0 or greater.
Now, let’s compare a statement using script block and comparison statement.
1 2 3 4 |
Get-ChildItem | Where-Object extension -eq ".txt" Get-ChildItem | Where-Object {$_.extension -eq ".txt"} |
Remember that we use comparison statements when we have only one condition. Why is it so? When we use Where-Object
without a script block, the comparison operators behave like parameters, not operators.
So, we can not use multiple comparison parameters. This is why we can only use multiple comparisons in a script block. Let’s see another example of Where-Object
with multiple conditions where we find all the processes that use between 4%
& 8%
of the CPU.
1 2 3 |
Get-Process | Where-Object {($_.CPU -gt 4.0) -and ($_.CPU -lt 8)} |
1 2 3 4 5 6 7 8 |
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 336 17 40040 70796 4.56 6764 34 chrome 305 17 30180 59432 6.16 9968 34 chrome 310 17 37640 61072 4.13 12700 34 chrome 297 16 31032 61092 5.58 26616 34 chrome |