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: the lesson commands read process and file information. They do not stop processes or change files. Record inaccessible information and its error; do not elevate privileges just to reveal it.
  • 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 unit, 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

This section’s Tools at a Glance

Category Details
Language/environment Windows PowerShell 5.1 / PowerShell 7 — the pipe (|) operator
This section’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

A Linux pipe carries a byte stream, which can contain text or binary data. A following program interprets text according to its expected format. Between the PowerShell cmdlets used here, the pipeline carries objects with properties.

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
├── WorkingSet64: 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 This section’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

Before you begin. PowerShell normally passes objects through its pipeline. Select properties before presentation formatting; use Format-Table or Format-List only at the display end of a pipeline.

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) — accumulated processor time in seconds, not current CPU utilization (%) or elapsed time since launch.
  • WS(K) — working set (pages resident in physical memory), shown in KiB. PowerShell 7 may show WS(M) in MiB instead. The WorkingSet64 property itself is measured in bytes.
  • 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 cumulative CPU time 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 worker
   1997      97   753512     309468   4,024.48  41684   1 ChatGPT
   2453      64   521032     168260   3,970.92  35616   1 chrome
... (up to 10 processes if enough exist; headings are extra)
  • Select-Object -First 10 — “pick only the first 10”

This selects up to 10 processes by accumulated CPU time. It does not reproduce Task Manager’s current CPU percentage ranking. The table illustrates the output format; names, counts, and values vary with the time of execution. A blank CPU value is not proof of zero usage: access restrictions or a process exiting can prevent a value from being read.

Predict first: what would Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 show? WorkingSet64 went in where CPU used to be. Predict, then run it.
(Answer: up to 5 processes with the largest working sets. Task Manager’s default memory column may use a different metric. 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 -in "powershell", "pwsh"}

-in checks for a match among the following values. Windows PowerShell normally runs as powershell; PowerShell 7 runs as pwsh, so the filter includes both. Other hosts may use another name. To inspect the current session itself, run:

Get-Process -Id $PID | Select-Object ProcessName, Id, CPU, WorkingSet64

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 -MemberType Properties
   TypeName: System.Diagnostics.Process

Name        MemberType    Definition
----        ----------    ----------
...
CPU         ScriptProperty System.Object CPU {get=$this.TotalProcessorTime.TotalSeconds;}
Id          Property      int Id {get;}
ProcessName Property      string ProcessName {get;}
WorkingSet64 Property      long WorkingSet64 {get;}
...

-MemberType Properties includes Property, ScriptProperty, AliasProperty, and other property kinds. CPU, for example, is a ScriptProperty. Details in the Definition column may vary between versions. 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 -File | Sort-Object Length -Descending | Select-Object -First 5

Read it as: select ordinary files directly under the home folder, sort by Length in bytes, and keep up to five. -File excludes folders. This does not search subfolders or calculate the total size of directories; hidden files are excluded by default.

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 500MiB (=524288000 bytes, the value of PowerShell’s 500MB) of memory (WorkingSet64)”
  2. “Show me how many processes named powershell or pwsh are running right now” (hint: attach | Measure-Object after the filter to count them)
  3. “Show me up to 3 most recently modified ordinary files directly in the Windows System32 folder” (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 {$_.WorkingSet64 -gt 524288000}
# 2
Get-Process | Where-Object {$_.ProcessName -in "powershell", "pwsh"} | Measure-Object
# 3
Get-ChildItem "$env:WINDIR\System32" -File | 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. A Linux pipe carries a byte stream containing text or binary data. The PowerShell cmdlet pipelines in this lesson carry objects, allowing selection by property name instead of display-column position. Pipelines involving external executables require separate consideration.

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}

Use -File so Length unambiguously refers to file size. This checks visible files directly under the home folder. No matching files means an empty result. The comparison operator is -eq.

Answer 4. Attach | Get-Member. Example: Get-ChildItem | Get-Member. Use Get-Member -MemberType Properties to include all property kinds, such as ScriptProperty and AliasProperty as well as Property.

Completion Checklist

  • [ ] I can explain that the pipe | “passes the left result as the right side’s material”
  • [ ] I know the cmdlet pipelines in this lesson pass objects with properties
  • [ ] 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 -MemberType Properties. ③ 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 $_

The script-block form used here combines braces with $_. A simplified comparison form such as Where-Object CPU -gt 100 also exists; do not mix the two forms. 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/WorkingSet64 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

This section’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 -MemberType Properties
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.


Practice verification record

Historical record. The dated record below describes the earlier lesson version. The current instructions include subsequent editorial corrections; that record does not certify every revised example.

2026-09-10 · Executed process listing, cumulative CPU sorting, filters, Get-Member, file sorting, and missions on Windows 11 with Windows PowerShell 5.1.26100.9444 and PowerShell 7.6.5. Live process values change continuously, so rankings are not fixed answer keys. Separate sample objects and newly created test files were used to verify conditions, ordering, and exclusion of folders. No processes were stopped and no system files were modified.

References: Microsoft Get-Process · Get-Member and property types · Linux pipe

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