Chapter 06Lesson 01~120 minutes

if, elseif, else, Truthiness, and Defensive Conditions

Build explicit operational decisions with PowerShell Boolean rules, short-circuit logic, defensive null checks, and guard clauses that make invalid configuration fail clearly.

Learning objectives

  • Explain how PowerShell converts nulls, numbers, strings, and zero/one/many-element collections to Boolean values.
  • Build readable if/elseif/else chains and compound conditions with short-circuit logical operators.
  • Write explicit null, range, and presence tests instead of relying on accidental truthiness.
  • Use guard clauses to keep normal automation paths shallow and failure conditions visible.
  • Diagnose assignment-in-condition and collection-comparison mistakes by examining the actual expression result.
  • Validate structured configuration in memory and produce explicit failure messages.

1. A condition is a decision boundary, not merely an if keyword

Operational automation constantly asks questions: is this configuration complete, is the selected environment allowed, is a port within range, or should a deployment stop before changing anything? A condition is an expression that PowerShell evaluates as true or false so code can choose whether to run a block of statements.

$environment = 'staging'

if ($environment -eq 'production') {
    'Use the production workflow.'
}
else {
    'Use the non-production workflow.'
}

The comparison expression $environment -eq 'production' produces a Boolean value. When the result is $true, PowerShell runs the first block; otherwise it runs the else block. Chapter 04 introduced comparison operators. This lesson focuses on how those results control execution.

2. PowerShell can convert many values to Boolean truthiness

PowerShell does not require every condition to already be a [bool]. It can interpret other values as Boolean. This convenience is useful, but it becomes dangerous when a condition depends on accidental data shape rather than an explicit business rule.

Value or shapeBoolean interpretationWhy it matters
$nullFalseNo value should not normally pass a presence test.
Numeric zero such as 0 or 0.0FalseA legitimate numeric zero can be mistaken for missing data.
Empty string ''FalseWhitespace is different; ' ' is non-empty and therefore true.
Non-empty stringTrueEven the literal text 'False' is true because it is a non-empty string.
Empty collectionFalseNo elements means false.
One-element collectionTruthiness of its one element@(0) is false while @(1) is true.
Collection with more than one elementTrueEven @(0,0) is true because the collection has multiple elements.
[bool]$null
[bool]0
[bool]''
[bool]'False'
[bool]@()
[bool]@(0)
[bool]@(0, 0)
False
False
False
True
False
False
True
Defensive rule: When zero, an empty string, or a collection can be a legitimate value, write the actual business condition instead of relying on implicit truthiness.

3. Build if/elseif/else from mutually exclusive operational cases

An elseif chain is appropriate when one input should select one of several ordered cases. PowerShell evaluates the conditions from top to bottom and stops at the first successful branch.

$replicas = 3

if ($replicas -lt 1) {
    'Invalid replica count.'
}
elseif ($replicas -eq 1) {
    'Single-instance deployment.'
}
elseif ($replicas -le 3) {
    'Small replicated deployment.'
}
else {
    'Larger replicated deployment.'
}

Order matters. A broad condition placed before a narrow one can make the narrow branch unreachable. Write the most exceptional or restrictive conditions first when that matches the business logic.

4. Compound conditions combine smaller tests with short-circuit logic

The logical operators -and and -or evaluate conditions from left to right and short-circuit when the final result is already known. This means the right side of -and is skipped when the left side is false, and the right side of -or is skipped when the left side is true.

$config = [pscustomobject]@{
    Environment = 'staging'
    Port = 8443
    Enabled = $true
}

if ($config.Enabled -and $config.Port -ge 1 -and $config.Port -le 65535) {
    'Configuration can proceed to the next validation stage.'
}

Short-circuiting is not only a performance detail. It lets you guard an operation that would be invalid when an earlier requirement is missing. Parentheses are useful when several operators appear together because they make the intended grouping obvious to reviewers.

5. Put $null on the left when testing scalar absence

PowerShell comparison operators can behave differently when the left operand is a collection. Writing $null -eq $value makes the intent clear: ask whether the value itself is null. This avoids collection filtering behavior from changing the meaning of the test.

$value = $null

if ($null -eq $value) {
    'No value was supplied.'
}

$servers = @('api-01', $null, 'worker-01')
$null -eq $servers       # asks whether the collection variable itself is null
$servers -eq $null       # returns elements from the collection that compare equal to null

The second comparison can emit collection elements rather than one Boolean answer. That is a Chapter 04 collection-comparison rule surfacing inside control flow. Use explicit predicates such as $null -eq $servers, $servers.Count -eq 0, or a filtered count depending on what you really mean.

6. Guard clauses keep failure logic shallow and visible

A guard clause checks an invalid or exceptional condition early and exits the current unit of work. This avoids deeply nested “happy path” code. In a script or function, common exits are return for a normal early return and throw when the caller must treat the condition as failure.

function Test-DeploymentConfig {
    param([pscustomobject]$Config)

    if ($null -eq $Config) {
        throw 'Configuration object is required.'
    }

    if ([string]::IsNullOrWhiteSpace($Config.Environment)) {
        throw 'Environment is required.'
    }

    if ($Config.Port -lt 1 -or $Config.Port -gt 65535) {
        throw 'Port must be between 1 and 65535.'
    }

    $true
}

The valid path is now easy to read because each invalid condition is handled immediately. Chapter 10 will teach error handling in depth; here the focus is structural clarity.

7. Assignment inside a condition is valid syntax but often a logic bug

PowerShell assignment is an expression: it assigns a value and also produces that value. Therefore, accidentally typing = instead of -eq can both mutate state and influence the branch.

$enabled = $false

# Wrong for comparison: this assigns $true.
if ($enabled = $true) {
    'This branch runs because the assigned value is true.'
}

$enabled
This branch runs because the assigned value is true.
True

The safer form is explicit comparison when comparison is the intent: if ($enabled -eq $true). For an actual Boolean variable, if ($enabled) is also clear because the variable is already typed semantically as a Boolean.

8. Prefer explicit conditions when configuration values can have several meanings

Configuration often arrives as strings from environment variables, JSON, YAML, or command-line arguments. A non-empty string such as 'false' is truthy, so this is unsafe: if ($env:FEATURE_ENABLED) { ... }. Parse or validate the value first, then branch on the typed result.

$rawEnabled = 'false'
$enabled = [bool]::Parse($rawEnabled)

if ($enabled) {
    'Feature is enabled.'
}
else {
    'Feature is disabled.'
}

Lesson 02 of Chapter 04 introduced type conversion. Control flow is where those conversion choices become operationally important.

9. Lab: validate deployment configuration with explicit failure messages

The lab stays in memory. It validates a structured configuration object, accumulates human-readable errors, and only reports success when every requirement passes.

$config = [pscustomobject]@{
    Environment = 'staging'
    Port = 8443
    Replicas = 2
    Enabled = $true
    Targets = @('api-01', 'worker-01')
}

$errors = [System.Collections.Generic.List[string]]::new()

if ($config.Environment -notin @('dev', 'staging', 'production')) {
    $errors.Add("Unsupported environment: $($config.Environment)")
}

if ($config.Port -lt 1 -or $config.Port -gt 65535) {
    $errors.Add("Port $($config.Port) is outside 1..65535")
}

if ($config.Replicas -lt 1) {
    $errors.Add('Replicas must be at least 1.')
}

if ($null -eq $config.Targets -or @($config.Targets).Count -eq 0) {
    $errors.Add('At least one deployment target is required.')
}

if ($errors.Count -gt 0) {
    'Configuration is invalid:'
    $errors | ForEach-Object { " - $_" }
}
else {
    'Configuration is valid.'
}

Change one field at a time—try an empty target list, port 0, or an unsupported environment—and observe which explicit rule fails. The code does not depend on accidental truthiness for business-critical values.

Verification checklist

10. Common mistakes and the evaluation behind them

if ('False'). This runs because a non-empty string is truthy. Parse text into a Boolean when the text represents Boolean configuration.

if (0). This does not run. If zero is a valid business value, compare the value to the relevant threshold instead of treating zero as “missing”.

if (@(0,0)). This runs because a collection with more than one element is always truthy under PowerShell Boolean conversion rules.

if ($servers -eq $null). With collections, comparison can return matching elements. Ask the exact question you mean: whether the variable is null, whether the collection is empty, or whether it contains null entries.

11. Knowledge check

Question 1. Why is if ('False') true?

Question 2. How does a two-element collection such as @(0,0) evaluate?

Question 3. Why use $null -eq $value instead of $value -eq $null?

Question 4. What is the purpose of a guard clause?

Question 5. Why can if ($enabled = $true) be dangerous?

12. Summary

PowerShell conditions are driven by Boolean evaluation, and Boolean conversion has important rules for nulls, numbers, strings, and collections. Use explicit comparisons for business meaning, group compound conditions clearly, exploit short-circuiting deliberately, and prefer guard clauses over deep nesting. Treat configuration text as text until it has been validated and converted, and never rely on accidental truthiness when a deployment decision matters.

13. Further reading

Next lesson

Use switch when one or many input values should be classified against matching rules

Lesson 02 expands control flow from Boolean branches to PowerShell’s multi-match switch statement, including wildcard, regex, file, break, and continue behavior.

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.