Search code examples
powershellerror-handlingexit-codecopy-item

Powershell Copy-Item Exit code 1


I have a script with several files I'd like to copy and I do it more or less like so.

Copy-Item xxx1 yyy1 -Force
Copy-Item xxx2 yyy2 -Force
Copy-Item xxx3 yyy3 -Force
Copy-Item xxx4 yyy4 -Force

and so on.

Now I'd like this script to exit with 1 if any of the files was not copied.

Thanks in advance


Solution

  • What you're asking for is similar to the set -e option in bash, which causes a script to exit instantly in the event that a command signals failure (except in conditionals)[1].

    PowerShell has no such option[2], but you can emulate it:

    # Set up a trap (handler for when terminating errors occur).
    Trap { 
        # Print the error. 
        # IMPORTANT: -ErrorAction Continue must be used, because Write-Error
        #            itself would otherwise cause a terminating error too.
        Write-Error $_ -ErrorAction Continue
        exit 1 
    }
    
    # Make non-terminating errors terminating.
    $ErrorActionPreference = 'Stop'
    
    # Based on $ErrorActionPreference = 'Stop', any error reported by
    # Copy-Item will now cause a terminating error that triggers the Trap
    # handler.
    Copy-Item xxx1 yyy1 -Force
    Copy-Item xxx2 yyy2 -Force
    Copy-Item xxx3 yyy3 -Force
    Copy-Item xxx4 yyy4 -Force
    
    # Failure of an EXTERNAL PROGRAM must be handled EXPLICITLY,
    # because `$ErrorActionPreference = 'Stop'` does NOT apply.
    foo.exe -bar
    if ($LASTEXITCODE -ne 0) { Throw "foo failed." } # Trigger the trap.
    
    # Signal success.
    exit 0
    

    Note:

    • PowerShell-internally, exit codes are not used in error handling; they typically only come into play when invoking external programs from PowerShell, or when PowerShell / a PowerShell script needs to signal success vs. failure for the outside world (when called from another shell, such as cmd on Windows, or bash on Unix-like platforms).

    • PowerShell's automatic $LASTEXITCODE variable reflects the exit code of the most recently executed external program / PowerShell script that called exit <n>.

    • Calls to external (console/terminal) programs that signal failure via a nonzero exit code do not trigger the trap block, hence the explicit throw statement in the snippet above.

    • Unless you set the exit code explicitly, it is the exit code of whatever external program happened to execute last that determines the script's overall exit code.

    [1] Note that this option has its critics, because the exact rules around when a failure is tolerated and when it causes a script to abort are hard to remember - see http://mywiki.wooledge.org/BashFAQ/105

    [2] Potentially adding support for it is being discussed in this RFC proposal.