PowerShell#

PowerShell is Microsoft’s object-oriented shell. Pipelines pass typed .NET objects instead of text. Cross-platform since 6.0; the default administrative shell on Windows and a serious contender on Linux and macOS for any operator whose work crosses into Active Directory, Hyper-V, Azure, or Microsoft 365.

PowerShell as an interactive shell, PSReadLine line editing, Get-Help, Get-Command, Get-Member discovery, tab- completion on cmdlet parameter names. PowerShell as a scripting language, typed parameters, advanced functions with [CmdletBinding()], modules with manifest files, real classes, remoting over WinRM and SSH. The chapters below cover both faces.

Setup#

Install the cross-platform PowerShell (the artist formerly known as PowerShell Core; version 7+ is the current line):

$ winget install Microsoft.PowerShell           # Windows
$ brew install --cask powershell                # macOS
$ sudo apt install powershell                   # Debian / Ubuntu
$ sudo dnf install powershell                   # RHEL / Fedora

Launch with pwsh (not powershell, which is the older Windows-only 5.1):

pwsh
$PSVersionTable                                  # confirm version

Files#

PowerShell init files split by host (Console vs. ISE vs. VS Code) and by scope (all users vs. current user). The defaults differ between Windows PowerShell 5.1 and PowerShell 7+; inspect $PROFILE to see the path for the current host:

File

Loaded for

$PROFILE.AllUsersAllHosts

Every user, every host

$PROFILE.AllUsersCurrentHost

Every user, current host (Console / ISE / VS Code)

$PROFILE.CurrentUserAllHosts

Current user, every host

$PROFILE.CurrentUserCurrentHost

Current user, current host (the most common file)

Inspect from the prompt:

$PROFILE | Format-List *
Test-Path $PROFILE
notepad $PROFILE                                 # or code, vim, etc.

Most user customization goes in $PROFILE.CurrentUserCurrentHost.

Object Pipelines#

The defining feature, and the reason PowerShell exists. Bash pipes bytes between processes and forces every consumer to re-parse the text; PowerShell pipes typed .NET objects, so a downstream cmdlet can ask for $_.Name instead of slicing column 11 with awk. The same idea drives Nushell on the Linux side.

$ ps aux | grep nginx | awk '{print $2}'

PowerShell pipes objects:

Get-Process | Where-Object Name -like "nginx*" | Select-Object Id

Each cmdlet emits objects; downstream cmdlets access fields by name, not column position.

Cmdlets#

PowerShell commands follow a Verb-Noun convention, with verbs drawn from a fixed approved list (Get-Verb prints it). Discoverability is a core value: knowing the verb narrows down what to search for, and Get-Command -Verb Get lists every cmdlet that retrieves something.

Aliases shortcut the verbose names. The operator usually keeps these around because typing Get-ChildItem two hundred times a day is unreasonable:

Alias

Cmdlet

Bash equivalent

ls / dir / gci

Get-ChildItem

ls

cd / sl

Set-Location

cd

cat / gc

Get-Content

cat

cp / copy / ci

Copy-Item

cp

ps / gps

Get-Process

ps

%

ForEach-Object

xargs / shell for

? / where

Where-Object

grep / shell if

select

Select-Object

cut / awk

Line Editing (PSReadLine)#

The interactive editing module that ships with modern PowerShell. PSReadLine adds Bash-style line editing, history search, syntax highlighting, and predictive autocomplete, the things that make a shell feel modern at the prompt rather than only powerful in scripts:

Set-PSReadLineOption -EditMode Emacs              # or Vi
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -Function ReverseSearchHistory

Most-used keys (Emacs mode):

Keys

Action

Ctrl-A / Ctrl-E

Start / end of line

Alt-F / Alt-B

Forward / back one word

Ctrl-K

Kill to end of line

Ctrl-W

Kill word back

Ctrl-R

Reverse history search

Ctrl-L

Clear screen

Tab

Completion menu

Alt-.

Last argument of previous command

History#

PowerShell records command history per session in memory and to disk via PSReadLine. The history file lives under (Get-PSReadLineOption).HistorySavePath. Defaults are generous; the operator rarely needs to bump them.

Get-History                                       # session history
Get-Content (Get-PSReadLineOption).HistorySavePath | Select-Object -Last 10

Set-PSReadLineOption -HistoryNoDuplicates -MaximumHistoryCount 10000

Completion#

Tab cycles candidates; MenuComplete (Ctrl-Space by default) shows a graphical menu. Cmdlet parameter names complete by default; parameter values complete when the cmdlet author declared an ArgumentCompleter. Many vendor modules (Az, AWS.Tools, Microsoft.Graph) ship completions on import.

Set-PSReadLineKeyHandler -Chord 'Tab' -Function MenuComplete

Strengths#

What PowerShell does that no Unix shell matches. The object pipeline is the headline; the depth of integration with Microsoft / .NET infrastructure is the reason most operators end up using it even when they would rather not.

  • Object pipelines, no more parsing text columns.

  • Tight integration with Windows administration (Active Directory, Hyper-V, Exchange, Azure).

  • Cross-platform since PowerShell Core (now just “PowerShell” 7+).

  • Discoverable, Get-Help, Get-Member, Get-Command, Get-Verb.

  • Big standard library of cmdlets.

  • Real .NET access, drop into the framework when no cmdlet fits.

Weaknesses#

The cost of bringing a .NET shell to a Unix world. Most show up as friction rather than dealbreakers, but together they explain why PowerShell rarely displaces Bash on Linux even when it is installed and available.

  • Verbose, everything is Verb-Noun-Adjective-Adverb until you alias it.

  • Startup time, slower than Bash / Fish; precompiled profiles help.

  • Cultural mismatch on Linux, Bash idioms still dominate Linux scripting.

  • .NET-isms, type casts, reflection, occasional dialog boxes are surprising in a shell.

  • Two versions in the wild, Windows PowerShell 5.1 (Windows- only, .NET Framework) and PowerShell 7+ (cross-platform, .NET); scripts that target one may not run on the other.

When to Pick PowerShell#

The default any time Windows or Microsoft-managed cloud services are in scope. On a pure-Linux operator station Bash or Zsh wins on muscle memory and tooling, but the moment Active Directory, Hyper-V, Azure, or Microsoft 365 enters the picture, PowerShell pays for itself.

  • Windows administration, it is the default for a reason.

  • Cross-platform automation that targets Windows + Linux uniformly.

  • Cloud / infra work in Azure (Az module) and Microsoft 365 (Microsoft.Graph).

  • Teams already deep in the Microsoft / .NET stack.

For Linux-only or macOS-only work, Bash / Zsh / Fish / Nu are usually better defaults; PowerShell shines when Windows is in the mix.

Chapters#

Overview

PowerShell as a command interpreter. Syntax, operators, control flow, advanced functions, error handling, the runtime.

Overview
I/O and Pipelines

Streams (six of them, not three), redirection, the object pipeline, parallel pipelines, jobs.

I/O and Pipelines
Structures

Strings, numerics, arrays, hashtables, PSCustomObject, classes, the standard .NET types under the hood.

Structures
Algorithms

Search, sort, group, dedupe through Sort-Object / Group-Object / Compare-Object. When LINQ-style pipelines beat explicit loops.

Algorithms
Libraries

Built-in cmdlets, modules, the PowerShell Gallery, Import-Module.

Libraries
Frameworks

Pester for testing, PSScriptAnalyzer for linting, PowerShell Universal, common module patterns.

Frameworks
Networking

Invoke-RestMethod, Invoke-WebRequest, Test-NetConnection, PSRemoting over WinRM and SSH.

Networking
Patterns

Set-StrictMode, $ErrorActionPreference, parameter validation, the advanced-function template.

Patterns
Tools

The interpreter, PSScriptAnalyzer, the language server, profiling, debugging.

Tools