Chapter 06Lesson 02~120 minutes

switch: Values, Wildcards, Regex, Files, and Multiple Matches

Classify values, collections, and line-oriented input with PowerShell switch, choose exact/wildcard/regex matching intentionally, and control overlapping matches safely.

Learning objectives

  • Explain how PowerShell switch differs from a first-match-only C-style mental model.
  • Use exact/default, wildcard, regex, and case-sensitive matching according to the data contract.
  • Process collection input one element at a time and understand the current $_/$PSItem value.
  • Distinguish break from continue when switch processes multiple input items.
  • Use switch -File safely for line-oriented training data and regex captures only where justified.
  • Choose a lookup hashtable instead of switch when the requirement is simple key-to-value data mapping.

1. switch is a matcher over values, not only a prettier if chain

Use if when each branch is naturally a Boolean rule. Use switch when one or more input values should be compared against a set of cases. PowerShell goes beyond the C-style “pick exactly one case” mental model: one input can match multiple clauses unless you deliberately stop processing.

$state = 'warning'

switch ($state) {
    'ok'      { 'No action required.' }
    'warning' { 'Investigate soon.' }
    'error'   { 'Immediate attention required.' }
    default   { 'Unknown state.' }
}

Without mode switches, string matching is exact and case-insensitive. For ordinary case-value comparison, PowerShell converts values to strings before comparing them; use script-block conditions when the object type itself must drive the decision. The default clause runs only when no earlier case matches the current input value.

2. PowerShell tests every matching clause unless break or continue changes the flow

A single input can trigger multiple actions. This is useful when classifications overlap, but it surprises learners who assume the first match wins.

switch ('warning') {
    { $_ -is [string] } { "String input: $_" }
    'warning'           { "Severity match: $_" }
}
String input: warning
Severity match: warning

Both clauses match. If exactly one action should run, place break or continue intentionally after the selected action, depending on whether the switch is processing one value or a collection.

3. Exact, wildcard, regex, and case sensitivity are different matching contracts

ModeExampleMental model
Default / -Exact'error'Whole value must match; string comparison is case-insensitive unless requested otherwise.
-CaseSensitive'ERROR' does not equal 'error'Letter case becomes significant.
-Wildcard'error*'Shell-style patterns such as * and ?.
-Regex'^ERR\d+$'Regular-expression pattern matching; $Matches is available on a match.
$message = 'ERROR disk pressure'

switch -Wildcard ($message) {
    'ERROR*'   { 'Error-class message' }
    '*pressure*' { 'Capacity-related message' }
}

This produces two classifications because both wildcard patterns match. That is often exactly what log enrichment needs.

4. A collection input is processed one element at a time

When the switch input is a collection, PowerShell evaluates every element in order. Inside a matching action, $_ or $PSItem is the current input element.

$states = 'ok', 'warning', 'error', 'ok'

switch ($states) {
    'ok'      { "OK: $_" }
    'warning' { "WARN: $_" }
    'error'   { "ERROR: $_" }
}

This makes switch useful for classifying lists without writing a separate outer loop. Still, if the transformation is primarily a pipeline operation, ForEach-Object may be clearer; Lesson 03 compares those iteration styles.

5. In collection switches, break exits the whole switch; continue moves to the next input item

The difference matters most when input contains many values. break stops the entire switch immediately. continue stops testing additional clauses for the current item and advances to the next item.

$messages = @(
    'INFO starting service'
    'WARN disk at 80%'
    'ERROR disk at 95%'
    'INFO this line is never reached with break'
)

switch -Wildcard ($messages) {
    'ERROR*' {
        "Critical: $_"
        break
    }
    'WARN*' {
        "Warning: $_"
        continue
    }
    default {
        "Other: $_"
    }
}

The warning action uses continue so the next message is still processed. The error action uses break, so later input is not examined. Choose this intentionally; an accidental break can suppress evidence from later records.

6. Regex mode gives captures through $Matches

Regular expressions are powerful when input has a consistent textual structure. Keep the first regex small and anchored so learners can see what it means. Here a log line begins with a severity token followed by a colon and message text.

$line = 'WARN: cache usage 82%'

switch -Regex ($line) {
    '^(INFO|WARN|ERROR):\s+(?<Message>.+)$' {
        [pscustomobject]@{
            Severity = $Matches[1]
            Message  = $Matches['Message']
        }
        break
    }
    default {
        [pscustomobject]@{ Severity='UNKNOWN'; Message=$_ }
    }
}

The match populates $Matches. Index 1 contains the first capture group; the named group Message is available by name. Do not reach for regex when exact or wildcard matching expresses the rule more clearly.

7. switch -File can classify a text file one line at a time

The -File form reads one file line by line and applies the switch rules to each line. This is useful for line-oriented logs. Because it is a filename argument, wildcard characters in the path can have meaning; use a literal-safe path strategy when filenames can contain wildcard characters.

$path = Join-Path ([System.IO.Path]::GetTempPath()) 'ps-academy-switch.log'
@(
    'INFO startup complete'
    'WARN queue depth high'
    'ERROR dependency unavailable'
) | Set-Content -LiteralPath $path -Encoding utf8

try {
    switch -Wildcard -File $path {
        'ERROR*' { "ERROR => $_"; continue }
        'WARN*'  { "WARN  => $_"; continue }
        default  { "INFO  => $_" }
    }
}
finally {
    Remove-Item -LiteralPath $path -Force -ErrorAction SilentlyContinue
}

The temporary file makes the example reproducible without touching system logs. Chapter 07 will teach path and file handling in depth.

8. A lookup hashtable is better when the relationship is simple data

If every input key maps directly to one value and there is no branching logic, a hashtable is usually simpler than switch.

$portByService = @{
    api = 8443
    metrics = 9090
    cache = 6379
}

$portByService['metrics']

Use switch when matching modes, overlapping rules, conditional action blocks, or line-by-line classification are central. Use a hashtable when you mean “key X maps to value Y.”

9. Lab: classify operational log lines with layered rules

This lab demonstrates collection input, wildcard matching, regex extraction, multiple possible matches, and deliberate continue. It produces structured objects so later stages can filter or export them.

$lines = @(
    'INFO service=api status=ready'
    'WARN service=cache usage=82%'
    'ERROR service=db code=503 message=upstream unavailable'
    'DEBUG service=api detail=probe'
)

$classified = switch -Regex ($lines) {
    '^INFO\s+service=(?<Service>\S+)\s+status=(?<Status>\S+)$' {
        [pscustomobject]@{ Level='INFO'; Service=$Matches.Service; Detail=$Matches.Status }
        continue
    }
    '^WARN\s+service=(?<Service>\S+)\s+usage=(?<Usage>\d+)%$' {
        [pscustomobject]@{ Level='WARN'; Service=$Matches.Service; Detail="Usage $($Matches.Usage)%" }
        continue
    }
    '^ERROR\s+service=(?<Service>\S+)\s+code=(?<Code>\d+)\s+message=(?<Message>.+)$' {
        [pscustomobject]@{ Level='ERROR'; Service=$Matches.Service; Detail="$($Matches.Code): $($Matches.Message)" }
        continue
    }
    default {
        [pscustomobject]@{ Level='OTHER'; Service=$null; Detail=$_ }
    }
}

$classified | Format-Table Level, Service, Detail -AutoSize

Each matching branch emits one object and then uses continue so the same line is not tested against later clauses. The output remains reusable objects; formatting occurs only at the end for human display.

Verification checklist

10. Common mistakes to avoid

Assuming first match wins. PowerShell can execute every matching clause unless you change control flow.

Using break when you meant “next item”. In a collection switch, break stops all remaining switch processing; continue advances to the next input value.

Using regex for simple exact keys. Exact or wildcard matching is easier to review when it expresses the rule fully.

Using switch as a static dictionary. If a hashtable can express the relationship as data, prefer the simpler data structure.

11. Knowledge check

Question 1. Does PowerShell switch stop after the first matching clause by default?

Question 2. What does continue do inside a switch that is processing a collection?

Question 3. What does break do there?

Question 4. When is -Wildcard preferable to -Regex?

Question 5. When is a hashtable better than switch?

12. Summary

PowerShell switch is a flexible matcher that can process scalars, collections, and files; use exact, wildcard, regex, or case-sensitive matching according to the rule. Multiple cases can match one value, so break and continue must be intentional. Prefer a lookup hashtable for simple data mapping, and keep classification output structured so later pipeline stages can reuse it.

13. Further reading

Next lesson

Compare language-loop iteration with pipeline iteration

Lesson 03 uses the same structured records to compare foreach with ForEach-Object and explains why pipeline control flow is not identical to language-loop control flow.

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.