Filtering with Where-Object
Most PowerShell commands return more than you need. Where-Object keeps only the objects that pass your test — it's the funnel most working pipelines run through.
Documentation: Microsoft Learn — PowerShell reference
What Where-Object does
Where-Object sits in the middle of a pipeline and tests each object, one at a time. If the test is true, the object passes through. If not, it's dropped. Nothing is changed — filtering only decides what survives.
Five service objects go in. Each one is asked: "is your Status equal to 'Stopped'?" Two answer yes — Spooler and WinRM. Those two come out.
Genie tip: read the pipeline out loud — "get the services, where the status equals stopped." If you can say it, you can write it.
See the objects move
Inspect this authored example with fictional data in the bounded browser model. The numbered stages show how its objects change.
Get-Service | Where-Object Status -eq 'Stopped'- Stage 1Get-Service
Positional values or no named parameters - Stage 2Where-Object
-eq
The filter script block
For anything beyond a simple comparison, the test lives in a script block — the curly braces. Inside it, $_ means the object being tested right now:
The comparison operators you'll reach for daily:
- -eq / -ne — equal / not equal
- -gt / -lt / -ge / -le — greater / less than (and "or equal")
- -like — wildcard match ('Win*'), -match — regex match
You only need -eq today — the rest are here when you're ready for them.
Combine tests with -and and -or (the sample lab below runs -and chains; -or works the same way in real PowerShell). And check the property name first with Get-Service | Get-Member — by default (Strict Mode aside), a misspelled property never errors, it just silently matches nothing.
Version note: the short form (Where-Object Status -eq 'Stopped') needs PowerShell 3.0+. The script-block form works everywhere, including 5.1 and 7.x.
Try it: filter services
Safe to try — this lesson only reads, never changes, and nothing leaves your browser
Keep stopped services whose names start with "Win". Two conditions, one filter:
Sample output · fictional data, shaped like the real thing
| Status | Name | DisplayName |
|---|---|---|
| Stopped | WinRM | Windows Remote Management (WS-Management) |
Common mistakes
Using = instead of -eq. A single = assigns. On services it errors out loudly — Status is read-only on ServiceController, so Where-Object { $_.Status = 'Stopped' } fails instead of filtering. The silent version of this trap lives on objects with settable properties:
The lesson above builds a pretend object. This bounded demo models the same assignment on fictional user objects with writable properties. Toggle it and inspect the result:
| Name | Enabled |
|---|
Interactive simulation · fictional data
[pscustomobject]@{...} just builds a pretend object to demonstrate on — you'll build these properly in the Script stage.
That filter returns no objects: the ungrouped assignment changes each writable Enabled property to $true but outputs no value for Where-Object to test. The original objects are still changed, even though the pipeline result is empty. Parentheses change the behavior: Where-Object { ($_.Enabled = $true) } outputs the assigned Boolean and keeps every object. To compare without changing objects, use -eq (case-insensitive by default; -ceq when case matters). See Microsoft’s grouping assignment statements reference.
Filtering on a property that doesn't exist. Where-Object State -eq 'Running' on services returns nothing, with no error — the property is called Status, not State. When a filter returns nothing, suspect the property name first.
Genie tip: an empty result is a clue, not a failure. Run the command without the filter first, look at the actual property names, then add Where-Object back.
Your turn
On your own machine, list the running services whose names start with the letter "S". Write it before you peek.
Reveal the answer (unlocks after your first check)
Check it here first. Type your command and run it against sample data before trying your own machine:
Checked against fictional sample data — on your machine the service names will differ, but the shape of the answer is the same.
Prove it: write it alone
Blank editor. No starter, no hints. Write a command that returns only the stopped services from the five-service sample:
Practise this
Filter stopped services
Return the complete records for stopped services.
The sandbox is visible now. Sign in with Google only when you run or check a task; commands and temporary files are discarded when you leave.
Run a command to inspect its result.
Inspect starting data
Supported syntax
Virtual files
Recap
Where-Object tests each object in the pipeline and keeps only the ones whose test is true. = assigns (and lies silently on settable properties) — compare with -eq, case-insensitive by default. When a filter returns nothing, suspect the property name first.
When this lesson is done, you can write from a blank prompt: Get-Service | Where-Object Status -eq 'Stopped'
Next: Select-Object reference — choose the properties to keepThis lesson counts as done when you can write the filter from a blank prompt — solve it alone above to unlock the route.