这是错误报告的前奏或关于设计逻辑和有用性的问题。 无论如何,关于如何开发具有真正终止错误的cmdlet的问题。
在干净的会话中,即使用$ErrorActionPreference = 'Continue'
而不是。{
try
或trap
,调用以下任何命令(甚至全部):
# 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-Error
和ThrowTerminatingError()
存在重大差异。
其错误位置指向throw
行。这并不总是有用的
失败的命令调用行,特别是语法或
输入问题,即本质上终止问题。
所以脚本有一些东西。但是cmdlet可以做什么?
可用WriteError()
未终止。
原始throw
与ThrowTerminatingError()
没有太大区别。
更新
确实,$ErrorActionPreference = 'Stop'
使ThrowTerminatingError()
终止于调用脚本。请try
和trap
。
这不是我要找的。我特别注意到$ErrorActionPreference
= 'Continue'
,默认。我正在寻找绝对的终止错误
无论是否默认设置。比较,在脚本throw
中总是如此
终止(虽然它并不完美,如上所述)。我正在寻找
.NET cmdlet中的模拟。
用户忘记设置$ErrorActionPreference = 'Stop'
。我有时会忘记这一点。
有些情况如无效命令应该停止调用脚本
设置。至少命令作者应该能够选择这个选项。
答案 0 :(得分:1)
结果,'继续!'在使用
ThrowTerminatingError()
的每个命令后调用。事实证明,此方法终止命令本身,但不终止调用脚本。
当然不是 - 您的$ErrorActionPreference
设置为Continue
- 因此当cmdlet调用引发错误时,repl(或脚本)只会恢复(继续 s)执行。
$ErrorActionPreference
是定义它的作用域的本地,因此您可以在函数或脚本中设置它以覆盖用户的首选项(但仅限于函数/脚本的范围内):
[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'