Filtering: Where-Object and Comparisons
Where-Object keeps only the objects that pass a test, such as every file over 1 MB or every song, and the test is written with comparisons read aloud as words, -eq "equals", -gt "greater than", -like "is like", with $_ standing for this item.
Apprentice · PowerShell · Operating System · Updated
After this lesson you can
- Keep only the objects you want with Where-Object, writing the test with $_ for this item
- Compare with -eq, -ne, -gt, -lt and -like, and say each one aloud
Key takeaways
Where-Objectlets through only the objects that pass a test, like a sieve.Where-Object Length -gt 1MBkeeps every file over 1 MB.- Comparisons are words after a dash:
-eqequals,-nenot equals,-gtgreater than,-ltless than, and-likeis like, with wildcards. $_(read "this item") is the object being tested. In braces you can write{ $_.Length -gt 1MB -and $_.Extension -eq '.mp4' }.- Text comparisons ignore capital letters.
>is not greater than: it means "into a file".
Your phone says "Storage almost full", or a cloud backup refuses a file because it's too big. The first question is always the same: which files are over some size? File Explorer can sort a folder by size, but it can't answer "every file over 1 MB, in every folder, and nothing else". People sift lists like this all day: a teacher picks out the late assignments, a shop owner the orders over $100, an IT tech the programs using the most memory.
This lesson uses the drive folder from The Pipeline: |. If you don't have it yet, run that lesson's practice-drive lines first, then Set-Location ~\terminal-practice\drive.
Keep what passes a test: Where-Object
A kitchen sieve lets the water through and keeps the pasta. Where-Object is a sieve for objects: it tests each one that arrives through the pipe and lets through only those that pass. You name a property, a comparison and a value:
Get-ChildItem -Recurse -File | Where-Object Length -gt 1MB | Select-Object Name, Length
Name Length
---- ------
game-setup.exe 2355200
phone-backup.zip 1945600
unfinished-download.tmp 1126400
rain-sounds.mp3 1331200
road-trip-mix.mp3 1740800
birthday-party.mp4 1536000
graduation.mp4 2867200
Read it aloud: "every file, where Length is greater than one megabyte." Seven of the eighteen files pass. A file's Length is counted in bytes, the smallest unit of a file's size; 1MB is PowerShell's way of writing 1,048,576 of them, so you never count zeros. 1KB and 1GB work the same way. The Select-Object at the end only keeps the table narrow.
The comparisons, read aloud
Each comparison is a word after a dash, short for what you'd say:
| Comparison | Read it | Example |
|---|---|---|
-eq |
equals | Where-Object Extension -eq '.mp3' |
-ne |
not equals | Where-Object Extension -ne '.tmp' |
-gt |
greater than | Where-Object Length -gt 1MB |
-lt |
less than | Where-Object Length -lt 100KB |
-like |
is like (with wildcards) | Where-Object Name -like '*birthday*' |
-ge ("greater than or equal") and -le ("less than or equal") are there too. -like takes the wildcards from Wildcards and Filters, so '*birthday*' means "birthday anywhere in the name":
Get-ChildItem -Recurse -File | Where-Object Name -like '*birthday*' | Select-Object Name, Length
Name Length
---- ------
birthday-cake.png 532480
birthday-party.mp4 1536000
Text comparisons ignore capital letters, so Where-Object Extension -eq '.MP3' finds the three songs too. To make capitals count, put a c in front: -ceq, -clike.
$_: this item
For a test with two parts, write it in braces. The braces hold a script block, a small piece of code that Where-Object runs once for each object. Inside it, $_ (read "this item", or "dollar underscore") is the object being tested right now:
Get-ChildItem -Recurse -File | Where-Object { $_.Length -gt 1MB -and $_.Extension -eq '.mp4' } | Select-Object Name, Length
Name Length
---- ------
birthday-party.mp4 1536000
graduation.mp4 2867200
Read it aloud: "where this item's Length is greater than one megabyte, and this item's Extension equals .mp4." -and needs both parts to be true; -or needs one of them. $_.Length is the dot from Properties and Methods. $PSItem is a longer name for $_, and where and ? are short names for Where-Object.
The one mistake everybody makes: writing > for "greater than". In PowerShell > means "into a file", as in Writing to Files: Set-Content, Add-Content and >. Where-Object { $_.Length > 1MB } lets nothing through, and leaves a new file in your folder named 1048576. Use -gt. (If you made that file, Remove-Item 1048576 takes it away.)
Running programs, and filtering early
The same sieve works on anything. Get-Process | Where-Object WorkingSet64 -gt 200MB lists every running program using more than 200 MB of memory (WorkingSet64 is how much memory a program is using right now). Try it: the list is your own computer's, so no two people see the same one.
When you only need files by name, Get-ChildItem -Filter, from Wildcards and Filters, is faster, because Windows does the sifting before PowerShell sees a file. Where-Object is for everything else: size, date, anything an object knows.
Windows PowerShell 5.1 runs all of this the same way. On a Mac or Linux, -eq still ignores capital letters, but file names themselves care about them.
Try it. List every file on the drive smaller than 100 KB. Then every photo: .jpg or .png, written with -or.
Check yourself
2 questions to try on the lesson page.
So what
Where-Object turns "find me the ones that…" into one line: name the fact, the comparison and the value, and only what passes gets through.