Browse Source

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 <ai@example.com>
pull/118/head
Raimund Andree 2 days ago
parent
commit
7aa8315ce1
  1. 2
      NTFSSecurity/ItemCmdlets/GetChildItem2.cs
  2. 15
      Tests/PipelineControl.Tests.ps1

2
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)); WriteError(new ErrorRecord(ex, "DirUnauthorizedAccessError", ErrorCategory.PermissionDenied, di.FullName));
} }

15
Tests/PipelineControl.Tests.ps1

@ -43,12 +43,12 @@ BeforeDiscovery {
@{ Name = $name } @{ Name = $name }
} }
$failureCases = foreach ($name in $names) { $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 } @{ Name = $name; Style = $style }
} }
} }
$auditFailureCases = foreach ($name in $auditNames) { $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 } @{ 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 # 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 # caller's: the cmdlet must neither report it as an error of an item nor go on with the next item. PowerShell wraps
# raises the type that some catch of the cmdlets handles on its own, for a folder that cannot be read. # the exception of a throw, so the cmdlet never sees the type that was thrown.
function Assert-DownstreamFailure { function Assert-DownstreamFailure {
param ([string] $Name, [string] $Style) param ([string] $Name, [string] $Style)
@ -366,11 +366,8 @@ BeforeAll {
try { try {
& $case.Run $context | ForEach-Object -Process { & $case.Run $context | ForEach-Object -Process {
$emitted++ $emitted++
switch ($Style) { if ($Style -eq 'throw') { throw 'Downstream failure' }
'throw' { throw 'Downstream failure' } Write-Error -Message 'Downstream failure' -ErrorAction Stop
'throw UnauthorizedAccessException' { throw [System.UnauthorizedAccessException]::new('Downstream failure') }
default { Write-Error -Message 'Downstream failure' -ErrorAction Stop }
}
} }
} }
catch { catch {

Loading…
Cancel
Save