首页 > 解决方案 > PowerShell tr​​y-catch 丢失重复的访问错误

问题描述

Try-catch似乎不能可靠地捕获所有错误。Try-catch onget-ChildItem不会报告在 try-catch 之外报告的所有访问错误。

编辑:try-catch 不可靠是不正确的,它只报告一个错误是有充分理由的。请参阅我对已接受答案的评论,以了解我对这个问题的误解。

在运行 PowerShell 5.1 的 Windows 10 Pro 64 中,此脚本:

$sScriptName  = "ErrorTest.ps1"

write-host ("I will get the file structure of ""C:\Windows\System32"", but this yields two access-denied errors:")

$aoFileSystem = @(get-ChildItem "C:\Windows\System32" -recurse -force)

write-host ("I will now do it again and trap for those errors. But I only get one of them:")

try {$aoFileSystem = @(get-ChildItem $sPath -recurse -force -ErrorAction Stop)}
catch [System.UnauthorizedAccessException]
   {$sErrorMessage = $_.ToString()
    write-host ("System.UnauthorizedAccessException: " + $sErrorMessage.substring(20, $sErrorMessage.length - 32))}

以管理员身份在 ISE 中运行,得到以下输出:

PS C:\WINDOWS\system32> D:\<path>\ErrorTest.ps1
I will get the file structure of "C:\Windows\System32", but this yields two access-denied errors:
get-ChildItem : Access to the path 'C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5' is denied.
At D:\<path>\ErrorTest.ps1:5 char:19
+ ... aoFileSystem = @(get-ChildItem "C:\Windows\System32" -recurse -force)
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (C:\Windows\Syst...che\Content.IE5:String) [Get-ChildItem], UnauthorizedAccessException
    + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

get-ChildItem : Access to the path 'C:\Windows\System32\LogFiles\WMI\RtBackup' is denied.
At D:\<path>\ErrorTest.ps1:5 char:19
+ ... aoFileSystem = @(get-ChildItem "C:\Windows\System32" -recurse -force)
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (C:\Windows\Syst...es\WMI\RtBackup:String) [Get-ChildItem], UnauthorizedAccessException
    + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand

I will now do it again and trap for those errors. But I only get one of them:
System.UnauthorizedAccessException: C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5

PS C:\WINDOWS\system32> 

我想记录访问错误,但是当我尝试捕获它们时,我只得到第一个。当我诱捕他们时,我需要做什么才能让第二个出现?

编辑:我收到一条消息,告诉我需要编辑我的问题以解释它与GetChildItem 中的 PowerShell 捕获错误并继续循环有何不同?. 因此,我将在此重复我在回应 Scepticalist 下面的评论时所说的话。这个问题是get-ChildItem循环的ForEach。我的问题不涉及这样的循环。尽管如此,我还是从那里接受的答案中尝试了一些东西,使用-ErrorAction SilentlyContinue,但是隐藏了错误而不捕获它们。但是,在我找到并即将作为答案发布的解决方案中,我确实-ErrorAction SilentlyContinue-ErrorVariable.

标签: powershellerror-handling

解决方案


  • 发出的错误Get-ChildItem "C:\Windows\System32" -recurse -force是非终止错误,并且,鉴于根据定义,此类错误不会终止命令,因此单个命令可能会发出多个此类错误。

    • cmdlet 发出的所有非终止错误都可以在指定变量中捕获,您将其名称传递给-ErrorVariablecommon 参数。
    • 此外,默认情况下,所有错误(非终止和终止错误)都记录在会话全局自动$Error收集变量中。
  • try/catch仅作用于终止错误,因此默认情况下它对仅发出非终止错误的命令没有影响,例如Get-ChildItem "C:\Windows\System32" -recurse -force

    • -ErrorAction Stop您可以通过添加(使用common 参数)指示命令将遇到的第一个非终止错误转换为终止错误-ErrorAction,在这种情况下,封闭的try/catch 确实会捕获错误,但请注意,在遇到第一个错误之后执行会停止方式。

警告:有两种类型的终止错误(以及可能存在历史事故的事实);虽然这两种类型都可以用try/捕获catch,但它们的默认行为不同:

  • 语句终止错误,仅终止手头的语句,并在发出错误消息后默认继续执行脚本;通常,如果遇到不限于手头输入且不允许它们继续处理进一步输入的错误,则这些错误由(编译的)cmdlet 发出。

  • 脚本终止错误(运行空间终止错误),默认情况下完全中止处理。使用该Throw语句的 PowerShell 代码会生成此类错误,就像传递-ErrorAction Stop给发出非终止错误的命令一样。

    • 警告:虽然-ErrorAction Stop语句终止错误没有影响,但看似等效的首选项变量设置,意外地将语句终止错误提升为脚本终止错误。$ErrorActionPreference = 'Stop'

进一步阅读:

  • 有关 PowerShell(令人眼花缭乱的复杂)错误处理的全面概述,请参阅此 GitHub 文档问题

  • 至于在编写命令时何时报告终止错误与非终止错误,请参阅此答案


推荐阅读