PowerShell ThrowTerminatingError()错误不是真正的终止错误

时间:2016-07-19 18:12:57

标签: powershell

这是错误报告的前奏或关于设计逻辑和有用性的问题。 无论如何,关于如何开发具有真正终止错误的cmdlet的问题。

在干净的会话中,即使用$ErrorActionPreference = 'Continue'而不是。{ trytrap,调用以下任何命令(甚至全部):

# script module, missing path
Save-Module InvokeBuild -Path zzz -ErrorAction Stop; 'Continued!'

# cmdlet, invalid data
ConvertFrom-Json zzz -ErrorAction Stop; 'Continued!'

# cmdlet, invalid command syntax
Get-Module -Name zzz -FullyQualifiedName zzz -ErrorAction Stop; 'Continued!'
Export-Csv -Path zzz -LiteralPath zzz -InputObject 1 -ErrorAction Stop; 'Continued!'

因此,在使用'Continued!'的每个命令之后调用ThrowTerminatingError()。 事实证明,此方法终止命令本身,但不终止调用脚本。

这些只是一些人为的例子,还有很多其他例子。 例子不是真实的,但有时候问题是真实的。

请注意,-ErrorAction Stop没有帮助,它不是为此类错误而设计的。 它会影响非终止错误(WriteError()Write-Error)。

实际问题:有没有办法发出终止错误 终止当前命令和调用脚本?

在脚本中看起来会这样(在某些情况下,并非全部):

Write-Error -ErrorAction Stop "message"

请注意,throw "message"确实已经终止。 但与Write-ErrorThrowTerminatingError()存在重大差异。 其错误位置指向throw行。这并不总是有用的 失败的命令调用行,特别是语法或 输入问题,即本质上终止问题。

所以脚本有一些东西。但是cmdlet可以做什么? 可用WriteError()未终止。 原始throwThrowTerminatingError()没有太大区别。

更新

确实,$ErrorActionPreference = 'Stop'使ThrowTerminatingError()终止于调用脚本。请trytrap

这不是我要找的。我特别注意到$ErrorActionPreference = 'Continue'默认。我正在寻找绝对的终止错误 无论是否默认设置。比较,在脚本throw中总是如此 终止(虽然它并不完美,如上所述)。我正在寻找 .NET cmdlet中的模拟。

用户忘记设置$ErrorActionPreference = 'Stop'。我有时会忘记这一点。 有些情况如无效命令应该停止调用脚本 设置。至少命令作者应该能够选择这个选项。

2 个答案:

答案 0 :(得分:1)

  

结果,'继续!'在使用ThrowTerminatingError()的每个命令后调用。事实证明,此方法终止命令本身,但不终止调用脚本。

当然不是 - 您的$ErrorActionPreference设置为Continue - 因此当cmdlet调用引发错误时,repl(或脚本)只会恢复(继续 s)执行。

$ErrorActionPreference是定义它的作用域的本地,因此您可以在函数或脚本中设置它以覆盖用户的首选项(但仅限于函数/脚本的范围内):

script.ps1

[CmdletBinding()]
param()

$ErrorActionPreference = 'Stop'

# script module, missing path
Save-Module InvokeBuild -Path zzz -ErrorAction Stop; 'Continued!'

# cmdlet, invalid data
ConvertFrom-Json zzz -ErrorAction Stop; 'Continued!'

# cmdlet, invalid command syntax
Get-Module -Name zzz -FullyQualifiedName zzz -ErrorAction Stop; 'Continued!'
Export-Csv -Path zzz -LiteralPath zzz -InputObject 1 -ErrorAction Stop; 'Continued!'

Save-Module出错后(即使$ErrorActionPreference在调用范围内设置为Continue),它会立即返回

答案 1 :(得分:1)

您可以在PowerShell throw:

中抛出与throw语句相同的异常
Add-Type -TypeDefinition @‘
    using System;
    using System.Management.Automation;
    [Cmdlet(VerbsDiagnostic.Test, "Throw")]
    public class TestThrow : Cmdlet {
        protected override void ProcessRecord() {
            throw new RuntimeException("Message") { WasThrownFromThrowStatement=true };
        }
    }
’@ -PassThru|Select-Object -First 1 -ExpandProperty Assembly|Import-Module

Test-Throw; 'Not printed'

在脚本中,可以这种方式完成(需要调用内部方法):

function Test-ScriptThrow {
    $ErrorRecordType = [System.Management.Automation.ErrorRecord]
    $ErrorRecord = $ErrorRecordType::new([Exception]::new("Message"), 'ErrorId', 'NotSpecified', $null)
    $ErrorRecordType.InvokeMember('SetInvocationInfo', 'Instance, NonPublic, InvokeMethod', $null, $ErrorRecord, $MyInvocation)
    throw $ErrorRecord
}

Test-ScriptThrow; 'Not printed'

似乎C#cmdlet需要同样的事情:

Add-Type -TypeDefinition @‘
    using System;
    using System.Reflection;
    using System.Management.Automation;
    [Cmdlet(VerbsDiagnostic.Test, "Throw2")]
    public class TestThrow2 : PSCmdlet {
        protected override void ProcessRecord() {
            ErrorRecord errorRecord = new ErrorRecord(new Exception("Message"), "ErrorId", ErrorCategory.NotSpecified, null);
            typeof(ErrorRecord).InvokeMember("SetInvocationInfo", BindingFlags.Instance|BindingFlags.NonPublic|BindingFlags.InvokeMethod, null, errorRecord, new[] { MyInvocation });
            throw new RuntimeException(null, null, errorRecord) { WasThrownFromThrowStatement=true };
        }
    }
’@ -PassThru|Select-Object -First 1 -ExpandProperty Assembly|Import-Module

Test-Throw2 | % { Some other command }; 'Not printed'

否则它将整个语句强调为错误,而不仅仅是一个命令:

Test-Throw | % { Some other command }; 'Not printed'