Why does 'continue' behave like 'break' in a Foreach-Object?

Justin Dearing picture Justin Dearing · Oct 13, 2011 · Viewed 71.5k times · Source

If I do the following in a PowerShell script:

$range = 1..100
ForEach ($_ in $range) {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

I get the expected output of:

7 is a multiple of 7
14 is a multiple of 7
21 is a multiple of 7
28 is a multiple of 7
35 is a multiple of 7
42 is a multiple of 7
49 is a multiple of 7
56 is a multiple of 7
63 is a multiple of 7
70 is a multiple of 7
77 is a multiple of 7
84 is a multiple of 7
91 is a multiple of 7
98 is a multiple of 7

However, if I use a pipeline and ForEach-Object, continue seems to break out of the pipeline loop.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { continue; }
    Write-Host "$($_) is a multiple of 7"
}

Can I get a continue-like behavior while still doing ForEach-Object, so I don't have to breakup my pipeline?

Answer

Roman Kuzmin picture Roman Kuzmin · Oct 14, 2011

Simply use the return instead of the continue. This return returns from the script block which is invoked by ForEach-Object on a particular iteration, thus, it simulates the continue in a loop.

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}

There is a gotcha to be kept in mind when refactoring. Sometimes one wants to convert a foreach statement block into a pipeline with a ForEach-Object cmdlet (it even has the alias foreach that helps to make this conversion easy and make mistakes easy, too). All continues should be replaced with return.

P.S.: Unfortunately, it is not that easy to simulate break in ForEach-Object.