PowerShell try catch会丢失重复的访问错误

PowerShell try catch会丢失重复的访问错误,powershell,error-handling,Powershell,Error Handling,似乎无法可靠地捕获所有错误。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 ""

似乎无法可靠地捕获所有错误。Try catch on
get 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> 
PS C:\WINDOWS\system32>D:\\ErrorTest.ps1
我将获得文件结构“C:\Windows\System32”,但这会产生两个拒绝访问错误:
get-ChildItem:对路径“C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5”的访问被拒绝。
在D:\\ErrorTest.ps1:5字符:19
+ ... aoFileSystem=@(获取子项“C:\Windows\System32”-递归-force)
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CategoryInfo:PermissionDenied:(C:\Windows\Syst…che\Content.IE5:String)[Get ChildItem],UnauthorizedAccessException
+FullyQualifiedErrorId:DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
get-ChildItem:对路径“C:\Windows\System32\LogFiles\WMI\RtBackup”的访问被拒绝。
在D:\\ErrorTest.ps1:5字符:19
+ ... aoFileSystem=@(获取子项“C:\Windows\System32”-递归-force)
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+CategoryInfo:PermissionDenied:(C:\Windows\Syst…es\WMI\RtBackup:String)[Get ChildItem],UnauthorizedAccessException
+FullyQualifiedErrorId:DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
我现在将再次这样做,并为这些错误设置陷阱。但我只得到其中一个:
System.UnauthorizedAccessException:C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WINDOWS\INetCache\Content.IE5
PS C:\WINDOWS\system32>
我想记录访问错误,但当我试图捕捉它们时,我只得到第一个错误。当我为他们设陷阱时,我需要做什么才能让第二个出现


编辑:我收到一条消息,告诉我需要编辑我的问题,以解释它与其他问题的不同之处。因此,我将在这里重复我对怀疑论者下面评论的回应。该问题适用于
ForEach
循环中的
getchilditem
。我的问题不涉及这样的循环。尽管如此,我还是尝试了接受答案的方法,使用了
-ErrorAction-SilentlyContinue
,但这样可以隐藏错误而不会捕获错误。然而,在我找到的并将作为答案发布的解决方案中,我确实使用了
-ErrorAction SilentlyContinue
-ErrorVariable
组合使用,非常简单!您在第二条目录访问语句中指定了参数-ErrorAction Stop。将其切换到-ErrorAction Continue,您将收到两条错误消息。

非常简单!您在第二条目录访问语句中指定了参数-ErrorAction Stop。将其切换到-ErrorAction Continue时,您会收到两条错误消息。

我对
ErrorAction
参数进行了一些研究,发现了
ErrorVariable
参数。(两者都是,所以它们不会出现在的文档中。)从那以后,我就能够找出如何正确捕获错误

下面的新脚本显示了四种方法。方法2和方法3效果良好。方法4不起作用,因为它是。方法1,最初的try-catch方法,不起作用,我仍然不知道为什么。这是令人不安的,因为错误捕获按预期工作很重要。如果我不知道会出现两个错误,我就不会知道try-catch没有给我正确的输出

我不接受这个(我自己的)答案,因为,尽管下面的脚本显示了两种正确捕获这些错误的方法,如果有人能解释为什么try-catch不起作用,那就更好了。

新脚本:

$sScriptName  = "ErrorTest.ps1"

$sPath = "C:\Windows\System32"

write-host ("I will get the file structure of """ + $sPath + """, but this yields two access-denied errors:")
$aoFileSystem = @(get-ChildItem $sPath -recurse -force)

write-host ("I will now do it again and trap for those errors.")

write-host ("`r`nMethod 1: Original method using try-catch (incorrect results; only finds one of the two errors; why?):")
try {$aoFileSystem = @(get-ChildItem $sPath -recurse -force -ErrorAction Stop)}
catch [System.UnauthorizedAccessException]
   {$sErrorMessage = $_.ToString()
    write-host ("System.UnauthorizedAccessException: " + $sErrorMessage.substring(20, $sErrorMessage.length - 32))}

write-host ("`r`nGet array for Methods 2 to 4.")
$aoFileSystem = @(get-ChildItem $sPath -recurse -force -ErrorAction SilentlyContinue -ErrorVariable aoChildItemError)

write-host ("`r`nMethod 2: Output by piping to ForEach-object (correct results):")
$aoChildItemError | 
    ForEach-object `
       {$oErrorRecord = $_
        write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}

write-host ("`r`nMethod 3: Output by for loop (correct results):")
for ($nCount = 0; $nCount -lt $aoChildItemError.count; $nCount++)
   {$oErrorRecord = $aoChildItemError[$nCount]
    write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}

write-host ("`r`nMethod 4: Output by ForEach-object loop without pipeline (incorrect results because it incorrectly attempts to use the parameter ""InputObject"" in ""ForEach-object""):")
ForEach-object -InputObject $aoChildItemError `
   {$oErrorRecord = $_
    write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}
新产出:

PS C:\WINDOWS\system32> D:\_\z-temp\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:\_\z-temp\ErrorTest.ps1:6 char:19
+ $aoFileSystem = @(get-ChildItem $sPath -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:\_\z-temp\ErrorTest.ps1:6 char:19
+ $aoFileSystem = @(get-ChildItem $sPath -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.

Method 1: Original method using try-catch (incorrect results; only finds one of the two errors; why?):
System.UnauthorizedAccessException: C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5

Get array for Methods 2 to 4.

Method 2: Output by piping to ForEach-object (correct results):
UnauthorizedAccessException: "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5"
UnauthorizedAccessException: "C:\Windows\System32\LogFiles\WMI\RtBackup"

Method 3: Output by for loop (correct results):
UnauthorizedAccessException: "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5"
UnauthorizedAccessException: "C:\Windows\System32\LogFiles\WMI\RtBackup"

Method 4: Output by ForEach-object loop without pipeline (incorrect results because it incorrectly attempts to use the parameter "InputObject" in "ForEach-object"):

UnauthorizedAccessException UnauthorizedAccessException : " C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5 C:\Window
s\System32\LogFiles\WMI\RtBackup "

PS C:\WINDOWS\system32>  

我对
ErrorAction
参数做了一些研究,发现了
ErrorVariable
参数。(两者都是,所以它们不会出现在的文档中。)从那以后,我就能够找出如何正确捕获错误

下面的新脚本显示了四种方法。方法2和方法3效果良好。方法4不起作用,因为它是。方法1,最初的try-catch方法,不起作用,我仍然不知道为什么。这是令人不安的,因为错误捕获按预期工作很重要。如果我不知道会出现两个错误,我就不会知道try-catch没有给我正确的输出

我不接受这个(我自己的)答案,因为,尽管下面的脚本显示了两种正确捕获这些错误的方法,如果有人能解释为什么try-catch不起作用,那就更好了。

新脚本:

$sScriptName  = "ErrorTest.ps1"

$sPath = "C:\Windows\System32"

write-host ("I will get the file structure of """ + $sPath + """, but this yields two access-denied errors:")
$aoFileSystem = @(get-ChildItem $sPath -recurse -force)

write-host ("I will now do it again and trap for those errors.")

write-host ("`r`nMethod 1: Original method using try-catch (incorrect results; only finds one of the two errors; why?):")
try {$aoFileSystem = @(get-ChildItem $sPath -recurse -force -ErrorAction Stop)}
catch [System.UnauthorizedAccessException]
   {$sErrorMessage = $_.ToString()
    write-host ("System.UnauthorizedAccessException: " + $sErrorMessage.substring(20, $sErrorMessage.length - 32))}

write-host ("`r`nGet array for Methods 2 to 4.")
$aoFileSystem = @(get-ChildItem $sPath -recurse -force -ErrorAction SilentlyContinue -ErrorVariable aoChildItemError)

write-host ("`r`nMethod 2: Output by piping to ForEach-object (correct results):")
$aoChildItemError | 
    ForEach-object `
       {$oErrorRecord = $_
        write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}

write-host ("`r`nMethod 3: Output by for loop (correct results):")
for ($nCount = 0; $nCount -lt $aoChildItemError.count; $nCount++)
   {$oErrorRecord = $aoChildItemError[$nCount]
    write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}

write-host ("`r`nMethod 4: Output by ForEach-object loop without pipeline (incorrect results because it incorrectly attempts to use the parameter ""InputObject"" in ""ForEach-object""):")
ForEach-object -InputObject $aoChildItemError `
   {$oErrorRecord = $_
    write-host ($oErrorRecord.CategoryInfo.reason + ": """ + $oErrorRecord.TargetObject + """")}
新产出:

PS C:\WINDOWS\system32> D:\_\z-temp\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:\_\z-temp\ErrorTest.ps1:6 char:19
+ $aoFileSystem = @(get-ChildItem $sPath -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:\_\z-temp\ErrorTest.ps1:6 char:19
+ $aoFileSystem = @(get-ChildItem $sPath -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.

Method 1: Original method using try-catch (incorrect results; only finds one of the two errors; why?):
System.UnauthorizedAccessException: C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5

Get array for Methods 2 to 4.

Method 2: Output by piping to ForEach-object (correct results):
UnauthorizedAccessException: "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5"
UnauthorizedAccessException: "C:\Windows\System32\LogFiles\WMI\RtBackup"

Method 3: Output by for loop (correct results):
UnauthorizedAccessException: "C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5"
UnauthorizedAccessException: "C:\Windows\System32\LogFiles\WMI\RtBackup"

Method 4: Output by ForEach-object loop without pipeline (incorrect results because it incorrectly attempts to use the parameter "InputObject" in "ForEach-object"):

UnauthorizedAccessException UnauthorizedAccessException : " C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache\Content.IE5 C:\Window
s\System32\LogFiles\WMI\RtBackup "

PS C:\WINDOWS\system32>  
  • Get ChildItem“C:\Windows\System32”-recurse-force
    发出的错误是非终止错误,并且,根据定义,此类错误不会终止命令,因此单个命令可能会发出多个此类错误

    • cmdlet发出的所有非终止错误都可以在指定变量中捕获,该变量的名称可以传递给
      -ErrorVariable
      公共参数
    • 此外,默认情况下,所有错误(非终止和终止错误)都记录在会话全局自动
      $Error
      集合变量中
  • try
    /
    catch
    仅对终止错误起作用,因此默认情况下,它对仅发出非终止错误的命令(如
    Get-C)无效