Flow Control, Logic and Loops in PowerShell for Better Scripting

Posted by:

|

On:

|

Flow control is an important step in your PowerShell journey. When I was in school, there was an entire unit on conditional statements and a separate one on loops. It’s not really that bad, and easy enough to combine into one long post.

Conditional Statements

Conditional statements fire off if something is true or false. This is usually done through an expression but can be triggered with Booleans.

Logically, the easiest way to think about it is: “If this, then that.”

PowerShell
$myFruit = "apple"
if ($myFruit -eq "apple") { # Always indent the code to execute below
    Write-Output("My fruit is an apple.")
}

You can add an elseif if there is an additional action to be taken.

“If not this, but this, do this.”

PowerShell
$myFruit = "banana"
if ($myFruit -eq "apple") { # All false blocks skip
    Write-Output("My fruit is an apple.")
} 
elseif ($myFruit -eq "orange") {
    Write-Output("My fruit is an orange.")
}
elseif ($myFruit -eq "banana") {
    Write-Output("My fruit is a banana.")
}

Lastly, we can use else to handle anything not specified.

PowerShell
$myFruit = "gopher"
if ($myFruit -eq "apple") { 
    Write-Output("My fruit is an apple.")
} 
elseif ($myFruit -eq "orange") { 
    Write-Output("My fruit is an orange.")
}
elseif ($myFruit -eq "banana") {
    Write-Output("My fruit is a banana.")
}
else {
    Write-Output("Is that really a fruit?")
}

It’s also possible to “nest” these statements, so as long as they’re in the correct brackets you can get as specific as you’d like.

PowerShell
$myFruit = "crabapple"
if ($myFruit -like "*apple") { 
    Write-Output("My fruit is an apple.")
    if ($myFruit -like "*granny*") {
        Write-Output("My fruit is a Granny Smith Apple.")
    }
    elseif ($myFruit -like "*crab*") {
        Write-Output("My fruit is a crabapple.")
    }
}

You can also use the switch function to do similar.

PowerShell
switch ($myFruit) {
    "apple" {
        Write-Output"My fruit is an apple.")
    }
    "banana" {
        Write-Output("My fruit is a banana.")
    }
    "orange" {
        Write-Output("My fruit is an orange.")
    }
    default {
        Write-Output("Is that really a fruit?")
    }
}

Loops

Loops are where the real time-savings come in. With them you can run code as many times as needed which makes things like bulk changes a breeze.

ForEach – Run code for every object in a group.

PowerShell
$cities = @("New York", "Palo Alto", "Austin")
ForEach ($city in $cities) {
    Write-Output("My home is the city of $city.")
}

We can alternatively pipe an array to ForEach to do this, where $_ is the variable.

PowerShell
@("New York", "Palo Alto", "Austin") | ForEach {
    Write-Output("My home is the city of $_.")
}

ForEach can also be run with ranges.

PowerShell
($i in 1..3) | ForEach { 
    Write-Output("Number: $i") 
}

Do Until – Run code until a condition is true.

PowerShell
$number = Get-Random -Minimum 1 -Maximum 10
Do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    }
    elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
Until ($guess -eq $number)
Write-Output("Correct!")

Do While – Run code until a condition is false.

PowerShell
$number = Get-Random -Minimum 1 -Maximum 10
Do {
    $guess = Read-Host -Prompt "What's your guess?"
    if ($guess -lt $number) {
        Write-Output 'Too low!'
    }
    elseif ($guess -gt $number) {
        Write-Output 'Too high!'
    }
}
While ($guess -ne $number)
Write-Output("Correct!")

For – Run code a given number of times.

This is similar to ForEach and While. When using For you must specify a condition, as well as variable initialization, and iteration instructions.

The below code will initialize $i as 1, and continue to run as long as $i is less than or equal to 5, and increment $i by one each completed run.

PowerShell
#   (initialization; condition; iteration)
for ($i = 1; $i -le 5; $i++) { 
   Write-Output("Number: $i")
}

Control Flow Statements

Control Flow statements alter the way a flow works.

Break – Exits the loop or switch, continuing to the next block.

PowerShell
ForEach ($i in 1..10) {
    if ($i -eq 5) {
        Write-Output("Reached the break statement.")
        break
    }
    Write-Output("Number: $i")
}
Write-Output("Loop ended.")

Return – Exits the function and returns a value. This is generally used with functions, which we’ll cover next, so it’s okay not to understand. This can be used to move variables between scopes.

PowerShell
function Divide-Numbers($a, $b) {
     if ($b -eq 0) {
         return "Error: Division by zero is not allowed."
     }
     return $a / $b
}
PowerShell
$result = Divide-Numbers 5 3
Write-Output("Product: $result")

Continue – Skip to the next iteration of a loop.

PowerShell
ForEach ($i in 1..5) {
    if ($i -eq 3) {
        Write-Output("Skipping $i.")
        continue
    }
    Write-Output("Number: $i")
}

That is the gist of flow control. You can do more complex things by nesting and adding variables. If you want a fun exercise to do, plot out a Choose-Your-Own-Adventure game. The way I’d do that is plotting it out with a spreadsheet or bullet list.

[0] You wake up in a dark room. On one side a shadow waves against the wall, on the other there's a glimpse of light.
  • Go toward light [1]
  • Go toward shadow [2]
[2] You go toward the light and see goblins smoking meat on an immaculately clean smart pellet grill!

Take the food and run [1]
Swear Allegiance to Warchief Regeat [2]

Let me know if you make a CYOA you want to share!