Chapter 04Lesson 01~100 minutes

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().FullName

The 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

$workers
6

Compound 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 | 3
Maintainability rule: Prefer one clear assignment per conceptual decision in production scripts. Multiple assignment is useful for small, obvious decompositions, but a dense line can hide configuration mistakes.

3. 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.

VariableBeginner meaningTypical DevOps use
$PSVersionTablePowerShell edition/version/platform detailsRecord runtime facts in diagnostics.
$PWDCurrent PowerShell locationResolve or report working-directory assumptions.
$HOMECurrent user home directoryBuild user-scoped paths portably.
$PIDProcess ID of the current PowerShell processCorrelate logs or inspect the current process.
$?Whether the last operation succeeded in PowerShell termsImmediate status checks; Chapter 10 deepens error handling.
$LASTEXITCODEExit code from the most recent native executableCross the native-process boundary taught in Chapter 02.
$ErrorRecent PowerShell error recordsInteractive 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 $emptyArray
True
False
False
False

A 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.

Do not confuse null with false: $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:PATH

Environment 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 -Force

A 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
}

$configuration

The 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, Value

Later 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?

Question 2. Why is $null -eq $value a useful defensive style?

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

Next lesson

Numbers and types give configuration values enforceable meaning

Lesson 02 keeps the same configuration mindset and turns raw values into integers, Booleans, dates, durations, versions, and other typed state.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.