diff --git a/CHANGELOG.md b/CHANGELOG.md index d11fc8f..b4146ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,5 +115,8 @@ The format is based on - Fix `Copy-Item2`, `Move-Item2`, and `Remove-Item2`, which skipped the remaining paths of `-Path` after a path that didn't exist or, for copy and move, a file that already existed at the destination +- Fix `Remove-NTFSAccess` and `Remove-NTFSAudit`, which went on with a path + that didn't exist, wrote a second, misleading `RemoveAceError`, and with + `-PassThru` stopped with a `NullReferenceException` [Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD diff --git a/Docs/Cmdlets/Remove-NTFSAccess.md b/Docs/Cmdlets/Remove-NTFSAccess.md index 9eda4d0..6aa0d3d 100644 --- a/Docs/Cmdlets/Remove-NTFSAccess.md +++ b/Docs/Cmdlets/Remove-NTFSAccess.md @@ -306,6 +306,8 @@ Removing rights from an entry that does not exist is not an error; the cmdlet le Before 5.0.0, the `-RemoveSpecific` switch was missing, although version 4.1 had introduced it. +A path that does not exist produces the non-terminating error `ReadFileError`, and the cmdlet continues with the next path. Before 5.0.0, the cmdlet also wrote a misleading `RemoveAceError` for that path, and with `-PassThru` it stopped with a `NullReferenceException`. + ## RELATED LINKS [Get-NTFSAccess](Get-NTFSAccess.md) diff --git a/Docs/Cmdlets/Remove-NTFSAudit.md b/Docs/Cmdlets/Remove-NTFSAudit.md index 846edeb..c116fa8 100644 --- a/Docs/Cmdlets/Remove-NTFSAudit.md +++ b/Docs/Cmdlets/Remove-NTFSAudit.md @@ -308,6 +308,8 @@ The cmdlet reports no error when no entry matches the supplied values. Compare t Before 5.0.0, the cmdlet had no `-RemoveSpecific` switch. +A path that does not exist produces the non-terminating error `ReadFileError`, and the cmdlet continues with the next path. Before 5.0.0, the cmdlet also wrote a misleading `RemoveAceError` for that path, and with `-PassThru` it stopped with a `NullReferenceException`. + ## RELATED LINKS [Get-NTFSAudit](Get-NTFSAudit.md) diff --git a/NTFSSecurity/AccessCmdlets/RemoveAccess.cs b/NTFSSecurity/AccessCmdlets/RemoveAccess.cs index 4ed939a..5115150 100644 --- a/NTFSSecurity/AccessCmdlets/RemoveAccess.cs +++ b/NTFSSecurity/AccessCmdlets/RemoveAccess.cs @@ -138,6 +138,7 @@ namespace NTFSSecurity catch (Exception ex) { WriteError(new ErrorRecord(ex, "ReadFileError", ErrorCategory.OpenError, path)); + continue; } if (ParameterSetName == "PathSimple") diff --git a/NTFSSecurity/AuditCmdlets/RemoveAudit.cs b/NTFSSecurity/AuditCmdlets/RemoveAudit.cs index d4a738d..9a4e3dc 100644 --- a/NTFSSecurity/AuditCmdlets/RemoveAudit.cs +++ b/NTFSSecurity/AuditCmdlets/RemoveAudit.cs @@ -137,6 +137,7 @@ namespace NTFSSecurity catch (Exception ex) { WriteError(new ErrorRecord(ex, "ReadFileError", ErrorCategory.OpenError, path)); + continue; } if (ParameterSetName == "PathSimple") diff --git a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml index 957a61d..1958dd4 100644 --- a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml +++ b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml @@ -8385,6 +8385,7 @@ PS C:\Data> Get-NTFSSecurityDescriptor If the ACL of an item cannot be written because access is denied, the cmdlet tries once more after making the current account the owner of the item, and restores the previous owner afterwards. Changing the owner of an item requires the Take Ownership and Restore privileges, so this fallback only succeeds in an elevated session of an account that holds them. Removing rights from an entry that does not exist is not an error; the cmdlet leaves the ACL unchanged. Before 5.0.0, the `-RemoveSpecific` switch was missing, although version 4.1 had introduced it. + A path that does not exist produces the non-terminating error `ReadFileError`, and the cmdlet continues with the next path. Before 5.0.0, the cmdlet also wrote a misleading `RemoveAceError` for that path, and with `-PassThru` it stopped with a `NullReferenceException`. @@ -9224,6 +9225,7 @@ PS C:\Data> Get-NTFSSecurityDescriptor If the security descriptor cannot be read or written because access is denied, the cmdlet takes ownership of the item, repeats the operation, and restores the previous owner. If the second attempt fails as well, the cmdlet writes an error, and the ownership change is not rolled back. The cmdlet reports no error when no entry matches the supplied values. Compare the result with `Get-NTFSAudit` to confirm that the entry is gone. Before 5.0.0, the cmdlet had no `-RemoveSpecific` switch. + A path that does not exist produces the non-terminating error `ReadFileError`, and the cmdlet continues with the next path. Before 5.0.0, the cmdlet also wrote a misleading `RemoveAceError` for that path, and with `-PassThru` it stopped with a `NullReferenceException`. diff --git a/Tests/Access.Tests.ps1 b/Tests/Access.Tests.ps1 index 6ebe074..11b11c8 100644 --- a/Tests/Access.Tests.ps1 +++ b/Tests/Access.Tests.ps1 @@ -149,6 +149,25 @@ Describe 'Get-NTFSSimpleAccess' { } Describe 'Remove-NTFSAccess' { + Context 'When a path does not exist' { + BeforeAll { + $missing = Join-Path -Path $sandbox -ChildPath 'Missing.txt' + } + + # Before 5.0.0, the cmdlet went on with the missing item and wrote a second, misleading RemoveAceError. + It 'Should write only the read error' { + Remove-NTFSAccess -Path $missing -Account 'Everyone' -AccessRights ReadData -ErrorVariable removeErrors -ErrorAction SilentlyContinue + + $removeErrors | Should -HaveCount 1 + $removeErrors[0].FullyQualifiedErrorId | Should -BeLike 'ReadFileError,*' + } + + It 'Should not stop with -PassThru' { + { Remove-NTFSAccess -Path $missing -Account 'Everyone' -AccessRights ReadData -PassThru -ErrorAction SilentlyContinue } | + Should -Not -Throw + } + } + Context 'With -RemoveSpecific' { BeforeEach { $removeFolder = New-TestSandboxItem -Sandbox $sandbox -Name 'RemoveSpecific' -Directory diff --git a/Tests/Audit.Tests.ps1 b/Tests/Audit.Tests.ps1 index 8797303..7345e13 100644 --- a/Tests/Audit.Tests.ps1 +++ b/Tests/Audit.Tests.ps1 @@ -148,6 +148,25 @@ Describe 'Get-NTFSOrphanedAudit' { } Describe 'Remove-NTFSAudit' { + Context 'When a path does not exist' { + BeforeAll { + $missing = Join-Path -Path $sandbox -ChildPath 'Missing.txt' + } + + # Before 5.0.0, the cmdlet went on with the missing item and wrote a second, misleading RemoveAceError. + It 'Should write only the read error' { + Remove-NTFSAudit -Path $missing -Account 'Everyone' -AccessRights ReadData -ErrorVariable removeErrors -ErrorAction SilentlyContinue + + $removeErrors | Should -HaveCount 1 + $removeErrors[0].FullyQualifiedErrorId | Should -BeLike 'ReadFileError,*' + } + + It 'Should not stop with -PassThru' { + { Remove-NTFSAudit -Path $missing -Account 'Everyone' -AccessRights ReadData -PassThru -ErrorAction SilentlyContinue } | + Should -Not -Throw + } + } + Context 'With -RemoveSpecific' { BeforeEach { $removeFolder = New-TestSandboxItem -Sandbox $sandbox -Name 'RemoveSpecific' -Directory