PowerShell's if...elseif...else statements are pretty standard, taking the form:

if ( <condition> ) { # # Do something. # } elseif ( <alternative condition> ) { # # Do something else. # } else { # # If no conditions met... # } #else-if

The conditions used within if...elseif...else statements can be any combination of and operators, with parenthesis used to control operator precedence.   Good programming practice dictates that if...elseif...else shouldn't exceed a handful of conditions.  If you find yourself writing a long if...elseif...else statement, consider using a statement.

PowerShell's switch statement (sometimes referred to as a case statement) operates in multiple ways, the first of which will be familiar to anyone who has used C, or one of its syntactical derivatives.  All of the variants will be described below.

In its simplest form, PowerShell's switch statement looks very familiar:

switch -exact ( <expression> ) { <case 1> { # Do something. break; } <case 2> { # Do something else. break; } default { # No match? } } #switch

This is the default mode of operation, whereby a case will only be executed if it matches a given value or the result of a given expression.   Textual comparisons are case-insensitive, unless the -casesensitive directive is specified.  Being the default mode of operation, the switch statement will operate in this manner, even if the -exact directive isn't explicitly specified.  The use of the break statement in any given case is optional, and simply halts evaluation flow, therefore preventing any of the subsequent cases being evaluated.

The following example demonstrates a very simple switch statement with no cascading evaluations:

[Int32] $intSelection = Read-Host -Prompt 'Enter a number between 1 and 5'; switch -exact ( $intSelection ) { 1 { 'You entered one.'; break; } 2 { 'You entered two.'; break; } 3 { 'You entered three.'; break; } 4 { 'You entered four.'; break; } 5 { 'You entered five.'; break; } default { 'Invalid input.'; break; } } #switch

However, by removing the break statements, we can cause multiple cases to be evaluated.  This is particularly useful when using expressions instead of constants for one or more of the cases, for example:

[Int32] $intSelection = Read-Host -Prompt 'Enter a number between 1 and 5'; switch -exact ( $intSelection ) { 1 { 'You entered one.'; } 2 { 'You entered two.'; } 3 { 'You entered three.'; } 4 { 'You entered four.'; } 5 { 'You entered five.'; } { $_ -lt 3 } { 'Your number is less than 3.' }; { $_ -gt 3 } { 'Your number is greater than 3.' }; { $_ % 2 } { 'Your number is odd.'; } {! ($_ % 2) } { 'Your number is even.'; } default { 'Invalid input.'; } } #switch

The -wildcard option allows you to use simple pattern matches to evaluate cases.  The pattern match syntax is the same as that of the operator, that is, ?, *, [a-e] (range) and [aeiou] (set).

[String] $strWord = Read-Host -Prompt 'Enter a word'; switch -wildcard ( $strWord ) { 'a*' { 'Begins with A.'; } 'b*' { 'Begins with B.'; } 'c*' { 'Begins with C.'; } '?c*' { 'Second letter is C.'; } '[h-m]*' { 'First letter is between H and M.'; } '[aeiou]*' { 'First letter is a vowel.'; } '*s' { 'Last letter is S.'; } default { 'Other.' } } #switch

The -regex option is similar to the -wildcard option, except that it uses pattern matching.

[String] $strRegNum = Read-Host -Prompt 'Enter a UK car registration number'; switch -regex ( $strRegNum ) { '^[a-z]{1,2}\s?\d{1,4}$' { 'Pre-1932.'; break; } '^[a-z]{3} \d{1,2}$' { '1932-1963'; break; } '^[a-z]{3} \d{1,3}[a-z]$' { '1960-1982'; break; } '^[a-z]\d{2,3} [a-z]{3}$' { '1983-2001'; break; } '^[a-z]{2}\d{2} [a-z]{3}$' { '2002+'; break; } default { 'Unrecognised registration format.' } } #switch

The -file option causes the switch statement to evaluate each line of the given file against its defined cases.  This mode of operation, when combined with the -regex is useful for parsing configuration files, for example:

[String] $strInDir = ''; [String] $strOutDir = ''; [Int32] $intSleepPeriod = -1; [Boolean] $boolAlertOnFailure = $false; [Boolean] $boolConfigError = $false; [String] $strConfigFile = 'c:\params.cfg'; switch -regex -file ($strConfigFile) { '^in_dir=([c-z]:\\(?:\w+\\){0,}\w+\\?)$' { $strInDir = $matches[1]; continue; } '^out_dir=([c-z]:\\(?:\w+\\){0,}\w+\\?)$' { $strOutDir = $matches[1]; continue; } '^sleep_period=(\d{1,3})$' { $intSleepPeriod = [Convert]::ToInt32($matches[1]); continue; } '^alert_on_failure=(yes|no)$' { $boolAlertOnFailure = ($matches[1] -eq 'yes'); continue; } default { Write-Warning -Message ('Invalid or unrecognised configuration parameter : "{0}". Aborting.' -f $_ ); $boolConfigError = $true; break; } } #switch if ( ! $boolConfigError ) { Write-Host -Object ( 'In directory is : {0}' -f $strInDir ); Write-Host -Object ( 'Out directory is : {0}' -f $strOutDir ); Write-Host -Object ( 'Sleep period is : {0}' -f $intSleepPeriod ); Write-Host -Object ( 'Alert on failure : {0}' -f $boolAlertOnFailure ); } #if

However, there is one subtlety with this mode of operation; this being the way that the break statement affects execution.   Using a break statement in any of the cases will cause the switch statement to cease processing any further cases AND any further lines of the supplied file.  If you wish to cease processing any further cases for the current line of the file, but then continue with the next line of the file, you must use the continue statement (see example, above).

When presented with a compound data type, such as an array, the -switch statement will iterate through each element of the given data, evaluating each value against its defined cases.

[System.ComponentModel.Component[]] $objProcesses = Get-Process | Sort-Object -Property WorkingSet -Descending; switch ( $objProcesses ) { { $_.WorkingSet -gt 250MB } { 'The working set of process "{0}" is greater than 250MB.' -f $_.ProcessName; continue; } { $_.WorkingSet -gt 100MB } { 'The working set of process "{0}" is greater than 100MB.' -f $_.ProcessName; continue; } { $_.WorkingSet -gt 10MB } { 'The working set of process "{0}" is greater than 10MB.' -f $_.ProcessName; continue; } { $_.WorkingSet -gt 5MB } { 'The working set of process "{0}" is greater than 5MB.' -f $_.ProcessName; continue; } default { 'The working set of process "{0}" is {1:N0} KBytes.' -f $_.ProcessName, ($_.WorkingSet / 1KB); } } #switch

Note that the continue and break commands have the same effect here as they do with the -file option.

A ternary operator provides a convenient way of returning one of two values, based on a given condition, and is often used in place of an if...else, in order to aid readabilty of code.  The most common syntax of a ternary operator is that of the C programming language, i.e.:

( <condition> ? <expression_if_true> : <expression_if_false> )

Sadly, PowerShell doesn't have a ternary operator.  This is a great shame.  However, there is a simple trick that will provide a similar outcome, this being:

@( <expression_if_false>, <expression_if_true> )[ <condition> ]

This trick (or hack?) utilises a two element array with a condition being used as an array index.  The condition can evaluate to $false (0) or $true (1), therefore returning the relevant array value.