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


当前回答

我刚接触powershell,但这似乎是最有效的:

doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}

其他回答

重定向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

对于powershell函数和调用exe函数,您需要稍微不同的错误处理,并且您需要确保告诉脚本的调用者它失败了。构建在Psake库的Exec之上,具有下面结构的脚本将在所有错误时停止,并可作为大多数脚本的基本模板。

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
}

您应该能够通过在脚本的开头使用语句$ErrorActionPreference = "Stop"来实现这一点。

$ErrorActionPreference的默认设置是Continue,这就是为什么你看到你的脚本在错误发生后继续运行。

我刚接触powershell,但这似乎是最有效的:

doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}

不幸的是,由于有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脚本时,使用该文件进行点源可以帮助我保持头脑清醒。: -)