Variables, Assignment, Automatic Variables, and Environment Data
Learn how PowerShell variables bind names to objects, how assignment and automatic variables behave, how $null differs from empty values, and how environment data crosses process boundaries.
Learning objectives
- Explain variables as names bound to typed values/objects and distinguish them from environment variables.
- Use simple, multiple, and compound assignment with readable variable names and braced-name syntax where needed.
- Inspect useful automatic variables without treating PowerShell-owned state as scratch storage.
- Test $null deliberately and distinguish null from empty strings, zero, false, and empty collections.
- Read environment data through Env: and account for cross-platform name casing and process inheritance.
- Assemble a safe configuration snapshot without modifying machine-wide environment settings.
1. Variables are names that let you reach values
Chapter 03 taught you to follow objects as they move through a pipeline. A variable gives an object a name so you can use it again later. The dollar sign is part of PowerShell variable syntax: $serviceName means “look up the value currently associated with the variable named serviceName.” The variable is not a text replacement macro; it can refer to a string, number, date, process object, collection, or almost any other .NET object.
$serviceName = 'payments-api'
$retryCount = 3
$now = Get-Date
$serviceName
$retryCount.GetType().Name
$now.GetType().FullNameThe displayed values differ, but the important observation is that each variable refers to a typed value. PowerShell does not require you to declare a type first for an ordinary variable. Later in this chapter you will learn when constraining or converting a type is useful.
2. Assignment stores a result; compound assignment updates it
The assignment operator = evaluates the expression on its right and assigns the resulting value to the variable on its left. This means command output can be assigned directly, not only literals.
$startedAt = Get-Date
$workers = 2
$workers += 1
$workers *= 2
$workers6Compound operators such as +=, -=, *=, and /= combine an operation with assignment. They are convenient, but use them only when the new value is naturally understood as an update of the old value.
PowerShell also supports multiple assignment. The right side is evaluated first and then distributed across the variables on the left.
$environment, $region, $replicas = 'staging', 'eu-west', 3
"$environment | $region | $replicas"staging | eu-west | 33. Variable names are flexible; readable names are still a design choice
Simple variable names can contain letters, numbers, and underscores, and PowerShell variable names are normally case-insensitive. Use descriptive names such as $deploymentRoot rather than $dr when the value survives more than a few lines. A variable can also use braces when the name must be separated from surrounding text or contains unusual characters.
$app = 'catalog'
"Deploying ${app}-worker"
${build-number} = 42
${build-number}Braced names are especially important inside expandable strings when characters immediately after the variable could be interpreted as part of the variable name. Unusual names are legal, but ordinary scripts are easier to review when names stay conventional.
4. Automatic variables expose useful session state
PowerShell creates and maintains a set of automatic variables. They expose information about the shell, the current location, recent command status, the current process, and other execution state. Treat them as information supplied by PowerShell rather than scratch variables for your own data.
| Variable | Beginner meaning | Typical DevOps use |
|---|---|---|
$PSVersionTable | PowerShell edition/version/platform details | Record runtime facts in diagnostics. |
$PWD | Current PowerShell location | Resolve or report working-directory assumptions. |
$HOME | Current user home directory | Build user-scoped paths portably. |
$PID | Process ID of the current PowerShell process | Correlate logs or inspect the current process. |
$? | Whether the last operation succeeded in PowerShell terms | Immediate status checks; Chapter 10 deepens error handling. |
$LASTEXITCODE | Exit code from the most recent native executable | Cross the native-process boundary taught in Chapter 02. |
$Error | Recent PowerShell error records | Interactive diagnosis; do not use it as your only error-handling strategy. |
$PSVersionTable | Select-Object PSEdition, PSVersion, OS, Platform
"PowerShell PID: $PID"
"Home: $HOME"
"Current location: $PWD"Many automatic variables can technically be assigned for compatibility reasons, but Microsoft documents most of them conceptually as read-only. Avoid overwriting them. You will meet additional automatic variables such as $_/$PSItem, $Matches, and $PSScriptRoot in the chapters where they have a concrete purpose.
5. $null means “no value”; test it deliberately
$null represents the absence of a value. That sounds simple, but bugs appear when “missing,” empty string, zero, and empty collection are treated as if they were the same thing. They are not.
$notSet = $null
$emptyText = ''
$zero = 0
$emptyArray = @()
$null -eq $notSet
$null -eq $emptyText
$null -eq $zero
$null -eq $emptyArrayTrue
False
False
FalseA defensive convention is to put $null on the left side of -eq or -ne. PowerShell comparison operators behave differently when the left operand is a collection: they can filter matching elements instead of returning one Boolean. Writing $null -eq $value asks a scalar null question unambiguously.
$null, $false, 0, and '' may all behave as false-like values in some conditional contexts, but they carry different meaning and often different types. Preserve that distinction in configuration validation.6. PowerShell variables and environment variables live in different places
An ordinary variable such as $region belongs to PowerShell session state. An environment variable is process environment data used by the operating system and applications. PowerShell exposes the process environment through the Env: provider, so each environment variable appears like an item in a special drive.
$region = 'eu-central'
# Inspect environment data without changing it.
Get-ChildItem Env: | Sort-Object Name | Select-Object -First 10
$env:PATHEnvironment variable values are strings. Child processes normally inherit the environment of the PowerShell process that starts them. Assigning $env:DEMO_MODE = 'safe' changes the environment of the current PowerShell process and processes launched from it; it is not the same as configuring a persistent machine-wide setting.
Environment variable names are case-insensitive on Windows but case-sensitive on Linux and macOS. For cross-platform automation, use the conventional casing of well-known names such as PATH and do not assume $env:Path and $env:PATH are interchangeable everywhere.
7. Read-only and constant variables are guardrails, not everyday defaults
PowerShell can mark variables as read-only or constant. This can protect important session configuration from accidental reassignment, but it is not a substitute for good script design. Deep scope and module-state rules belong to Chapter 08.
Set-Variable -Name CourseMode -Value 'training' -Option ReadOnly
Get-Variable CourseMode | Select-Object Name, Value, Options
# This fails because the variable is read-only.
# $CourseMode = 'production'
# A read-only variable can be removed with -Force when you intentionally created it.
Remove-Variable -Name CourseMode -ForceA constant variable is stricter: it cannot be changed or removed during that scope’s lifetime. Do not create throwaway constants in shared interactive sessions. For most automation, clear parameters, local variables, and validation provide better structure than filling the session with constants.
8. Build configuration state from explicit sources
A DevOps script often combines defaults, environment hints, and values discovered at runtime. The important design choice is to make the source of each value obvious before the script starts changing infrastructure.
$defaultEnvironment = 'dev'
$environmentFromEnv = $env:ACADEMY_ENVIRONMENT
if ($null -ne $environmentFromEnv -and $environmentFromEnv.Trim().Length -gt 0) {
$environment = $environmentFromEnv.Trim()
}
else {
$environment = $defaultEnvironment
}
$configuration = [pscustomobject]@{
Environment = $environment
PowerShellVersion = $PSVersionTable.PSVersion.ToString()
Home = $HOME
CurrentLocation = $PWD.Path
}
$configurationThe object is a read-only snapshot for this example: it records what the script decided. Chapter 05 develops structured state with arrays, hashtables, and PSCustomObject in depth. Here the focus is the variable flow: read inputs, normalize them, then bind the result to a clear name.
9. Diagnose variable mistakes by asking what value and type you actually have
When a variable-based script behaves strangely, avoid guessing. Inspect whether the variable exists, what value it contains, and what type that value has.
$timeout = '30'
Get-Variable timeout | Format-List Name, Value, Options
$timeout.GetType().FullName
# A typo creates/uses a different variable name if the spelling differs,
# but letter casing alone does not create a different variable.
$timeuot = 60
Get-Variable time* | Select-Object Name, ValueLater you will use strict mode, validation, and tests to catch these errors earlier. For now, develop the habit of observing state rather than mentally simulating it.
10. Why variable discipline matters in DevOps
Automation frequently carries high-impact state: target environment, subscription, cluster name, artifact version, retry count, and feature flags. A variable name is part of the safety interface. Prefer variables that make dangerous ambiguity difficult: $targetEnvironment is better than $env when $env: already has a distinct PowerShell meaning. Normalize external strings once, keep derived values separate from raw inputs, and log the configuration snapshot before mutation in production tools.
11. Lab: inspect and assemble session configuration without persistent changes
This lab is read-only with respect to machine-wide configuration. It inspects session/environment facts, creates ordinary variables and one process-scoped demonstration environment variable, then removes that demonstration variable before finishing.
$labName = 'chapter04-lesson01'
$defaultRegion = 'local'
$originalDemo = $env:ACADEMY_DEMO_REGION
try {
$env:ACADEMY_DEMO_REGION = 'training-region'
$rawRegion = $env:ACADEMY_DEMO_REGION
$region = if ($null -eq $rawRegion -or $rawRegion.Trim().Length -eq 0) {
$defaultRegion
}
else {
$rawRegion.Trim()
}
$state = [pscustomobject]@{
Lab = $labName
Region = $region
UserHome = $HOME
CurrentPath = $PWD.Path
PowerShell = $PSVersionTable.PSVersion.ToString()
ProcessId = $PID
}
$state | Format-List
$state | Get-Member
}
finally {
if ($null -eq $originalDemo) {
Remove-Item Env:ACADEMY_DEMO_REGION -ErrorAction SilentlyContinue
}
else {
$env:ACADEMY_DEMO_REGION = $originalDemo
}
}The try/finally structure is intentionally shown before the full error-handling chapter because it makes the cleanup guarantee easy to see: the environment value is restored even if something inside the lab fails.
Verification checklist
12. Common mistakes to avoid
Using environment variables for every internal value. Environment data is string-based process configuration, not a replacement for typed PowerShell variables.
Overwriting automatic variables. Treat PowerShell-owned state as read-only unless documentation explicitly describes a supported write scenario.
Testing only truthiness when the distinction matters. If empty string, zero, false, and null mean different things in your configuration, compare and validate them explicitly.
Relying on platform-specific environment-variable casing. Code that works with Path on Windows may fail on Linux/macOS when the real variable is PATH.
13. Knowledge check
Question 1. What is the conceptual difference between $region and $env:REGION?
$region is ordinary PowerShell session state and can hold any object; $env:REGION is process environment data, represented as a string and inherited by child processes.Question 2. Why is $null -eq $value a useful defensive style?
$null on the left makes the null test unambiguous.Question 3. What does $PSVersionTable provide?
Question 4. Does assigning $env:ACADEMY_MODE = "test" persist a machine-wide setting?
Question 5. When is a read-only variable useful?
14. Summary
Variables give names to typed values and objects. Assignment evaluates a right-hand expression and binds its result to a name. Automatic variables expose PowerShell-owned state, $null represents absence of a value, and the Env: provider exposes string-based process environment data. Good automation makes configuration sources explicit, normalizes external input once, and avoids mutating shared or machine-wide state merely to pass data around.
15. Further reading
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.