【问题标题】:How to prevent $error from collecting caught exceptions?如何防止 $error 收集捕获的异常?
【发布时间】:2023-03-31 12:29:01
【问题描述】:

每当我捕捉到异常并处理它时,它似乎仍然会在$error 变量中结束。例如,使用以下代码作为示例重现:

$error.clear(); # To make the example as clear as possible

# Lots of logic happens here that leaves a trace in $error. I want to see these
# traces at the very end of my script. However, before the end, seomething along
# these lines happens:

try {
    Write-Output "Trying...";
    $myVar = $null; # Assume $null is actually the result of a complex function
    if ($myVar.ToString() -match "my pattern") {
        # More logic here
    }
} catch {
    Write-Output "Catching...";
} 

# Even more stuff happens here, which may (or may not) add interesting stuff to
# the $error variable.

# Here, at the end of my script, I'm only interested in errors *not* from the 
# try..catch bit, but alas, the Count will inlcude those too...
Write-Output ("Ending... with error.Count = {0}" -f $error.Count);

错误被捕获,但$error.Count 在此脚本末尾仍为“1”。但是,就我而言,我正在处理 catch 中的错误,我不想被脚本末尾的错误所困扰。

我试图重写导致命令行开关异常的逻辑,希望ErrorAction 参数能解决问题,但这没有用。

我也试过我的 Google-fu(this query 上的各种变体)和 SO-fu(this query 上的变体),但结果都是空的。

在我结束之前,让我详细说明一下我的场景的上下文,以防我遇到 XY 问题。上面的 sn-p 是较长部署脚本中一小段代码的表示。在该代码块之前和之后,可能还有其他东西会在 $error 变量中留下痕迹。出于这个原因,我认为我无法在一开始就清除错误(我想保留可能已经存在的东西)。

底线:如何防止$error 变量收集捕获的异常?

【问题讨论】:

  • 你不能在finally 块中再次执行$error.clear
  • 我认为您无法阻止这种行为。但出于好奇,为什么它会打扰你?如果您自己捕获异常,则根本不必处理 $error。
  • 嘿@Matt,感谢您的评论。我在问题中添加了一些上下文来解决它。基本上,当执行上述块时,$error 变量可能已经填充了我想要保留在那里的东西。
  • 哦。您正在尝试移动已解决的错误,但仍想知道您在执行代码时可能遗漏了什么。
  • @ojk 我之前的评论是否也希望解决您的问题?为了详细说明,我对$error 变量很感兴趣,因为我的脚本块之前 发生了什么。我想防止我的try...catch 弄乱那个变量。 (如果答案是“那不可能”,那就这样吧,当然——那只需要我重新考虑我的设置。)

标签: powershell try-catch


【解决方案1】:

如果它不是您想要的,我会删除它,但我尝试做这样的事情。它有一个警告,您可能会自己看到,我将解决。

$error.clear()
$addressedErrors = @()

Get-ChildItem c:\tempo1 -ErrorAction SilentlyContinue

try{
    Get-ChildItem c:\tempo2 -ErrorAction Stop
} Catch {
    $addressedErrors += [regex]::escape($error[0].Exception.Message)
}
Get-ChildItem c:\tempo3 -ErrorAction SilentlyContinue


$regex = "($($addressedErrors -join '|'))"
$uncaughtErrors = $error | Where-Object{$_.Exception.Message -notmatch $regex}

$uncaughtErrors.Count

所以我清除了$error 以从头开始。在我的测试中,我执行了 3 个应该失败的 Get-ChildItem。我只抓一个。

Catch 中,我获取错误消息并构建这些消息的数组。还可以使用静态 escape 正则表达式方法来转义正则表达式特殊字符。我考虑采用实际异常,在本例中为 [System.Management.Automation.ItemNotFoundException],但这不足以让我相信这种方法。

在我/你的脚本结束时,我收集错误消息并构建一个正则表达式字符串。获取$error 对象并输出尚未解决的错误。

警告

我知道这样做会出错的一件事是,如果完全相同的错误发生了两次但解决了一次。 -notmatch 将过滤掉这两种情况。可以通过构建一个带有错误索引的复杂哈希表来解决这个问题,但我不知道你是否甚至致力于这个解决方法。

【讨论】:

    【解决方案2】:

    我在我的 catch 块中使用 $Error.RemoveAt(0) 的方法来帮助解决这个问题。 我发现自己在计划任务中使用它,在那里我检查 $Error 的计数并在遇到任何非手动异常时抛出退出代码。

    $Error.RemoveAt(0) 中的零是索引号,实质上消除了最新的错误。这应该有望消除将您发送到 catch 块的错误。

    try {
        $FormattedDate = Get-Date -Date $Date -Format "yyyy-MM-dd" -ErrorAction Stop
    }
    catch {
        $Error.RemoveAt(0)
        $FormattedDate = $null
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 2010-10-28
      相关资源
      最近更新 更多