Anatomy of a PowerShell file
PowerShell is a cross-platform task automation and configuration management framework, consisting of a command-line shell and scripting language.
File extensions: .ps1
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside a PowerShell file
Shebang
Specifies the interpreter path (for non-Windows systems).
On Linux and macOS, #!/usr/bin/pwsh tells the kernel which interpreter should run the script when it is invoked directly, e.g. ./script.ps1 after chmod +x. PowerShell itself treats the line as an ordinary comment, so it has no effect on Windows. It is entirely optional when the script is run explicitly with pwsh ./script.ps1, and Windows PowerShell/powershell.exe never looks for it at all: the shebang only matters for cross-platform pwsh-based execution.
Comment
Single-line (#) or block (<# ... #>), ignored by interpreter.
A # starts a comment that runs to the end of the line, just like in many shell languages. A block comment opens with <# and closes with #>, and can span multiple lines, which makes it the natural home for comment-based help. When a block comment sits at the very top of a script or function and contains keywords like .SYNOPSIS, .DESCRIPTION, and .PARAMETER, Get-Help parses it directly and displays it the same way it displays help for built-in cmdlets.
Variable declaration ($)
Starts with $, dynamically typed.
Every variable name is prefixed with $ and requires no declared type. $target = "World" and $target = 3.14 are both valid, and the underlying .NET type is inferred at assignment. Optional type constraints like [int]$count = 0 add a static check without changing the dynamic-by-default model. Variables are scoped to the block or script that creates them by default, but scope modifiers such as $script:name, $global:name, and $local:name let a script explicitly reach outside or restrict access to the current scope.
Parameter block (param)
Defines input parameters for functions/scripts.
A param(...) block, placed as the first statement in a script or function, declares the arguments callers can supply by name or position. Each parameter can carry a type constraint like [string], a default value, and attributes such as [Parameter(Mandatory)] that make PowerShell prompt for the value if it is missing. Because parameters are strongly described up front, PowerShell can generate parameter validation, tab completion, and help text automatically, without any extra parsing code in the function body.
Function definition (function)
Defines a reusable block of code.
The function keyword binds a name and a script block together; the body executes each time the function is called. Function names conventionally follow the Verb-Noun pattern used by built-in cmdlets, drawn from a small set of approved verbs (Get, Set, New, Remove, and so on) that Get-Verb lists. Following that convention is not just style: it is what lets a custom function behave and discover like a real cmdlet, including showing up correctly in tab completion and Get-Command output alongside built-ins.
Cmdlet call
Executing a built-in or custom command.
Cmdlets are commands named in the same Verb-Noun form, such as Get-Date or Write-Host, implemented as .NET classes rather than standalone executables. Arguments are passed as named parameters, e.g. -Format $Format, which makes call sites self-documenting compared to positional flags. A custom function defined with function is invoked exactly the same way as a built-in cmdlet (Get-FormattedDate -Format "...") because PowerShell does not distinguish the two at the call site.
String interpolation
Embeds expressions/variables in double-quoted strings using $().
Inside double-quoted strings, $name expands a simple variable directly, while $(expression) (the subexpression operator) evaluates an arbitrary expression, including a cmdlet call, and inserts its result. "Current Date: $(Get-Date -Format $Format)" runs Get-Date and splices its output into the string. Single-quoted strings never interpolate: '$name' is inserted literally, which is why interpolation and variable expansion are one of the main reasons to prefer double quotes for user-facing text.
Control flow (Loop)
Executes code repeatedly (foreach, for, while, do).
foreach ($item in $collection) { ... } walks each element of a collection or range, such as 1..3; for and while support counter- and condition-driven iteration respectively. Unlike the ForEach-Object cmdlet used in a pipeline, the foreach statement loads the whole collection into memory before iterating. break exits a loop immediately and continue skips to the next iteration, matching the behavior familiar from C-style languages. Ranges like 1..3 are inclusive on both ends, producing 1, 2, 3.
Control flow (Conditional)
Executes code based on a condition (if, elseif, else, switch).
if/elseif/else branch on a boolean expression, using comparison operators spelled as letter codes (-eq, -ne, -lt, -gt) rather than symbols like ==, because = is reserved for assignment and </> are reserved for redirection. Conditions are always parenthesized: if ($i -eq 2) { ... }. For more than a couple of branches, switch compares a value against several patterns at once and supports wildcard, regex, and script-block conditions, often replacing a long elseif chain.
Function call
Executing a defined function.
Calling a PowerShell function looks like calling any cmdlet: the function name followed by its parameters, e.g. Get-FormattedDate -Format "dddd, MMMM dd, yyyy": no parentheses or commas separate the arguments, unlike a typical C-family method call. A function's output is whatever it writes to the pipeline, whether via an explicit return or simply by letting a value fall through unassigned; that output can be captured in a variable, piped into another command, or displayed directly.
Official PowerShell site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.