Free Ebook cover Windows PowerShell for Beginners: Everyday Automation and System Insights

Windows PowerShell for Beginners: Everyday Automation and System Insights

New course

10 pages

PowerShell Pipelines: Passing Objects Instead of Text

Capítulo 3

Estimated reading time: 7 minutes

+ Exercise

A mental model: the pipeline passes objects

In many traditional command prompts, a pipeline passes text: one command prints characters, and the next command tries to interpret those characters. In PowerShell, the pipeline passes .NET objects: structured data with a type, properties (data fields), and methods (actions). This difference is why PowerShell pipelines can be more reliable and readable: you can filter and sort by real properties instead of parsing text.

Think of each pipeline stage as a worker on an assembly line

  • Stage 1 produces objects (for example, process objects).
  • Stage 2 receives those objects and can filter, reshape, or enrich them.
  • Stage 3 receives the updated objects, and so on.

Only at the very end does PowerShell typically format objects into text for display. That formatting is for your screen; it is not what flows through the pipeline.

Side-by-side demo: text output vs object properties

Let’s compare a text-oriented approach with an object-oriented approach. The goal: find processes using more than a certain amount of CPU time.

Text-style thinking (what you might do elsewhere)

In a text pipeline world, you might list processes and then try to match lines with a text tool. In PowerShell, you can convert to text and do string matching, but it is fragile.

# This turns objects into formatted text, then filters by text (fragile pattern) Get-Process | Out-String -Stream | Select-String -Pattern "chrome"

This “works” for some cases, but it depends on how the output is formatted and what columns happen to be displayed. It also loses the original object structure.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

Object-style thinking (PowerShell’s strength)

Instead, filter by properties on the process objects:

# Filter by the Name property (robust) Get-Process | Where-Object { $_.Name -like "*chrome*" }

Here, $_ represents the current object flowing through the pipeline. $_.Name is a real property, not a substring in a line of text.

Seeing the difference: formatted view vs real data

When you run Get-Process, you see a table-like display. That display is a formatted view, not the full object. To prove it, select properties that are not shown by default:

# Show properties you choose, even if they aren't in the default table Get-Process | Select-Object -First 5 -Property Name, Id, CPU, StartTime

If a property isn’t available for a particular process (for example, StartTime may require permissions or may not be accessible), PowerShell will show blanks or errors depending on the situation. The key point: you are working with structured fields.

Inspecting pipeline objects with Get-Member

To use objects effectively, you need to know what type you’re receiving and what properties/methods it exposes. Get-Member (alias: gm) is your microscope.

What type is flowing through the pipeline?

Get-Process | Get-Member

You’ll see output indicating the object type (commonly System.Diagnostics.Process) and a list of members.

Focus on properties only

Get-Process | Get-Member -MemberType Property

This helps you discover what you can filter, sort, and select.

Focus on methods (actions you can call)

Get-Process | Get-Member -MemberType Method

Methods are actions on the object (for example, process-related methods). In pipelines, you’ll more commonly use properties for filtering/sorting and occasionally use methods when you intentionally want to perform an action.

Mini-check: inspect a single object

Sometimes it’s easier to inspect one item rather than the whole set:

$p = Get-Process | Select-Object -First 1 $p | Get-Member

This reinforces the idea that the pipeline is passing objects you can store, inspect, and reuse.

Core pipeline patterns you’ll use every day

Most practical pipelines are built from a few repeatable patterns. You’ll often combine them in this order:

Get-Something | Where-Object ... | Sort-Object ... | Select-Object ...

Grouping is a special case that often comes after filtering and before final formatting.

Filtering with Where-Object

Where-Object keeps only objects that match a condition.

# Keep processes with CPU time greater than 100 seconds Get-Process | Where-Object { $_.CPU -gt 100 }

Common comparison operators you’ll see:

  • -eq equals
  • -ne not equals
  • -gt greater than
  • -ge greater than or equal
  • -lt less than
  • -le less than or equal
  • -like wildcard match (use *)
  • -match regex match

Selecting with Select-Object

Select-Object chooses which properties to output (and can also limit the number of objects).

# Show only a few useful fields Get-Process | Select-Object -Property Name, Id, CPU
# Take only the first 10 objects Get-Process | Select-Object -First 10

You can also create calculated properties to make pipelines more readable:

# Add a calculated property in MB Get-Process | Select-Object Name, Id, @{Name='WorkingSetMB'; Expression = { [math]::Round($_.WorkingSet64 / 1MB, 1) } }

Sorting with Sort-Object

Sort-Object orders objects by one or more properties.

# Sort by CPU descending Get-Process | Sort-Object -Property CPU -Descending
# Sort by Name, then by Id Get-Process | Sort-Object -Property Name, Id

Grouping with Group-Object

Group-Object clusters objects that share the same value for a property.

# Group processes by name (how many instances of each process) Get-Process | Group-Object -Property Name

The output is itself objects (group objects) with useful properties like Name and Count. You can keep working with them:

# Show the most common process names Get-Process | Group-Object Name | Sort-Object Count -Descending | Select-Object -First 10 Name, Count

Guided mini-lab 1: from broad to targeted (Get-Process)

Goal: build a readable pipeline that finds the top CPU-consuming processes and shows a clean summary.

Step 1: Start broad

Get-Process

Notice you get many objects. The screen shows a table, but remember: objects are flowing.

Step 2: Inspect what you can use

Get-Process | Get-Member -MemberType Property

Look for properties like Name, Id, CPU, WorkingSet64.

Step 3: Filter to “interesting” processes

For example, keep only processes that have recorded CPU time:

Get-Process | Where-Object { $_.CPU -ne $null }

Or filter by a name pattern:

Get-Process | Where-Object { $_.Name -like "*svchost*" }

Step 4: Sort to find the top consumers

Get-Process | Where-Object { $_.CPU -ne $null } | Sort-Object CPU -Descending

Step 5: Select a small, readable set of fields

Get-Process | Where-Object { $_.CPU -ne $null } | Sort-Object CPU -Descending | Select-Object -First 10 -Property Name, Id, CPU

Step 6: Add a calculated property for memory in MB

Get-Process | Where-Object { $_.CPU -ne $null } | Sort-Object CPU -Descending | Select-Object -First 10 Name, Id, CPU, @{Name='WorkingSetMB'; Expression={ [math]::Round($_.WorkingSet64/1MB,1) }}

What you built is a classic object pipeline: produce objects → filter → sort → shape the output.

Guided mini-lab 2: grouping and then refining

Goal: identify which process names have the most running instances, then drill into one of them.

Step 1: Group by process name

Get-Process | Group-Object Name

Step 2: Sort groups by count

Get-Process | Group-Object Name | Sort-Object Count -Descending

Step 3: Select the top results

Get-Process | Group-Object Name | Sort-Object Count -Descending | Select-Object -First 10 Name, Count

Step 4: Drill into a specific name

Pick one of the names you saw (example: svchost) and list its instances with useful properties:

Get-Process | Where-Object { $_.Name -eq 'svchost' } | Sort-Object Id | Select-Object Name, Id, CPU, @{Name='WorkingSetMB'; Expression={ [math]::Round($_.WorkingSet64/1MB,1) }}

Notice how grouping gave you a summary, and then you returned to the original objects to investigate details.

Common pipeline “gotchas” that objects help you avoid

1) Formatting too early breaks object pipelines

Cmdlets like Format-Table and Format-List are meant for display. If you use them in the middle of a pipeline, you usually convert rich objects into formatting instructions, making later filtering/sorting unreliable.

# Avoid this pattern (formatting too early) Get-Process | Format-Table Name, CPU | Where-Object { $_.CPU -gt 100 }

Instead, filter/sort/select first, and only format at the end if you need custom display.

2) Some properties may be missing or inaccessible

Because you’re dealing with real system objects, some properties can be $null or throw access-related errors. A simple defensive filter can help:

# Keep only processes where StartTime is available Get-Process | Where-Object { $_.StartTime -ne $null } | Select-Object Name, Id, StartTime

Quick reference: a pipeline “recipe card”

TaskPatternExample
Filter objects... | Where-Object { condition }Get-Process | Where-Object { $_.Name -like '*sql*' }
Pick properties... | Select-Object Prop1,Prop2Get-Process | Select-Object Name,Id,CPU
Limit results... | Select-Object -First N... | Sort-Object CPU -Desc | Select-Object -First 5
Sort results... | Sort-Object Prop [-Descending]Get-Process | Sort-Object WorkingSet64 -Descending
Group results... | Group-Object PropGet-Process | Group-Object Name

Now answer the exercise about the content:

In PowerShell, why is filtering processes with Where-Object (for example, $_.Name -like "*chrome*") generally more reliable than converting output to text and using string matching?

You are right! Congratulations, now go to the next page

You missed! Try again.

PowerShell pipelines pass objects, not plain text. Where-Object filters using real object properties (like Name), which is more robust than converting output to formatted text and matching strings that depend on display formatting.

Next chapter

Finding and Shaping Output: Filtering, Formatting, and Exporting Results

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.