PowerShell:检测脚本函数中的错误 [英] PowerShell: detecting errors in script functions

查看:43
本文介绍了PowerShell:检测脚本函数中的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

检测脚本函数中是否发生错误的最佳方法是什么?我正在寻找一种一致的方式来指示类似于 $?(仅适用于 cmdlet,不适用于脚本函数).

What is the best way to detect if an error occurs in a script function? I'm looking for a consistent way to indicate error/success status similar to $? (which only works on cmdlets, not script functions).

给定一个特定的函数可能会返回一个供调用者使用的值,我们不能通过返回一个布尔值来表示成功.函数可以使用 [ref] 参数并在函数内部适当地设置值并在调用后检查,但这比我想要的要多.我们可以使用 PowerShell 的内置功能吗?

Given a particular function might return a value to be used by the caller, we can't indicate success by returning a boolean. A function could use a [ref] parameter and set the value appropriately inside the function and check after the call, but this is more overhead than I'd like. Is there something built-in to PowerShell that we can use?

我能想到的最好的是:

  1. 在函数中使用Write-Error将 ErrorRecord 对象放入错误中流;
  2. 调用函数ErrorVariable 参数;
  3. 检查 ErrorVariable 参数调用后不为空.

例如:

function MyFun {
  [CmdletBinding()]    # must be an advanced function or this 
  param ()             # will not work as ErrorVariable will not exist
  process {
    # code here....
    if ($SomeErrorCondition) {
      Write-Error -Message "Error occurred; details..."
      return
    }
    # more code here....
  }
}

# call the function
$Err = $null
MyFun -ErrorVariable Err
# this check would be similar to checking if $? -eq $false
if ($Err -ne $null) {
  "An error was detected"
  # handle error, log/email contents of $Err, etc.
}

还有更好的吗?有没有办法使用$?在我们的脚本函数中?我宁愿不抛出异常或 ErrorRecord 对象,而且到处都有大量的 try/catch 块.我也宁愿不使用 $Error ,因为在进行函数调用之前需要检查计数,因为在调用之前可能存在其他错误 - 我不想 Clear() 并丢失它们.

Is there something better? Is there a way of using $? in our script functions? I'd rather not throw exceptions or ErrorRecord objects and have tons of try/catch blocks all over the place. I'd also rather not use $Error as would require checking the count before making the function call as there could be other errors in there before the call - and I don't want to Clear() and lose them.

推荐答案

检测脚本函数中是否发生错误的最佳方法是什么?我正在寻找一种一致的方式来指示类似于 $?(仅适用于 cmdlet,不适用于脚本函数).

What is the best way to detect if an error occurs in a script function? I'm looking for a consistent way to indicate error/success status similar to $? (which only works on cmdlets, not script functions).

PowerShell 中的错误处理一团糟.有错误记录、脚本异常、.NET异常、$?$LASTEXITCODEtraps、$Error> 数组(范围之间),等等.并构造使这些元素彼此交互(例如 $ErrorActionPreference).当你陷入这样的困境时,很难保持一致;然而,有一种方法可以实现这一目标.

Error handling in PowerShell is a total mess. There are error records, script exceptions, .NET exceptions, $?, $LASTEXITCODE, traps, $Error array (between scopes), and so on. And constructs to interact these elements with each other (such as $ErrorActionPreference). It is very difficult to get consistent when you have a morass like this; however, there is a way to achieve this goal.

必须进行以下观察:

  • $? 是一个未公开的秘密.$? 来自 cmdlet 调用的值不会传播,它是一个只读变量"(因此不能手动设置)并且不清楚什么时候确切被设置(可能是执行状态",这个术语在 PowerShell 中从未使用过,除了 about_Automatic_Variables 中的 $? 描述,是一个谜).幸运的是,Bruce Payette 已经阐明了这一点:如果您想设置 $?$PSCmdlet.WriteError() 是唯一已知的方法.

  • $? is an underdocumented mystery. $? values from cmdlet calls do not propagate, it is a "read-only variable" (thus cannot be set by hand) and it is not clear on when exactly it gets set (what could possibly be an "execution status", term never used in PowerShell except on the description of $? in about_Automatic_Variables, is an enigma). Thankfully Bruce Payette has shed light on this: if you want to set $?, $PSCmdlet.WriteError() is the only known way.

如果您希望函数像 cmdlet 一样设置 $?,您必须避免使用 Write-Error 并使用 $PSCmdlet.WriteError() 代替.Write-Error$PSCmdlet.WriteError() 做同样的事情,但前者没有正确设置 $? 而后者可以.(不要费心在某处找到这个文档.它不是.)

If you want functions to set $? as cmdlets do, you must refrain from Write-Error and use $PSCmdlet.WriteError() instead. Write-Error and $PSCmdlet.WriteError() do the same thing, but the former does not set $? properly and the latter does. (Do not bother trying to find this documented somewhere. It is not.)

如果您想正确处理 .NET 异常(就像它们是非终止性错误,将暂停整个执行的决定留给客户端代码),您必须catch$PSCmdlet.WriteError() 它们.你不能不处理它们,因为它们变成了非终止性错误,尊重 $ErrorActionPreference.(也没有记录.)

If you want to handle .NET exceptions properly (as if they were non-terminating errors, leaving the decision of halting the entire execution up to the client code), you must catch and $PSCmdlet.WriteError() them. You cannot leave them unprocessed, since they become non-terminating errors which do not respect $ErrorActionPreference. (Not documented either.)

换句话说,产生一致的错误处理行为的关键是尽可能使用 $PSCmdlet.WriteError().它设置 $?,尊重 $ErrorActionPreference(因此是 -ErrorAction)并接受 System.Management.Automation.ErrorRecord 从其他 cmdlet 或 catch 语句(在 $_ 变量中)生成的对象.

In other words, the key to produce consistent error handling behavior is to use $PSCmdlet.WriteError() whenever possible. It sets $?, respects $ErrorActionPreference (and thus -ErrorAction) and accepts System.Management.Automation.ErrorRecord objects produced from other cmdlets or a catch statement (in the $_ variable).

以下示例将展示如何使用此方法.

The following examples will show how to use this method.

# Function which propagates an error from an internal cmdlet call,
# setting $? in the process.
function F1 {
    [CmdletBinding()]
    param([String[]]$Path)

    # Run some cmdlet that might fail, quieting any error output.
    Convert-Path -Path:$Path -ErrorAction:SilentlyContinue
    if (-not $?) {
        # Re-issue the last error in case of failure. This sets $?.
        # Note that the Global scope must be explicitly selected if the function is inside
        # a module. Selecting it otherwise also does not hurt.
        $PSCmdlet.WriteError($Global:Error[0])
        return
    }

    # Additional processing.
    # ...
}


# Function which converts a .NET exception in a non-terminating error,
# respecting both $? and $ErrorPreference.
function F2 {
    [CmdletBinding()]
    param()

    try {
        [DateTime]"" # Throws a RuntimeException.
    }
    catch {
        # Write out the error record produced from the .NET exception.
        $PSCmdlet.WriteError($_)
        return
    }
}

# Function which issues an arbitrary error.
function F3 {
    [CmdletBinding()]
    param()

    # Creates a new error record and writes it out.
    $PSCmdlet.WriteError((New-Object -TypeName:"Management.Automation.ErrorRecord"
        -ArgumentList:@(
            [Exception]"Some error happened",
            $null,
            [Management.Automation.ErrorCategory]::NotSpecified,
            $null
        )
    ))

    # The cmdlet error propagation technique using Write-Error also works.
    Write-Error -Message:"Some error happened" -Category:NotSpecified -ErrorAction:SilentlyContinue
    $PSCmdlet.WriteError($Global:Error[0])
}

最后一点,如果您想从 .NET 异常中创建终止错误,请执行 try/catch 并重新throw 异常抓到了.

As a last note, if you want to create terminating errors from .NET exceptions, do try/catch and rethrow the exception caught.

这篇关于PowerShell:检测脚本函数中的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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