Index


Introduction

I can’t count the times when i needed to test which method i should use to abort my code, loop or function. When I asked other people they also didn’t know it most of the time. That’s when I decided to write a nice explanation for myself to reference to and also for my co-workers (and all others who will benefit). I really hope it helps you too.

⚠️ Warning! In the following code we use a foreach statement. When using a Foreach-Object, discussed at the end, the methods will change their behaviour. This also extents to the foreach() method of a Array.

Code

We’ll use a tiny script to demonstrate how each of the methods work.

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    Foreach ($Item in $Fruit) {
        if ($Item -eq "Carrot") {
            ## Insert Method
        }

        Write-Host "$Item is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

We start each test with writing some output, then we itterate through some items to check if the’re fruits. If the item is a fruit we write it to the screen. After we exit the Foreach-loop, we mention it on the screen. And finally at the end of the script we write once again to the screen that we are finished.

Each test we edit the function with the method we want to test. We only change the method.

Break

With break we exit the current loop and continue the rest of the code as it would have runned normally.

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    Foreach ($Item in $Fruit) {
        if ($Item -eq "Carrot") {
            break
        }

        Write-Host "$Item is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

When we run this, the output will be

Let's Start!
Apple is a fruit
Pear is a fruit
Banana is a fruit
We're outside the Foreach-loop.
Finished | End of the script

What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot we exit the Foreach-loop and the rest of the code will run as it normally would have.

Continue

With continue we skip the current itteration, but we continue the loop.

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    Foreach ($Item in $Fruit) {
        if ($Item -eq "Carrot") {
            continue
        }

        Write-Host "$Item is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

When we run this, the output will be

Let's Start!
Apple is a fruit
Pear is a fruit
Banana is a fruit
Pineapple is a fruit
Grape is a fruit
Lemon is a fruit
We're outside the Foreach-loop.
Finished | End of the script

What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot it is skipped and we continue with Pineapple, Grape and Lemon. After this we arrive outside the Foreach-loop and the script runs all the remaining lines of code.

Return

With return we exit the function and continue the rest of the code as it would have runned normally.

With return we could also return a custom message or object. I will not be demonstration this, but instead of just using return we type something like return "Custom Message".

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    Foreach ($Item in $Fruit) {
        if ($Item -eq "Carrot") {
            return
        }

        Write-Host "$Item is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

When we run this, the output will be

Let's Start!
Apple is a fruit
Pear is a fruit
Banana is a fruit
Finished | End of the script

What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot we exit the Function. So the Write-Host "We're outside the Foreach-loop." line won’t run. Also Pineapple, Grape and Lemon will be skipped. The rest of the code will run as it normally would have.

Exit

The last method, exit, is maybe the easiest to understand.

Using it will abort the code at the caller scope, meaning that the script or function will stop instantaneously. If you use it in your console, the console will exit/close.

Most of the time when I use it functions as a big red panic button, killing the script and ensuring that it will not keep running with a possible risk of harming my enviroment.

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    Foreach ($Item in $Fruit) {
        if ($Item -eq "Carrot") {
            exit
        }

        Write-Host "$Item is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

When we run this, the output will be

Let's Start!
Apple is a fruit
Pear is a fruit
Banana is a fruit

What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot we exit the script and the rest of the code will not run as the script was killed instantaneously.

Using Foreach-Object

As mentioned in the introduction if we do the same code, but change the way we loop, the results will change. First we look at the changed code and then we take a look at the changed results.

Function Test-AbortMethods {
    $Fruit = @("Apple","Pear","Banana","Carrot","Pineapple","Grape","Lemon")

    $Fruit | ForEach-Object {
        if ($_ -eq "Carrot") {
            ## Insert Method
        }

        Write-Host "$_ is a fruit"
    }

    Write-Host "We're outside the Foreach-loop."
}

Write-Host "Let's Start!"
Test-AbortMethods
Write-Host "Finished | End of the script"

Break

Within a script the break will function like an exit. if used in the console it will function as a return without the option to add a custom message/object.

Continue

Within a script the continue will function like an exit. if used in the console it will function as a return without the option to add a custom message/object.

Return

Within a script or at the console the return will function like an continue.

Exit

No change.

Summary

In summary I advice to use the Foreach statement when you want to add an abortion method. This way is (by default) also more readable then the Foreach-Object.

  • Use break when you want to want to exit the loop, but still want to finish the rest of the script.
  • Use continue when you want to skip the itteration matching your statement.
  • Use return when you want to exit the function or scriptblock you’re currently in.
  • Use exit when you want to exit the script entirely.

2 responses to “Mastering Control Flow in PowerShell: Break, Return, Continue, and Exit”

  1. Ferry Bodijn Avatar
    Ferry Bodijn

    Return

    What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot we exit the Function. So the Write-Host “Finished | End of the script” line won’t run. The rest of the code will run as it normally would have.

    This line must be:

    What’s happening? The start output is shown, then we process Apple, Pear and Banana. When we hit Carrot we exit the Function. So the ‘Write-Host “We’re outside the Foreach-loop.”‘ line won’t run. The rest of the code will run as it normally would have.

    Nice article, thanks. 🙂

    1. Jos Fissering Avatar

      Thank you for noticing and reporting the error. I’ve adjusted it.

      Also thanks for liking the article. I hope that we can post more articles that you may find useful.

Leave a Reply

Your email address will not be published. Required fields are marked *