Skip to content

Switch Statements

Note

Learn how to efficiently handle multiple conditions using switch statements instead of long if/elseif chains.

Overview

A switch statement lets you check one value against multiple possible matches. Instead of writing many if/elseif statements, you use switch to make your code cleaner and easier to read. Think of it like a multiple-choice question where you execute different code based on which answer matches.

Basic Syntax

switch (value-to-test) {
    "match1" { # Code if value equals "match1" }
    "match2" { # Code if value equals "match2" }
    "match3" { # Code if value equals "match3" }
    default  { # Code if no matches found }
}

Key Points

  • Tests one value against multiple possible matches
  • Cleaner than long if/elseif chains
  • Supports wildcards, regex, and conditions
  • Can match multiple cases (doesn't auto-break like other languages)
  • Case-insensitive by default (use -casesensitive for exact matching)

Simple Switch Statements

Basic Value Matching

$dayOfWeek = (Get-Date).DayOfWeek

switch ($dayOfWeek) {
    "Monday"    { Write-Output "Start of the work week" }
    "Tuesday"   { Write-Output "Second day" }
    "Wednesday" { Write-Output "Midweek" }
    "Thursday"  { Write-Output "Almost Friday" }
    "Friday"    { Write-Output "TGIF!" }
    "Saturday"  { Write-Output "Weekend!" }
    "Sunday"    { Write-Output "Weekend!" }
}

Using Default

$status = "Unknown"

switch ($status) {
    "Active"   { Write-Output "User is active" }
    "Inactive" { Write-Output "User is inactive" }
    "Pending"  { Write-Output "User is pending approval" }
    default    { Write-Output "Status not recognized: $status" }
}

Output:

Status not recognized: Unknown

Common Use Cases

Use Case 1: Menu Systems

What it does: Create interactive menus

Write-Output "`n===== Main Menu ====="
Write-Output "1. View Files"
Write-Output "2. Create File"
Write-Output "3. Delete File"
Write-Output "4. Exit"

$choice = Read-Host "`nEnter your choice"

switch ($choice) {
    "1" {
        Write-Output "Viewing files..."
        Get-ChildItem
    }
    "2" {
        $filename = Read-Host "Enter filename"
        New-Item -Path $filename -ItemType File
        Write-Output "File created: $filename"
    }
    "3" {
        $filename = Read-Host "Enter filename to delete"
        Remove-Item -Path $filename
        Write-Output "File deleted: $filename"
    }
    "4" {
        Write-Output "Exiting..."
        exit
    }
    default {
        Write-Output "Invalid choice. Please try again."
    }
}

Use Case 2: File Extension Handling

What it does: Process files differently based on extension

$file = Get-Item "C:\Temp\document.pdf"

switch ($file.Extension) {
    ".txt" {
        Write-Output "Text file - displaying first 10 lines..."
        Get-Content -Path $file.FullName -TotalCount 10
    }
    ".csv" {
        Write-Output "CSV file - importing data..."
        $data = Import-Csv -Path $file.FullName
        Write-Output "Rows: $($data.Count)"
    }
    {$_ -in @(".jpg", ".png", ".gif")} {
        Write-Output "Image file - opening in viewer..."
        Invoke-Item -Path $file.FullName
    }
    ".pdf" {
        Write-Output "PDF file"
        Write-Output "Size: $([math]::Round($file.Length/1MB, 2)) MB"
    }
    default {
        Write-Output "Unknown file type: $($file.Extension)"
    }
}

Use Case 3: Error Code Handling

What it does: Take different actions based on error codes

$exitCode = 1

switch ($exitCode) {
    0 {
        Write-Output "Success"
        # Continue processing
    }
    1 {
        Write-Warning "General error occurred"
        # Log and retry
    }
    2 {
        Write-Error "File not found"
        # Create file and retry
    }
    {$_ -in 3..10} {
        Write-Warning "Configuration error (code: $_)"
        # Reset config
    }
    default {
        Write-Error "Unknown error code: $exitCode"
        # Alert admin
    }
}

Advanced Switch Features

Wildcard Matching

$filename = "report_2025_november.txt"

switch -Wildcard ($filename) {
    "*.txt" {
        Write-Output "Text file"
    }
    "report_*" {
        Write-Output "This is a report file"
    }
    "*2025*" {
        Write-Output "File from 2025"
    }
}

Output:

Text file
This is a report file
File from 2025

Note: Unlike most languages, PowerShell switch doesn't automatically "break" - it checks ALL cases that match!

Regex Matching

$input = "Server01"

switch -Regex ($input) {
    "^Server\d+$" {
        Write-Output "Valid server name format"
    }
    "^\d+$" {
        Write-Output "Numeric value"
    }
    "^[A-Z]" {
        Write-Output "Starts with uppercase letter"
    }
}

Output:

Valid server name format
Starts with uppercase letter

Case-Sensitive Matching

$value = "PowerShell"

# Default: case-insensitive
switch ($value) {
    "powershell" { Write-Output "Matched (case-insensitive)" }
}
# Output: Matched (case-insensitive)

# Case-sensitive
switch -CaseSensitive ($value) {
    "powershell" { Write-Output "Matched" }
    "PowerShell" { Write-Output "Exact match!" }
}
# Output: Exact match!

Condition-Based Matching

$number = 42

switch ($number) {
    {$_ -lt 0}    { Write-Output "Negative number" }
    {$_ -eq 0}    { Write-Output "Zero" }
    {$_ -le 10}   { Write-Output "Between 1 and 10" }
    {$_ -le 50}   { Write-Output "Between 11 and 50" }
    {$_ -le 100}  { Write-Output "Between 51 and 100" }
    {$_ % 2 -eq 0} { Write-Output "Even number" }
    default       { Write-Output "Greater than 100" }
}

Output:

Between 11 and 50
Even number

Processing Arrays with Switch

$services = "Spooler", "W32Time", "WinRM", "UnknownService"

switch ($services) {
    "Spooler" {
        Write-Output "Print Spooler service"
    }
    "W32Time" {
        Write-Output "Windows Time service"
    }
    "WinRM" {
        Write-Output "Windows Remote Management"
    }
    default {
        Write-Output "Unknown service: $_"
    }
}

Output:

Print Spooler service
Windows Time service
Windows Remote Management
Unknown service: UnknownService

Controlling Switch Flow

Break (Stop Processing)

$value = "test"

switch -Wildcard ($value) {
    "t*" {
        Write-Output "Starts with 't'"
        break  # Stop checking other cases
    }
    "*e*" {
        Write-Output "Contains 'e'"  # Won't run due to break
    }
    "test" {
        Write-Output "Exact match"    # Won't run due to break
    }
}

Output:

Starts with 't'

Continue (Skip to Next Item)

$numbers = 1, 2, 3, 4, 5

switch ($numbers) {
    {$_ % 2 -eq 0} {
        Write-Output "$_ is even"
        continue  # Skip to next number
    }
    {$_ -gt 3} {
        Write-Output "$_ is greater than 3"
    }
    default {
        Write-Output "Processing $_"
    }
}

Real-World Examples

Example: Service Status Reporter

Scenario: Generate different reports based on service status

function Get-ServiceReport {
    param([string]$ServiceName)

    $service = Get-Service -Name $ServiceName

    switch ($service.Status) {
        "Running" {
            [PSCustomObject]@{
                Service = $ServiceName
                Status = "Running"
                Action = "None required"
                Priority = "Low"
            }
        }
        "Stopped" {
            # Check if it should be running
            if ($service.StartType -eq "Automatic") {
                [PSCustomObject]@{
                    Service = $ServiceName
                    Status = "Stopped"
                    Action = "Start service immediately"
                    Priority = "High"
                }
            } else {
                [PSCustomObject]@{
                    Service = $ServiceName
                    Status = "Stopped"
                    Action = "Manual start only"
                    Priority = "Low"
                }
            }
        }
        {$_ -in "Paused", "StartPending", "StopPending"} {
            [PSCustomObject]@{
                Service = $ServiceName
                Status = $service.Status
                Action = "Monitor for state change"
                Priority = "Medium"
            }
        }
        default {
            [PSCustomObject]@{
                Service = $ServiceName
                Status = $service.Status
                Action = "Unknown status - investigate"
                Priority = "High"
            }
        }
    }
}

# Usage
Get-ServiceReport -ServiceName "Spooler"

Example: Log Level Handler

Scenario: Route log messages to different outputs based on severity

function Write-Log {
    param(
        [string]$Message,
        [ValidateSet("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")]
        [string]$Level = "INFO"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$timestamp] [$Level] $Message"

    switch ($Level) {
        "DEBUG" {
            Write-Verbose $logEntry
        }
        "INFO" {
            Write-Output $logEntry
            Add-Content -Path "C:\Logs\info.log" -Value $logEntry
        }
        "WARNING" {
            Write-Warning $Message
            Add-Content -Path "C:\Logs\warning.log" -Value $logEntry
        }
        {$_ -in "ERROR", "CRITICAL"} {
            Write-Error $Message
            Add-Content -Path "C:\Logs\error.log" -Value $logEntry

            if ($Level -eq "CRITICAL") {
                # Send email alert for critical errors
                Write-Output "ALERT: Critical error logged!"
            }
        }
    }
}

# Usage
Write-Log "Application started" -Level INFO
Write-Log "Low disk space" -Level WARNING
Write-Log "Database connection failed" -Level CRITICAL

Example: HTTP Status Code Handler

Scenario: Handle different HTTP response codes appropriately

function Handle-HttpResponse {
    param([int]$StatusCode)

    switch ($StatusCode) {
        {$_ -in 200..299} {
            Write-Output "Success (Code: $_)"
            return $true
        }
        {$_ -in 300..399} {
            Write-Warning "Redirect (Code: $_)"
            return $true
        }
        401 {
            Write-Error "Unauthorized - Check credentials"
            return $false
        }
        403 {
            Write-Error "Forbidden - Insufficient permissions"
            return $false
        }
        404 {
            Write-Error "Not Found - Check URL"
            return $false
        }
        {$_ -in 400..499} {
            Write-Error "Client Error (Code: $_)"
            return $false
        }
        {$_ -in 500..599} {
            Write-Error "Server Error (Code: $_)"
            return $false
        }
        default {
            Write-Warning "Unknown status code: $_"
            return $false
        }
    }
}

# Usage
$statusCode = 404
$success = Handle-HttpResponse -StatusCode $statusCode

Switch vs If/ElseIf

When to Use Switch

# Use switch when checking ONE value against MANY possibilities
switch ($fileExtension) {
    ".txt"  { "Text file" }
    ".csv"  { "CSV file" }
    ".json" { "JSON file" }
    ".xml"  { "XML file" }
    ".log"  { "Log file" }
    default { "Unknown" }
}

When to Use If/ElseIf

# Use if/elseif when checking DIFFERENT conditions
if ($fileSize -gt 100MB) {
    "Large file"
} elseif ($fileAge -gt 30) {
    "Old file"
} elseif ($fileName -like "*.tmp") {
    "Temporary file"
}

Tips & Tricks

Multiple Matches Execute by Default

# All matching cases run!
switch -Wildcard ("test.txt") {
    "*.txt"  { Write-Output "Text file" }
    "test*"  { Write-Output "Test file" }
    "*.*"    { Write-Output "Has extension" }
}
# Output: All three messages

# Use 'break' to stop after first match
switch -Wildcard ("test.txt") {
    "*.txt"  { Write-Output "Text file"; break }
    "test*"  { Write-Output "Test file" }
    "*.*"    { Write-Output "Has extension" }
}
# Output: Only "Text file"

Use Conditions for Range Checking

$age = 25

switch ($age) {
    {$_ -lt 13}  { "Child" }
    {$_ -lt 20}  { "Teenager" }
    {$_ -lt 65}  { "Adult" }
    default      { "Senior" }
}

Process Multiple Values at Once

# Switch can iterate through arrays automatically
$files = "report.txt", "data.csv", "config.json"

switch -Wildcard ($files) {
    "*.txt"  { Write-Output "$_ is a text file" }
    "*.csv"  { Write-Output "$_ is a CSV file" }
    "*.json" { Write-Output "$_ is a JSON file" }
}
# Processes each file in the array

Case Insensitive by Default

# These both match
switch ("PowerShell") {
    "powershell" { "Matched!" }  # Matches!
    "POWERSHELL" { "Also matches!" }  # Also matches!
}

# Use -CaseSensitive if you need exact matching
switch -CaseSensitive ("PowerShell") {
    "powershell" { "Won't match" }
    "PowerShell" { "Exact match!" }  # Only this matches
}

Default Runs When No Matches

$value = "unknown"

switch ($value) {
    "known1" { "Match 1" }
    "known2" { "Match 2" }
    default  { "No matches found" }  # This runs
}

# Default won't run if any case matches
switch -Wildcard ($value) {
    "*"     { "Wildcard match" }  # Matches everything
    default { "Won't run" }       # Never runs
}

Additional Resources