我是C#开发人员,有时PowerShell只会让我发疯。
我有以下代码:
$script:ErrorActionPreference = 'Stop'
try {
# Some code here
}
catch [Microsoft.PowerShell.Commands.WriteErrorException] {
# Print error messages (without stacktrace)
Write-Host -ForegroundColor Red $_.Exception.Message
exit 1
}
catch [System.Management.Automation.RuntimeException] {
# A thrown string
Write-Host -ForegroundColor Red $_.Exception.Message
Write-Host -ForegroundColor Red $_.ScriptStackTrace
exit 1
}
catch {
# Print proper exception message (including stack trace)
Write-Host -ForegroundColor Red "$($_.Exception.GetType().Name): $($_.Exception.Message)"
Write-Host -ForegroundColor Red $_.ScriptStackTrace
exit 1
}
这个想法基本上是:
Write-Error
的调用,请使用第一个 catch块。现在,我的问题在于Write-Error
和第一个catch块:
Write-Error
块内调用try
,则执行第二个catch块(即使应该执行第一个块)。Write-Error
,则使用正确的(第一个)catch块。为什么?
我已经检查过WriteErrorException
和RuntimeException
是否相互继承:它们不是(都来自SystemException
,但这无关紧要。)
我还验证了PowerShell 5.1和PowerShell Core(6.0)中的这种行为是相同的。
答案 0 :(得分:1)
Write-Error
不会抛出终止错误,但正如您所提到的那样,ErrorActionPreference
设置为Stop
。但是,这会将抛出的异常更改为ActionPreferenceStopException
继承RuntimeException
您仍然可以在没有WriteErrorException
子句的情况下捕获RuntimeException
,因为ActionPreferenceStopException
的内部错误记录包含WriteErrorException
你可以通过运行这个来看看我的意思:
Write-Error 'this is a test' -ErrorAction Stop
$error[0].ErrorRecord.Exception.GetType()
# IsPublic IsSerial Name BaseType
# -------- -------- ---- --------
# True True WriteErrorException System.SystemException
但是使用RuntimeException
子句,它将首先被选中,因为RuntimeException
是最接近的匹配异常类型。
要解决此问题,您需要在$_
子句中抛出更具体的异常或测试RuntimeException
。这是后者
$script:ErrorActionPreference = 'Stop'
try {
# Some code here
}
catch [Microsoft.PowerShell.Commands.WriteErrorException] {
# Print error messages (without stacktrace)
Write-Host -ForegroundColor Red $_.Exception.Message
exit 1
}
catch [System.Management.Automation.RuntimeException] {
if ($_.Exception -is [Microsoft.PowerShell.Commands.WriteErrorException]) {
# Print error messages (without stacktrace)
Write-Host -ForegroundColor Red $_.Exception.Message
exit 1
}
# A thrown string
Write-Host -ForegroundColor Red $_.Exception.Message
Write-Host -ForegroundColor Red $_.ScriptStackTrace
exit 1
}
catch {
# Print proper exception message (including stack trace)
Write-Host -ForegroundColor Red "$($_.Exception.GetType().Name): $($_.Exception.Message)"
Write-Host -ForegroundColor Red $_.ScriptStackTrace
exit 1
}
您还可以添加ActionPreferenceStopException
子句并在那里测试$_
。
编辑:实际上,除非确实想要使用Write-Error
,否则最好只抛出类似于C#的异常。因此,请使用:
Write-Error
throw [System.InvalidOperationException]::new('This is my message')