我希望我的PowerShell脚本在我运行的任何命令失败时停止(如bash中的set -e)。我正在使用Powershell命令(New-Object System.Net.WebClient)和程序(.\setup.exe)。


当前回答

不幸的是,由于有bug的cmdlet,如New-RegKey和Clear-Disk,这些答案都不够。我目前在一个名为ps_support.ps1的文件中确定了以下代码:

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

然后在任何powershell文件中,在文件(如果存在)的CmdletBinding和Param之后,我有以下内容:

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

重复的ErrorActionPreference = "Stop"行是有意的。如果我犯了错误,以某种方式获得了ps_support的路径。Ps1错了,那需要的不是默默的失败!

我保留ps_support。Ps1位于我的repo/workspace的公共位置,因此点源的路径可能会根据当前. Ps1文件的位置而改变。

任何本地调用都会得到这样的处理:

native_call.exe
ThrowOnNativeFailure

在编写powershell脚本时,使用该文件进行点源可以帮助我保持头脑清醒。: -)

其他回答

据我所知,Powershell对它调用的子程序返回的非零退出码没有任何自动处理。

到目前为止,我所知道的模仿bash -e行为的唯一解决方案是在每次调用外部命令后添加这个检查:

if(!$?) { Exit $LASTEXITCODE }

重定向stderr到stdout似乎也没有任何其他命令/scriptblock包装的技巧,尽管我找不到一个解释为什么它是这样工作的。

# test.ps1

$ErrorActionPreference = "Stop"

aws s3 ls s3://xxx
echo "==> pass"

aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"

这将如预期的那样输出以下内容(命令aws s3…返回$LASTEXITCODE = 255)

PS> .\test.ps1

An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass

不幸的是,由于有bug的cmdlet,如New-RegKey和Clear-Disk,这些答案都不够。我目前在一个名为ps_support.ps1的文件中确定了以下代码:

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

然后在任何powershell文件中,在文件(如果存在)的CmdletBinding和Param之后,我有以下内容:

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

重复的ErrorActionPreference = "Stop"行是有意的。如果我犯了错误,以某种方式获得了ps_support的路径。Ps1错了,那需要的不是默默的失败!

我保留ps_support。Ps1位于我的repo/workspace的公共位置,因此点源的路径可能会根据当前. Ps1文件的位置而改变。

任何本地调用都会得到这样的处理:

native_call.exe
ThrowOnNativeFailure

在编写powershell脚本时,使用该文件进行点源可以帮助我保持头脑清醒。: -)

对于2021年来到这里的人,这是我的解决方案,涵盖了cmdlet和程序

function CheckLastExitCode {
    param ([int[]]$SuccessCodes = @(0))

    if (!$?) {
        Write-Host "Last CMD failed" -ForegroundColor Red
        #GoToWrapperDirectory in my code I go back to the original directory that launched the script
        exit
    }

    if ($SuccessCodes -notcontains $LastExitCode) {
        Write-Host "EXE RETURNED EXIT CODE $LastExitCode" -ForegroundColor Red
        #GoToWrapperDirectory in my code I go back to the original directory that launched the script
        exit
    } 
    
}

你可以这样用

cd NonExistingpath
CheckLastExitCode

我来这里也是为了寻找同样的东西。$ErrorActionPreference="Stop"立即杀死我的shell时,我宁愿看到错误消息(暂停)之前,它终止。回到我的批处理敏感性:

IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF

我发现这对我的特定ps1脚本几乎是一样的:

Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}