Step 3. The Pipe (|) — A Way of Thinking That Assembles Commands
Level 0 — Understanding How to Operate a Computer and How It’s Structured | Difficulty ★★☆☆☆ | Estimated time: 2–3 hours
Prerequisites: Step 2 complete. We’ll work in Windows PowerShell.
- What you need: a Windows PC, PowerShell.
- Safety: every experiment today is "read-only." No command changes the system, so type away freely.
- Caution: two pieces of syntax today (
{}and$_) will feel unfamiliar. Don’t try to fully understand them yet — type them verbatim and build a feel first. We’ll explain why later.
Today is one of the most conceptually important days. Individual commands are just tools; the pipe is the way you "assemble" those tools. Most security investigations are problems like "show me only the processes that have been running suspiciously long" or "pull only the failed logins out of tens of thousands of log lines" — all of them assemblies of "list → filter → sort → trim." Once this assembly mindset becomes second nature, unfamiliar problems start falling apart along the same skeleton.
1. Learning Objectives
By the end of this chapter, you can:
- Pass a command’s output into the next command’s input with the pipe (
|) - Assemble the three machines
Sort-Object,Select-Object -First N, andWhere-Object - Design combined commands of the form "the top N things that are ○○" on your own
- Investigate the properties (tags) of an unfamiliar command with
Get-Member
2. Background Knowledge — Today’s Tools and Concepts
Today’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | PowerShell 5.1 — today’s star is the pipe (|) operator |
| Today’s commands | Sort-Object (sort), Select-Object -First N (trim), Where-Object (filter), Get-Member (inspect properties), Measure-Object (count) |
| Concepts you need | objects and properties, $_ and {} syntax, comparison operators like -eq/-gt |
Imagine a factory. Raw material travels along a conveyor belt, and each station’s machine takes the material, does its job, and passes it to the next machine.
raw material → [cut] → [polish] → [package] → finished product
PowerShell’s pipe (|) is exactly that conveyor belt. The left command’s output rides the belt and becomes the right command’s raw material.
2-1. The Secret of PowerShell’s Pipe — Objects Travel, Not Text
The Linux pipe (you’ll learn it in Step 19) passes text. That’s why it needs tricks like "cut out only the third word."
PowerShell is different. What rides the belt isn’t text but objects — "things with tags attached." For example, what Get-Process passes along is one process at a time, each carrying tags (properties) like these:
one process object
├── Name: "chrome"
├── CPU: 245.3
├── WorkingSet: 892345600
├── Id: 4520
└── ...
So the command on the right doesn’t "guess by tearing text apart" — it picks things out precisely, by tag name. Sort-Object CPU means "sort by the tag called CPU," and it’s accurate regardless of how things happen to look on screen. That’s what people mean by "PowerShell’s pipe is precise."
2-2. Meet Today’s Machines (Commands)
| Command | Role | Factory analogy |
|---|---|---|
Sort-Object property |
Sort by a given property | the lining-up machine |
Select-Object -First N |
Keep only the first N | the cutting machine |
Where-Object {condition} |
Pass through only what matches | the inspection machine |
Get-Member |
Show the list of tags (properties) | opening the blueprint |
2-3. $_ and {} — Operating the Inspection Machine
Only Where-Object has unusual syntax:
Where-Object {$_.CPU -gt 100}
How to read it:
{}(curly braces): "the inspection condition is inside here"$_: a pronoun pointing to "this one item passing by right now" on the belt$_.CPU: "the CPU tag of the item passing by"-gt: "greater than"
Read as a whole: "for each item passing by, let through only those whose CPU is greater than 100."
Comparison operators use words instead of math symbols:
| Symbol | Meaning |
|---|---|
-eq |
equals |
-ne |
not equal |
-gt |
greater than |
-lt |
less than |
At first this syntax looks like an alien language. That’s normal. For today, just memorize and use it as a block, and let understanding catch up through repetition — this is actually the shortcut to acquiring syntax.
3. Follow Along
3-1. Check the Material — Get-Process
Get-Process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
238 15 5120 18420 0.23 4520 1 ApplicationFrameHost
2156 89 185412 245800 45.12 8812 1 chrome
...
This is the list of programs (processes) running on this computer right now. Let’s look at the columns:
ProcessName— the program’s nameCPU(s)— total CPU time used so far (seconds)WS(K)— memory usageId— the process number (PID)
There’s a lot of it — it fills the screen. Let’s start processing this material.
3-2. First Pipe — Sorting
Get-Process | Sort-Object CPU -Descending
Same list, but this time ordered by highest CPU usage first. How to read it:
|— "pass the left result to the right"Sort-Object CPU— "sort by the tag called CPU"-Descending— "descending (biggest first)." Omit it for ascending (smallest first)
Pause and feel what just happened: "the items made by the machine on the left rode the belt and became raw material for the machine on the right." Sort-Object doesn’t need to know what Get-Process is — sorting whatever is on the belt is its job.
3-3. Extending the Belt — Just the First 10
It sorted, but printing everything is still long. Let’s attach one more machine to the belt:
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
614 26 31684 28228 11,861.81 24832 1 cloud-drive-daemon
1997 97 753512 309468 4,024.48 41684 1 ChatGPT
2453 64 521032 168260 3,970.92 35616 1 chrome
... (exactly 10 lines)
Select-Object -First 10— "pick only the first 10"
Now it’s readable. "The top 10 processes by CPU" — the same information you’d get by clicking the CPU column in Task Manager, obtained with a single command line. (The output above is an actual run — the #1 program on your screen may differ.)
Predict first: what would
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5show? WorkingSet went in where CPU used to be. Predict, then run it.
(Answer: the top 5 processes by memory usage. We only swapped a tag name, yet we answered a completely different question — that’s the power of assembly.)
3-4. The Inspection Machine — Where-Object
This time it’s not sorting but filtering.
Get-Process | Where-Object {$_.CPU -gt 100}
Only processes that have used more than 100 seconds of CPU remain. (If there are none, you may get nothing — that’s a normal result meaning "no matches." Lower the number to 50 or 10 and try again.)
This command grabs each process passing along the belt and asks: "Is your CPU over 100?" — pass if yes, discard if no.
Now let’s select by name:
Get-Process | Where-Object {$_.ProcessName -eq "powershell"}
Only processes named exactly powershell remain. (Since PowerShell is running right now, at least one should appear for it to be normal.)
3-5. Curious About the Tags? — Get-Member
The command for when you wonder "what other tags are there besides CPU?":
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
...
CPU Property double CPU {get;}
Id Property int Id {get;}
ProcessName Property string ProcessName {get;}
WorkingSet Property long WorkingSet {get;}
...
Everything marked Property is a candidate tag. Look at this list, think "ah, that property exists too," and get ideas for your next combination. When you wonder about an unfamiliar command’s properties, Get-Member — an investigation habit you’ll use hundreds of times.
3-6. The Same Idea Works on Files — Applied Combination
The pipe isn’t just for processes. Get-ChildItem (file listing) can ride the same belt:
Get-ChildItem $HOME | Sort-Object Length -Descending | Select-Object -First 5
How to read it: "get the list of files in my home → sort by size (Length), biggest first → keep 5." We answered the question "what are the 5 biggest files in my home?" with one command line. A real-world combination for disk cleanup.
The pattern so far:
(get a list) | (process: sort/filter) | (trim)
Just swap the material and the conditions onto this skeleton.
4. Missions & Exercises
Mission — Assembly Designer
Assemble commands yourself that answer the following questions. The answers are in Section 5, but build and run yours first, then compare.
- "Show me only processes using more than 500MB (=524288000) of memory (WorkingSet)"
- "Show me how many processes named powershell are running right now" (hint: attach
| Measure-Objectafter the filter to count them) - "Show me the 3 most recently modified files in C:\Windows\System32" (hint: the modification-time tag is
LastWriteTime) - "Show me processes sorted alphabetically by name, first 10 only" (hint: do you need -Descending this time?)
Exercises
Exercise 1. Explain one way PowerShell’s pipe differs from the Linux pipe.
Exercise 2. In Where-Object {$_.Length -gt 1000000}, what does $_ refer to?
Exercise 3. Assemble a command for "find only the zero-byte files in my home folder."
Exercise 4. You want to know the list of properties (tags) available in some command’s output. What do you attach after it?
5. Model Answers & Completion Criteria
Mission Walkthrough
# 1
Get-Process | Where-Object {$_.WorkingSet -gt 524288000}
# 2
Get-Process | Where-Object {$_.ProcessName -eq "powershell"} | Measure-Object
# 3
Get-ChildItem C:\Windows\System32 | Sort-Object LastWriteTime -Descending | Select-Object -First 3
# 4
Get-Process | Sort-Object ProcessName | Select-Object -First 10
More important than how many you got right is reviewing, for the ones you missed, which machine you chose wrong.
Exercise Answers
Answer 1. The Linux pipe passes text, but the PowerShell pipe passes objects (things with properties/tags attached). That’s why PowerShell can sort and filter precisely by property name, independent of what’s shown on screen.
Answer 2. It’s a pronoun pointing to the one item passing by right now on the pipe (belt). $_.Length means "the Length property of that item passing by."
Answer 3.
Get-ChildItem $HOME -File | Where-Object {$_.Length -eq 0}
(It works without -File, but folders get mixed in. And the comparison is -eq — not =!)
Answer 4. Attach | Get-Member. Example: Get-ChildItem | Get-Member. The lines marked Property are the candidates you can sort and filter by.
Completion Checklist
- [ ] I can explain that the pipe
|"passes the left result as the right side’s material" - [ ] I know PowerShell passes "objects (things with tags)" instead of text
- [ ] I can build the combination
Get-Process | Sort-Object ... | Select-Object -First N - [ ] I can use the
Where-Object {$_ ... }shell from memory - [ ] I’ve built the habit of reaching for
Get-Memberwhen curious about properties - [ ] I assembled the 4 mission problems myself
6. Common Pitfalls & Fixes
Wall 1. Where-Object lets nothing through (empty result)
Three candidate causes: ① the number in your condition is too big — lower the threshold. ② A typo in the property name — check exact spelling with Get-Process | Get-Member. ③ Comparing text as if it were a number (or vice versa). Also remember that an empty result may not be a malfunction but simply "no matches."
Wall 2. I forgot the {} or the $_
If you type Where-Object $_.CPU -gt 100 without the braces, you get an error. This one command has a peculiar shape, so memorize it as a shell: Where-Object { $_.property comparison }. Only the inside changes.
Wall 3. I used = and got an error (or a weird result)
In PowerShell, = is "assignment" (putting something into a variable), not "equality comparison." Comparisons are -eq, size comparisons are -gt/-lt. You’ll be tempted by math symbols, but this is PowerShell tradition.
Wall 4. Sorting seems to happen as text, not numbers
Rarely, when a property is stored as a string, sorting puts "10" before "9." Get-Process’s CPU/WorkingSet are numbers so this problem doesn’t occur here, but remember this trap — you’ll meet it later when handling CSV files and the like.
Wall 5. I don’t know what to attach after the pipe
Memorize it like a formula: "get a list → process it → trim it." And when unsure, type one stage at a time. Run just Get-Process, then add | Sort-Object ..., then | Select-Object .... Extending the belt while confirming each stage’s output with your eyes is the beginner’s correct form.
7. Summary
Today’s Assembly Parts
| Machine (command) | Role | Example |
|---|---|---|
Sort-Object property -Descending |
Sort (biggest first) | Sort-Object CPU -Descending |
Select-Object -First N |
Trim to the first N | Select-Object -First 10 |
Where-Object {$_.property condition} |
Conditional filter | Where-Object {$_.CPU -gt 100} |
Get-Member |
Inspect the property list | Get-Process | Get-Member |
Measure-Object |
Count | ... | Measure-Object |
Comparison Operators
-eq (equals) / -ne (not equal) / -gt (greater than) / -lt (less than)
All-Purpose Skeleton
(get a list) | (sort or filter) | (trim)
Instincts That Matter More Than Commands
"Translate the problem into a conveyor belt." "Find suspicious processes" is really "get a list → filter by a condition → trim for readability." And attaching one stage at a time and checking is the beginner’s assembly method.
One nice-to-know: besides -First N, Select-Object can also pick only the tags (columns) you want to see, like Select-Object ProcessName, CPU. Try Get-Process | Select-Object ProcessName, CPU -First 5 — a technique you’ll use when making reports.
Once every box is checked, Step 3 is complete. Click the checkbox in the sidebar to save your progress.