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 |
|---|---|
|
Every user, every host |
|
Every user, current host (Console / ISE / VS Code) |
|
Current user, every host |
|
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 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 (
Azmodule) 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#
PowerShell as a command interpreter. Syntax, operators, control flow, advanced functions, error handling, the runtime.
Streams (six of them, not three), redirection, the object pipeline, parallel pipelines, jobs.
Strings, numerics, arrays, hashtables, PSCustomObject, classes, the standard .NET types under the hood.
Search, sort, group, dedupe through Sort-Object /
Group-Object / Compare-Object. When LINQ-style
pipelines beat explicit loops.
Built-in cmdlets, modules, the PowerShell Gallery,
Import-Module.
Pester for testing, PSScriptAnalyzer for linting, PowerShell Universal, common module patterns.
Invoke-RestMethod, Invoke-WebRequest,
Test-NetConnection, PSRemoting over WinRM and SSH.
Set-StrictMode, $ErrorActionPreference,
parameter validation, the advanced-function template.
The interpreter, PSScriptAnalyzer, the language server, profiling, debugging.