powershellbreakcontrol-flowcontinue

Why does a continue in this ForEach-Object loop cause Powershell to error


When piping the output of a command to a ForEach-Object loop in PowerShell, using a continue statement causes it to error out.

Works as expected:

ipconfig | ForEach-Object {
  $_
} 

Errors:

ipconfig | ForEach-Object {
  $_
  continue
} 

The error is

Program 'ipconfig.exe' failed to run: System error.At C:\Users\test\ps.ps1:1 char:1
+ nslookup google.com | ForEach-Object {
+ ~~~~~~~~~~~~~~~~~~~.
At C:\Users\test\ps.ps1:1 char:1
+ nslookup google.com | ForEach-Object {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [], ApplicationFailedException
    + FullyQualifiedErrorId : NativeCommandFailed

This seems to happen with any external command, such as nslookup and net

I thought maybe this had to do with some type conversion, but the object inside the loop is always a string. Saving the command output to a variable, and then doing a $var | ForEach-Object works.


Solution

  • continue statements in PowerShell can only be used within loop constructs. While ForEach-Object seems like a loop, it's not.

    In PowerShell, you can technically use continue outside of a loop, but it causes PowerShell to not find a loop, and just terminate the current runspace.1

    This means PowerShell can actually terminate the caller1, and looking at the callstack, that caller is the "parent" line and so it is terminated.

    Callstack right before the continue executes:

    ScriptLineNumber : 4
    Position         : continue
    FunctionName     : <ScriptBlock>
    
    
    ScriptLineNumber : 1
    Position         : net help | ForEach-Object {
                           $_.GetType()
                           continue
                       }
    FunctionName     : <ScriptBlock>
    

    Instead, use a return statement.


    Reference

    1 - https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_continue?view=powershell-5.1