What PowerShell Actually Is: The Object Pipeline vs. Text Streams

PowerShell Fundamentals

Chapter 1 · What PowerShell Actually Is: The Object Pipeline vs. Text Streams

It's an easy first assumption: PowerShell opens in a black window, dir still lists a folder, cd still changes directory, so surely it's just the old MS-DOS/cmd.exe prompt with a longer command list bolted on. That assumption is exactly wrong, and it's worth correcting before anything else in this course, because the correction is the single idea everything else builds on. dir works in PowerShell — but so does ls, and so does gci, and none of that is a coincidence or a compatibility shim. It's a visible symptom of something genuinely different underneath: PowerShell doesn't pipe text between commands the way cmd.exe and Bash both do — it pipes real, structured .NET objects. That one design choice is what this whole chapter, and in a real sense this whole course, is built around.

Three Command-Line Lineages, Compared

Pipeline modelWhere it's covered on this site
cmd.exe (DOS legacy)Barely a pipeline at all — | exists, but every command's output is just a raw stream of characters, and batch scripting has no real data types or object model to speak ofNot separately covered — the legacy floor PowerShell was built to move past
BashA real pipeline, but a text one — every command's stdout is bytes, and tools like grep/awk/sed exist specifically to re-extract structure from that textBash Scripting Fundamentals, Intermediate & Advanced
PowerShellAn object pipeline — cmdlets pass real .NET objects to each other, with properties and methods still attached, no text parsing requiredThis course, and its own sequel

Seeing the Object Pipeline Directly

The clearest way to see the difference is to do the same everyday task both ways. Say you want the five files taking up the most space in a folder. In Bash, that means parsing ls's own text output by column position:

# Bash — sort by size, but only because the size happens to sit in a known text column ls -la | sort -k5 -rn | head -5

That works — until a locale change, a different ls implementation, or a filename with a space in it shifts the column layout, and the whole pipeline silently breaks. PowerShell's equivalent never touches text at all — it asks each file object directly for its Length property:

# PowerShell — sort by the real Length property on each file object, not a text column Get-ChildItem | Sort-Object Length -Descending | Select-Object -First 5

Sort-Object isn't guessing which column holds the size — it's reading an actual Length property that was already sitting on every object Get-ChildItem produced. Nothing about the file's name, spacing, or the current locale can break that.

The central fact this whole course is built on
In Bash, "the pipeline" means "a stream of bytes that the next command has to re-parse." In PowerShell, "the pipeline" means "a stream of live objects that the next command can query directly." Every cmdlet name, every Where-Object/Select-Object filter, and every script you'll write in this course leans on that one distinction — it's the reason PowerShell reads as a genuinely different tool once you get past the surface-level dir/cd familiarity, not a reskinned cmd.exe.

Filtering by Property, Not by Pattern

Counting .txt files makes the same point a second way — Bash has to pattern-match text, PowerShell just asks for the property:

# Bash — a regex has to reconstruct "does this line end in .txt" ls -la | grep '\.txt$' | wc -l # PowerShell — Extension is already a real property on the object, no regex needed Get-ChildItem | Where-Object Extension -eq '.txt' | Measure-Object

cmd.exe: The Legacy Floor PowerShell Was Built to Replace

cmd.exe traces directly back to COMMAND.COM in MS-DOS — a command interpreter, not a scripting language in any real sense. Batch files (.bat/.cmd) can loop and branch, but every variable is a string, there's no object model, and error handling is famously primitive (%ERRORLEVEL% checked by convention, not enforced). PowerShell — started inside Microsoft in 2002 under the codename Monad, released in 2006 — was built specifically to replace that floor: a real, typed, .NET-backed scripting language with a genuine shell wrapped around it, not an incremental patch to cmd.exe.

To ease that transition, PowerShell ships with built-in aliases that map familiar cmd.exe and Unix command names onto its own cmdlets — which is exactly why your original instinct that dir would still work, and that ls might also work, was correct on both counts:

Get-Alias dir, ls, gci # CommandType Name Definition # ----------- ---- ---------- # Alias dir -> Get-ChildItem # Alias ls -> Get-ChildItem # Alias gci -> Get-ChildItem

All three are just names for the same one cmdlet, Get-ChildItem — unlike cmd.exe's own dir, which isn't an alias for anything; it's cmd.exe's own single, built-in, non-substitutable implementation. And because PowerShell aliases are just names you can define yourself with Set-Alias (or a short function, for anything needing arguments), the same trick that gives you a Linux-style ll shortcut on a real terminal is available here too — Chapter 11 covers writing your own.

Windows PowerShell vs. PowerShell 7 — Which One Are You Actually Using?

One more thing worth sorting out before writing any real code: "PowerShell" today quietly refers to two different products.

  • Windows PowerShell 5.1 — built into every modern Windows install, running on the older .NET Framework, Windows-only, and now in maintenance mode: it still gets security fixes, but no new features.
  • PowerShell 7+ (sometimes called "PowerShell Core") — open-source, built on modern .NET, genuinely cross-platform (Windows, macOS, and Linux all run the identical pwsh), and where all active development happens.
$PSVersionTable.PSVersion # Major Minor Patch # ----- ----- ----- # 7 4 2 <- PowerShell 7.4.x (pwsh.exe) # 5 1 22621 <- Windows PowerShell 5.1 (powershell.exe)
A first practical habit
Run $PSVersionTable.PSVersion right now (or recall doing so) to see which one you're actually in. This course's examples target PowerShell 7+ (the pwsh executable) — everything shown works in Windows PowerShell 5.1 too unless a chapter says otherwise, but if you're setting up fresh, install PowerShell 7 rather than relying on whatever 5.1 build already shipped with Windows.
"It's just DOS with more commands" is a costly assumption
Treat PowerShell's output as text you need to grep or regex apart, the way you might in Bash, and you'll write exactly the kind of brittle script this chapter's Sort-Object/Where-Object examples were built to avoid — one that quietly breaks the moment a filename, a locale, or a column width shifts. The object pipeline exists precisely so you never have to reconstruct structure that was never actually lost in the first place.

Where This Course Is Headed

Navigating the object filesystem through PowerShell's provider model, cmdlet discovery and getting real help (Get-Help, Get-Command, Get-Member), the pipeline in real depth, variables and PowerShell's own type system, control flow, functions and script files, working with files/text/formatted output, error handling and basic debugging, execution policy and script security, and modules/aliases/the PowerShell Gallery — closing with a capstone automating a real administrative task end to end. PowerShell Intermediate/Advanced then picks up from there: remoting, parallel execution, .NET/COM interop, calling REST APIs, publishing your own modules, and more.

Hands-On Exercises

Exercise 1

Using this chapter's own .txt-counting example, explain in your own words why PowerShell's object pipeline avoids the "same command name doesn't guarantee the same result" trap that a Bash pipeline built on grep/regex can fall into.

📄 View solution
Exercise 2

Run Get-Alias dir, ls, gci (or recall this chapter's own output). What single cmdlet do all three point to? Then explain why cmd.exe's own dir isn't an alias for anything the same way.

📄 View solution
Exercise 3

Run $PSVersionTable.PSVersion (or recall this chapter's own explanation) and describe the practical difference between Windows PowerShell 5.1 and PowerShell 7+. Which one does this course target, and why?

📄 View solution

Chapter 1 Quick Reference

  • Object pipeline — PowerShell cmdlets pass real .NET objects to each other, properties and methods intact; Bash and cmd.exe both pass raw text
  • Get-ChildItem — the real cmdlet behind the dir, ls, and gci aliases
  • Sort-Object / Where-Object / Select-Object — filter and shape objects by real property, not by text pattern
  • Monad → PowerShell — started inside Microsoft in 2002, released 2006, built specifically to replace cmd.exe's text-only batch model
  • Windows PowerShell 5.1 — built in, .NET Framework, Windows-only, maintenance mode
  • PowerShell 7+ — cross-platform, modern .NET, actively developed; this course's own target
  • $PSVersionTable.PSVersion — check which one you're actually running
  • Next chapter: Getting Around: Providers, PSDrives & Navigating the Object Filesystem