我希望我的PowerShell脚本在我运行的任何命令失败时停止(例如bash中的set -e
)。我正在使用Powershell命令(New-Object System.Net.WebClient
)和程序(.\setup.exe
)。
答案 0 :(得分:253)
$ErrorActionPreference = "Stop"
会让你在那里的一部分(即这适用于cmdlet)。
但是对于EXE,您需要在每次exe调用后自己检查$LastExitCode
并确定是否失败。不幸的是,我不认为PowerShell可以在这里提供帮助,因为在Windows上,EXE在构成“成功”或“失败”退出代码的方面并不十分一致。大多数遵循UNIX标准0指示成功但不是全部。查看CheckLastExitCode function in this blog post。您可能会发现它很有用。
答案 1 :(得分:61)
您应该可以通过在脚本开头使用语句$ErrorActionPreference = "Stop"
来实现此目的。
$ErrorActionPreference
的默认设置为Continue
,这就是您在错误发生后看到脚本继续运行的原因。
答案 2 :(得分:11)
可悲的是,due to buggy cmdlets like New-RegKey and Clear-Disk,这些答案都不够。我目前在任何PowerShell脚本的顶部都定位了以下几行,以保持我的理智。
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
然后任何本地电话都会得到这种待遇:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
对我来说,原生呼叫模式正在慢慢变得普遍,我应该考虑使其更简洁的选项。我仍然是一个名副其实的新手,所以欢迎提出建议。
答案 3 :(得分:9)
对于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
}
答案 4 :(得分:5)
对@alastairtree中的answer进行了一些修改:
function Invoke-Call {
param (
[scriptblock]$ScriptBlock,
[string]$ErrorAction = $ErrorActionPreference
)
& @ScriptBlock
if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
exit $lastexitcode
}
}
Invoke-Call -ScriptBlock { dotnet build . } -ErrorAction Stop
关键区别在于:
Invoke-Command
)-ErrorAction
来自内置cmdlet的行为答案 5 :(得分:2)
我来这里寻找同样的事情。 $ ErrorActionPreference =“Stop”会在我终止之前看到错误消息(暂停)时立即终止我的shell。回到我的批处理感上:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
我发现这对我的特定ps1脚本几乎一样:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
答案 6 :(得分:1)
似乎简单的重新抛出就可以了。
param ([string] $Path, [string] $Find, [string] $Replace)
try {
((Get-Content -path $Path -Raw) -replace $Find, $Replace) | Set-Content -Path $Path
Write-Output Completed.
} catch {
# Without try/catch block errors don't interrupt program flow.
throw
}
现在输出 Completed 只有在成功执行后才会出现。
答案 7 :(得分:0)
我是Powershell的新手,但这似乎最有效:
doSomething -arg myArg
if (-not $?) {throw "Failed to doSomething"}
答案 8 :(得分:0)
在没有任何其他命令/脚本块包装的情况下,将stderr
重定向到stdout
似乎也可以解决问题,尽管我找不到解释为什么这样做的原因。
# 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