The correct solution is to carefully read the warning in the Powershell documentation and realize that if there is an enclosing loop (or switch) then it will catch the break and exit cleanly, leaving any remaining portion of the pipeline functional. Some may argue that this is all just theoretical and that a clean exit or crashing the pipeline does not make any difference. This is only true in cases where the pipeline processes each object to completion before processing the next. For example,
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_ }
still produces the expected output (1, 5, 3, 8). Similarly,
1,5,3,8,9,3,5,7,2,5,7,6,9 |
ForEach-Object { Write-Host $_; if ($_ -eq 9) { break } $_ } |
Select-Object -First 2 -Wait
also works, producing (1, 5) as pipeline output interspersed in the Write-Host displayed (1, 5, 3, 8, 9). -Wait is included so that Select-Object does not prematurely stop the pipeline before the break occurs, thereby invalidating the example.
However, in cases where the output is collected before being used, crashing the pipeline produces unexpected results. Consider,
$output = 1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_ }
In this case the output must be collected into an array before being assigned to $output. When the pipeline crashes, this assignment is aborted and the collected output is simply displayed. Another example might be,
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_} | Sort-Object
Here, Sort-Object is collecting the output in order to sort it. When the pipeline crashes, it takes Sort-Object with it and the output is lost. Both of these situations can be avoided by using the enclosing loop method. Some other answers/comments used somewhat simplistic examples where the output was simply displayed, e.g.
$array = 'a'..'z'
do{
$array | ForEach-Object {
$_
if ($_ -eq 'c') {
break
}
}
} until ($true)
# (Sorry to pick on you again, Maybe)
While this example is correct, it is also another of the "doesn't make any difference if the pipeline crashes" examples. This is pretty much the case for any pipeline that is just placed within a loop in its entirety. If it works in the loop then it probably worked without it. For those pipelines that fail, more care is often required. For example,
do {
$output = 1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_ }
} while ($False)
still does not work. $output is not assigned and the output is just displayed as before. In this case, the correct solution is to place the assignment outside of the breaking loop:
$output = do {
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_ }
} while ($False)
leaving $output with (1, 5, 3, 8) as required. For other situations, it is even more complicated.
do {
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_} | Sort-Object
} while ($False)
still produces no output because the loop is terminated before Sort-Object has processed its input. Sort-Object must be placed outside the breaking loop like the assignment example. Unfortunately,
do {
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_}
} while ($False) | Sort-Object
does not work because a statement cannot be used as the input to a pipeline, only a command or expression. But
(
do {
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_}
} while ($False)
) | Sort-Object
also fails despite the fact that, syntactically, the input to the pipeline is now an expression because of the ( ). The reason is that the content of the ( ) is syntactically invalid (as an expression) and so is treated as a command and thus fails because there is no "do" command (probably wouldn't "do" what you want even if there were). (Preempting some comments: see Notes regarding use of $( )) The answer here (as before) is to invoke a scriptblock containing the breaking loop statement in order to provide the input to Sort-Object,
&{
do {
1,5,3,8,9,3,5,7,2,5,7,6,9 | ForEach-Object { if ($_ -eq 9) { break } $_ }
} while ($False)
} | Sort-Object
thus obtaining the desired output (1, 3, 5, 8).