From 7aa8315ce1c93dffc1c4bbd7ed63bfb915bb1a4c Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Fri, 9 Oct 2026 17:15:17 +0000 Subject: [PATCH] refactor: remove the exception filter that no exception can reach The catch for an UnauthorizedAccessException of Get-ChildItem2 had an exception filter that passes on what a later command raises. A bounded mutation that removed the filter was not detected: PowerShell wraps the exception of a throw, so a cmdlet never sees the type that was thrown, and no later command can raise a raw UnauthorizedAccessException through a Write call. The filter and the test style that was meant to reach it are removed instead of leaving a branch that nothing can enter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- NTFSSecurity/ItemCmdlets/GetChildItem2.cs | 2 +- Tests/PipelineControl.Tests.ps1 | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/NTFSSecurity/ItemCmdlets/GetChildItem2.cs b/NTFSSecurity/ItemCmdlets/GetChildItem2.cs index 102e4f1..7e8b05c 100644 --- a/NTFSSecurity/ItemCmdlets/GetChildItem2.cs +++ b/NTFSSecurity/ItemCmdlets/GetChildItem2.cs @@ -263,7 +263,7 @@ namespace NTFSSecurity } } } - catch (UnauthorizedAccessException ex) when (!IsFromLaterCommand(ex)) + catch (UnauthorizedAccessException ex) { WriteError(new ErrorRecord(ex, "DirUnauthorizedAccessError", ErrorCategory.PermissionDenied, di.FullName)); } diff --git a/Tests/PipelineControl.Tests.ps1 b/Tests/PipelineControl.Tests.ps1 index 2c071ee..903c545 100644 --- a/Tests/PipelineControl.Tests.ps1 +++ b/Tests/PipelineControl.Tests.ps1 @@ -43,12 +43,12 @@ BeforeDiscovery { @{ Name = $name } } $failureCases = foreach ($name in $names) { - foreach ($style in 'throw', 'throw UnauthorizedAccessException', 'Write-Error -ErrorAction Stop') { + foreach ($style in 'throw', 'Write-Error -ErrorAction Stop') { @{ Name = $name; Style = $style } } } $auditFailureCases = foreach ($name in $auditNames) { - foreach ($style in 'throw', 'throw UnauthorizedAccessException', 'Write-Error -ErrorAction Stop') { + foreach ($style in 'throw', 'Write-Error -ErrorAction Stop') { @{ Name = $name; Style = $style } } } @@ -353,8 +353,8 @@ BeforeAll { } # A later command that fails with a terminating error ends the pipeline for the commands before it. The error is the - # caller's: the cmdlet must neither report it as an error of an item nor go on with the next item. The second style - # raises the type that some catch of the cmdlets handles on its own, for a folder that cannot be read. + # caller's: the cmdlet must neither report it as an error of an item nor go on with the next item. PowerShell wraps + # the exception of a throw, so the cmdlet never sees the type that was thrown. function Assert-DownstreamFailure { param ([string] $Name, [string] $Style) @@ -366,11 +366,8 @@ BeforeAll { try { & $case.Run $context | ForEach-Object -Process { $emitted++ - switch ($Style) { - 'throw' { throw 'Downstream failure' } - 'throw UnauthorizedAccessException' { throw [System.UnauthorizedAccessException]::new('Downstream failure') } - default { Write-Error -Message 'Downstream failure' -ErrorAction Stop } - } + if ($Style -eq 'throw') { throw 'Downstream failure' } + Write-Error -Message 'Downstream failure' -ErrorAction Stop } } catch {