在 powershell 模块函数中发出错误的正确方法是什么? [英] What's the right way to emit errors in powershell module functions?

查看:50
本文介绍了在 powershell 模块函数中发出错误的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了很多关于 powershell 错误处理的内容,现在我对在任何给定情况下应该做什么(错误处理)感到非常困惑.我正在使用 powershell 5.1(不是核心).照这样说:假设我有一个模块,它的函数看起来像这个模拟:

I've read quite a bit on powershell error handling and now I'm quite confused about what I should be doing on any given situation (error handling). I'm working with powershell 5.1 (not core). With that said: Suppose I have a module with a function that would look like this mock:

function Set-ComputerTestConfig {
  [CmdletBinding()]
  param(
    [Parameter(Position=0, Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [string] $Name)

begin { ... }
process { 
 # task 1
 # task 2 => results in a failure that prevents further tasks
 # task 3
 # task 4
}
end { ... }

假设对于我传递给此函数的每台计算机名称,我有 4 个任务要完成,但如果其中任何一个任务失败,我将无法继续执行剩余的任务.我应该如何产生错误(最佳实践),以便它停止此特定计算机名称的进程",但有效地继续处​​理管道?

Let's say that for each computer name that I pass to this function, I have 4 tasks to complete, but if any of the tasks fail, I can't continue with the remaining tasks. How should I be producing an error (best practice) such that it halts "process" for this particular computer name but effectively continues to process the pipeline?

推荐答案

  • 如果您想继续处理来自管道的输入,您必须发出一个非终止错误:

    • If you want to continue processing inputs from the pipeline, you must emit a non-terminating error:

      • Write-Error 写入非终止错误;它写入 PowerShell 的错误流,而不会在幕后产生异常;执行正常继续.

      • Write-Error writes non-terminating errors; it writes to PowerShell's error stream without generating an exception behind the scenes; execution continues normally.

      • 如果 .NET 方法调用是错误源(如您的情况),请将其包装在 try/catch 中,然后调用 Write-catch 块中的错误 -ErrorRecord $_:

      • If a .NET method call is the error source, as in your case, wrap it in try / catch, and call Write-Error -ErrorRecord $_ in the catch block:

      • try { <#task 1 #>;... } catch { Write-Error -ErrorRecord $_ }

      不幸的是,从 PowerShell Core 7.0.0-preview.4 开始,Write-Error 没有完全按预期运行,因为它没有设置自动成功 -状态变量 $? 在调用者的上下文中设置为 $false,这是应该的.目前唯一的解决方法是确保您的函数/脚本是 高级 一并使用 $PSCmdlet.WriteError();catch你可以简单地使用 $PSCmdlet.WriteError($_),但是从头开始制作你自己的错误很麻烦 - 见 GitHub 问题 #3629.

      Unfortunately, still as of PowerShell Core 7.0.0-preview.4, Write-Error doesn't fully behave as expected, in that it doesn't set the automatic success-status variable, $?, to $false in the caller's context, as it should. The only workaround at present is to make sure that your function/script is an advanced one and to use $PSCmdlet.WriteError(); from a catch block you can simply use $PSCmdlet.WriteError($_), but crafting your own error from scratch is cumbersome - see GitHub issue #3629.

      如果您希望处理立即停止,请使用终止错误:

      If you want processing to stop right away, use a terminating error:

      • throw 会产生终止错误.
        • 不幸的是,throw 创建了一种比二进制 cmdlet 发出的基本类型的终止错误:不同于 语句-终止由(编译的)cmdlet 发出的错误throw 创建一个脚本-终止(致命)错误.

        • throw creates terminating errors.
          • Unfortunately, throw creates a more fundamental kind of terminating error than binary cmdlets emit: unlike the statement-terminating errors emitted by (compiled) cmdlets, throw creates a script-terminating (fatal) error.

          • 也就是说,默认情况下,二进制 cmdlet 的语句终止错误仅终止手头的语句(管道)并继续执行封闭脚本,而 throw 在默认情况下会中止整个脚本(及其来电者).
          • GitHub 问题 #14819 讨论了这种不对称性.
          • That is, by default a binary cmdlet's statement-terminating error only terminates the statement (pipeline) at hand and continues execution of the enclosing script, whereas throw by default aborts the entire script (and its callers).
          • GitHub issue #14819 discusses this asymmetry.

          同样,解决方法要求您的脚本/函数是高级,这使您能够调用 $PSCmdlet.ThrowTerminatingError() 而不是 throw,它正确地生成一个语句终止错误;与 $PSCmdlet.WriteError() 一样,您可以简单地使用 $PSCmdlet.ThrowTerminationError($_) 来自 catch,但是从头开始编写自己的语句终止错误很麻烦.

          Again, the workaround requires that your script/function is an advanced one, which enables you to call $PSCmdlet.ThrowTerminatingError() instead of throw, which properly generates a statement-terminating error; as with $PSCmdlet.WriteError(), you can simply use $PSCmdlet.ThrowTerminatingError($_) from a catch block, but crafting your own statement-terminating error from scratch is cumbersome.

          至于 $ErrorActionPreference = 'Stop'

          • 这会将所有错误类型变成脚本-终止错误,以及至少高级函数/脚本-那些应该像 cmdlet 一样运行 - 应该设置它.

          • This turns all error types into script-terminating errors, and at least advanced functions / scripts - those expected to act like cmdlets - should not set it.

          相反,让您的脚本/函数发出适当类型的错误,并让调用者通过常见的-ErrorAction参数控制对它们的响应或通过 $ErrorActionPreference 变量.

          Instead, make your script / function emit the appropriate types of errors and let the caller control the response to them, either via the common -ErrorAction parameter or via the $ErrorActionPreference variable.

          • 警告:如果调用者在模块外或在不同的模块中,模块中的函数不会看到调用者的偏好变量 -GitHub 问题 #4568 中讨论了这个基本问题.
          • Caveat: Functions in modules do not see the caller's preference variables, if the caller is outside a module or in a different module - this fundamental problem is discussed in GitHub issue #4568.

          至于通过传递错误/从函数脚本内部重新打包:

          As for passing errors through / repackaging them from inside your function script:

          • 非终止性错误自动传递.

          • 如果需要,您可以使用 -ErrorAction Ignore2>$null 抑制它们,也可以选择收集它们以供以后使用 -ErrorVariable 公共参数(与 -ErrorAction SilentlyContinue 结合).
          • If needed, you can suppress them with -ErrorAction Ignore or 2>$null and optionally also collect them for later processing with the -ErrorVariable common parameter (combine with -ErrorAction SilentlyContinue).

          脚本终止错误,整个调用堆栈默认终止,代码终止.

          Script-terminating errors are passed through in the sense that the entire call stack is terminated by default, along with your code.

          语句-终止错误会写入错误流,但默认情况下您的脚本/函数继续运行.

          Statement-terminating errors are written to the error stream, but by default your script / function continues to run.

          • 使用 try { ... } catch { throw } 来代替将它们变成 script-终止错误,或者 ...

          • Use try { ... } catch { throw } to instead turn them into script-terminating errors, or ...

          ... 使用 $PSCmdlet.ThrowTerminatingError($_) 而不是 throw 将错误作为 statement-终止一个.

          ... use $PSCmdlet.ThrowTerminatingError($_) instead of throw to relay the error as a statement-terminating one.

          进一步阅读:

          • 关于何时发出终止与非终止错误的指南在这个答案中.

          PowerShell 错误处理的全面概述位于 GitHub 文档问题 #1583.

          A comprehensive overview of PowerShell's error handling is in GitHub docs issue #1583.

          这篇关于在 powershell 模块函数中发出错误的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆