What would you like to learn?

Try PowerShell, networks, XSS, or Step 138

Browse the full curriculum →

PowerShell

Step 3. The Pipe (|) — A Way of Thinking That Assembles Commands

Step 3Estimated practice · 2–3 hours

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, and Where-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 name
  • CPU(s) — total CPU time used so far (seconds)
  • WS(K) — memory usage
  • Id — 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 5 show? 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.

  1. "Show me only processes using more than 500MB (=524288000) of memory (WorkingSet)"
  2. "Show me how many processes named powershell are running right now" (hint: attach | Measure-Object after the filter to count them)
  3. "Show me the 3 most recently modified files in C:WindowsSystem32" (hint: the modification-time tag is LastWriteTime)
  4. "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?


Answers & completion criteria · expand/collapse

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:WindowsSystem32 | 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-Member when 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.

ONE STEP FURTHER

Finished this lesson?

Check the completion criteria, then mark your progress.

Something wrong with this page or a link? Let us know.
Next