Break not working in ForEach

Kirk has a great summary of a difference between ForEach the PowerShell keyword and ForEach the alias for ForEach-Object cmdlet. Just a few days ago while working on the automated software testing pack I found myself confusing these two and having to debug the code which at first site looked perfectly legit:

# Locate the results entry for the currently selected test
$i = 0
$bNew = $true
$PreviousResults | ForEach {
    if ( $_.Name -eq $currentTest.Name ) {
        $bNew = $false
        break
    }
    $i++
}

Basically, I had to find a record for the test selected to run (records stored in the $PreviousResults array) and have the $i hold the index of the record so I can update it with the record with test results. The code seemed obviou: just go through the records (ForEach), break if the test is found (the name comparison), and increment the counter if not ($i++).

The problem is that this is not a cycle – because ForEach here is actually a ForEach-Object cmdlet that simply calls the block after itself for the items it gets from the pipeline stream. There’s no cycle – so there’s nothing to break (so in my case break was breaking the whole function).

If you need to use break – use ForEach the cycle keyword or just For, like in this code which I used instead:

# Locate the results entry for the currently selected test
$i = 0
$bNew = $true
for ( $i=0; $i -le ($PreviousResults.length - 1); $i++)  {
    if ( $PreviousResults[$i].Name -eq $currentTest.Name ) {
        $bNew = $false
        break
    }
}

Read Kirk’s post for other differences to keep in mind and try using full name for ForEach-Object to make your code more readable.

Dmitry

Tags:

9 Responses to “Break not working in ForEach”


  1. 1 Argenis Fernandez June 9, 2009 at 7:23 pm

    Thanks for the post. Nice to know.

  2. 2 Powershell Newbie August 27, 2009 at 6:31 am

    “break” used in the following recursive function only breaks out of the current iteration of the recursion instead of the complete recursion. I already tried to use “return” but it did not help. Any idea how I can break out of the recursive function?

    function find-file( $startfolder, $nameoffile )
    {
    foreach ( $_ in get-childitem $startfolder ) {
    if( $_ -match $nameoffile )
    {
    Write-Host “Found the file, assigning the file path to a variable…”
    $FilePath = $_.FullName
    break
    } else {
    if( $_.PsIsContainer )
    {
    find-file $_.FullName $nameoffile
    }
    }
    }
    }

  3. 3 Dmitry Sotnikov August 27, 2009 at 7:48 am

    You are right – break only breaks the current scope and return only returns from the current function (again, not the full recursion).

    You can use “throw” to generate an exception and this will get you from the whole thing. The tricky part is that this will by default terminate the whole script – not just the function. This might or might not be what you need.

    If this is not what you need, and you do need to proceed from some place – you need to catch the exception there.

    Unfortunately, catching that exception so the script does not terminate at all is not that easy in PowerShell v1. In v2, it is as easy as enclosing the original function call in try/catch.

    If you need more information, I would as in the forums at http://powergui.org

    • 4 Powershell Newbie August 28, 2009 at 5:55 pm

      It is a bit frustrating that this has been my workaround for the other issue I ran into and has to be again worked around.

      Thanks for your information. I will take a look at the links.

      Newbie

  4. 5 karl prosser September 22, 2009 at 9:00 pm

    Break in powershell is dangerous as it just throws an exception, and if in a scriptblock, it will just bubble up to the nearest thing in the pipeline, a cmdlet or whatnot and the result will be unpredicatable or at least inconsistant.

  5. 6 Dmitry Sotnikov September 23, 2009 at 8:44 am

    Good point Karl! Break can be very confusing indeed.

    • 7 karl prosser September 23, 2009 at 3:13 pm

      I personally think Break has a wrong design, and is a liability to solid code and should really just be avoided in PowerShell. Even the scenarios where its perfectly safe is not worth it IMO


  1. 1 Essential PowerShell: Understanding foreach (Addendum) « Poshoholic Trackback on September 1, 2007 at 12:00 am
  2. 2 Episode 85 – Lee Holmes talks about v2 « PowerScripting Podcast Trackback on September 28, 2009 at 4:24 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




My Recent Tweets

Legal

The posts on this blog are provided “as is” with no warranties and confer no rights. The opinions expressed on this site are mine and mine alone, and do not necessarily represent those of my employer - WSO2 or anyone else for that matter. All trademarks acknowledged.

© 2007-2014 Dmitry Sotnikov

August 2007
M T W T F S S
« Jul   Sep »
 12345
6789101112
13141516171819
20212223242526
2728293031  

%d bloggers like this: