How to stop a PowerShell script on the first error?

后端 未结 8 1768
长情又很酷
长情又很酷 2020-12-02 06:11

I want my PowerShell script to stop when any of the commands I run fail (like set -e in bash). I\'m using both Powershell commands (New-Object System.Net.

相关标签:
8条回答
  • 2020-12-02 06:40

    You should be able to accomplish this by using the statement $ErrorActionPreference = "Stop" at the beginning of your scripts.

    The default setting of $ErrorActionPreference is Continue, which is why you are seeing your scripts keep going after errors occur.

    0 讨论(0)
  • 2020-12-02 06:40

    Redirecting stderr to stdout seems to also do the trick without any other commands/scriptblock wrappers although I can't find an explanation why it works that way..

    # test.ps1
    
    $ErrorActionPreference = "Stop"
    
    aws s3 ls s3://xxx
    echo "==> pass"
    
    aws s3 ls s3://xxx 2>&1
    echo "shouldn't be here"
    

    This will output the following as expected (the command aws s3 ... returns $LASTEXITCODE = 255)

    PS> .\test.ps1
    
    An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
    ==> pass
    
    0 讨论(0)
  • 2020-12-02 06:41

    You need slightly different error handling for powershell functions and for calling exe's, and you need to be sure to tell the caller of your script that it has failed. Building on top of Exec from the library Psake, a script that has the structure below will stop on all errors, and is usable as a base template for most scripts.

    Set-StrictMode -Version latest
    $ErrorActionPreference = "Stop"
    
    
    # Taken from psake https://github.com/psake/psake
    <#
    .SYNOPSIS
      This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
      to see if an error occcured. If an error is detected then an exception is thrown.
      This function allows you to run command-line programs without having to
      explicitly check the $lastexitcode variable.
    .EXAMPLE
      exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
    #>
    function Exec
    {
        [CmdletBinding()]
        param(
            [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
            [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ("Error executing command {0}" -f $cmd)
        )
        & $cmd
        if ($lastexitcode -ne 0) {
            throw ("Exec: " + $errorMessage)
        }
    }
    
    Try {
    
        # Put all your stuff inside here!
    
        # powershell functions called as normal and try..catch reports errors 
        New-Object System.Net.WebClient
    
        # call exe's and check their exit code using Exec
        Exec { setup.exe }
    
    } Catch {
        # tell the caller it has all gone wrong
        $host.SetShouldExit(-1)
        throw
    }
    
    0 讨论(0)
  • 2020-12-02 06:42

    Sadly, due to buggy cmdlets like New-RegKey and Clear-Disk, none of these answers are enough. I've currently settled on the following code in a file called ps_support.ps1:

    Set-StrictMode -Version Latest
    $ErrorActionPreference = "Stop"
    $PSDefaultParameterValues['*:ErrorAction']='Stop'
    function ThrowOnNativeFailure {
        if (-not $?)
        {
            throw 'Native Failure'
        }
    }
    

    Then in any powershell file, after the CmdletBinding and Param for the file (if present), I have the following:

    $ErrorActionPreference = "Stop"
    . "$PSScriptRoot\ps_support.ps1"
    

    The duplicated ErrorActionPreference = "Stop" line is intentional. If I've goofed and somehow gotten the path to ps_support.ps1 wrong, that needs to not silently fail!

    I keep ps_support.ps1 in a common location for my repo/workspace, so the path to it for the dot-sourcing may change depending on where the current .ps1 file is.

    Any native call gets this treatment:

    native_call.exe
    ThrowOnNativeFailure
    

    Having that file to dot-source has helped me maintain my sanity while writing powershell scripts. :-)

    0 讨论(0)
  • 2020-12-02 06:42

    I'm new to powershell but this seems to be most effective:

    doSomething -arg myArg
    if (-not $?) {throw "Failed to doSomething"}
    
    0 讨论(0)
  • 2020-12-02 06:46

    I came here looking for the same thing. $ErrorActionPreference="Stop" kills my shell immediately when I'd rather see the error message (pause) before it terminates. Falling back on my batch sensibilities:

    IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
    

    I found that this works pretty much the same for my particular ps1 script:

    Import-PSSession $Session
    If ($? -ne "True") {Pause; Exit}
    
    0 讨论(0)
提交回复
热议问题