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

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.


Because For-Each object is a cmdlet and not a loop and continue and break do not apply to it.

For example, if you have:

$b = 1,2,3

foreach($a in $b) {

    $a | foreach { if ($_ -eq 2) {continue;} else {Write-Host $_} }

    Write-Host  "after"
}

You will get output as:

1
after
3
after

It is because the continue gets applied to the outer foreach loop and not the foreach-object cmdlet. In absence of a loop, the outermost level, hence giving you an impression of it acting like break.

So how do you get a continue-like behaviour? One way is Where-Object of course:

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}