我希望当我运行的任何命令失败(例如set -e
在bash中)时,PowerShell脚本都能停止。我同时使用Powershell命令(New-Object System.Net.WebClient
)和程序(.\setup.exe
)。
我希望当我运行的任何命令失败(例如set -e
在bash中)时,PowerShell脚本都能停止。我同时使用Powershell命令(New-Object System.Net.WebClient
)和程序(.\setup.exe
)。
Answers:
$ErrorActionPreference = "Stop"
将带您进入那里(例如,这对于cmdlet非常有用)。
但是,对于EXE,您将需要$LastExitCode
在每次exe调用后检查自己,并确定是否失败。不幸的是,我不认为PowerShell可以在这里提供帮助,因为在Windows上,EXE在构成“成功”或“失败”退出代码的内容上并不一致。多数遵循UNIX标准0表示成功,但并非全部成功。在此博客文章中查看CheckLastExitCode函数。您可能会发现它很有用。
throw "$exe failed with exit code $LastExitCode"
,其中$ exe只是执行此操作的路径EXE。
可悲的是,由于像New-RegKey和Clear-Disk这样的cmdlet出错,这些答案都不足够。我目前在任何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'
}
这种本地调用模式对我来说已经变得越来越普遍,我可能应该研究使其更简洁的选项。我仍然是新手,欢迎提出建议。
您需要对Powershell函数和调用exe进行略有不同的错误处理,并且需要确保告诉脚本的调用者该脚本已失败。Exec
在库Psake的基础上构建的,具有以下结构的脚本将在发生所有错误时停止,并且可用作大多数脚本的基本模板。
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
}
Exec { sqlite3.exe -bail some.db "$SQL" }
而-bail
导致错误?用引号将内容包装起来似乎无效。有任何想法吗?
对@alastairtree 的答案进行了轻微修改:
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中的行为Invoke-Call { dotnet build $something }
& @ScriptBlock
并& $ScriptBlock
似乎做同样的事情。在这种情况下,还无法通过谷歌搜索有什么区别
重定向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
$ErrorActionPreference = "Stop"
行为良好的程序是否有效(成功返回0)?