- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The access and audit cmdlets wrote the owner of an item back with the
entries they changed. For a DACL without the auto-inherit flag, Windows
returns the owner and the group even when only the DACL is read, and the
cmdlets wrote every section that the descriptor held. Without the Restore
privilege, or on a file server that refuses the owner, the write failed
with error 1307 (#34).
- Add-NTFSAccess, Clear-NTFSAccess, Add-NTFSAudit, and Clear-NTFSAudit
read only the DACL or the SACL. FileSystemSecurity2.Write(),
Remove-NTFSAccess, and Remove-NTFSAudit write only the sections they
read, which also fixes the access inheritance cmdlets.
- Read together with the SACL, the inherited entries of such a DACL lose
their inherited flag when the parent folder has no SACL, and the
cmdlets stored them as explicit copies. Get-NTFSSecurityDescriptor now
reads the DACL in a separate call.
- Set-NTFSSecurityDescriptor writes only the sections that changed since
they were read; an unchanged descriptor writes nothing (maintainer
decision of 2026-10-06).
- Clear-NTFSAudit writes nothing for an item without a SACL, and reports
an error without the Security privilege (maintainer decision).
The regression tests failed before and pass after the fix in Windows
PowerShell 5.1 and PowerShell 7, elevated and as a basic user.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The fix for #17 stopped adding Synchronize to an Allow rule with generic
rights, which bypassed the exact match of FileSystemSecurity.RemoveAccessRule:
-AccessRights GenericAll left a Synchronize-only entry behind when the entry
also had Synchronize. RemoveRule now does what FileSystemSecurity does,
without its validation: it removes a rule that matches an entry exactly as it
is, and otherwise without Synchronize. It covers every mask that .NET
rejects, not only the generic rights. The tests cover -RemoveSpecific, a
Deny entry, a partial generic mask, and that nothing else is removed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
FileSystemSecurity.RemoveAccessRule rebuilds a rule that doesn't match an
entry exactly and rejects generic rights then, so removing an entry with
GENERIC_ALL failed with "The value '269484032' is not valid". Windows keeps
generic rights in the inherit-only entries of folders. Such a rule is now
removed through ModifyAccessRule, without the added Synchronize right
(#17).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Mark the Set-NTFSInheritance change as breaking and warn that scripts that
used it to drop the inherited access entries now leave broader access in
place. Report any failure to create the hash algorithm as
HashAlgorithmNotAvailable, assert that error ID, check that the
MACTripleDES warning appears once, and guard the descriptor test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The message overloads of BaseCmdletWithPrivControl hide the methods of
Cmdlet, so every message went through string.Format, also one without
arguments. A path with braces in it, such as C:\Data\{Archive}, then
stopped the cmdlet with a FormatException (#3).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The behavior stays: the cmdlet removes the explicit entries and disables
inheritance without copying the inherited ones. The parameter text now
states the empty DACL and its risk, and a test pins the behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Copy-Item2 and Move-Item2 named the source path as the destination,
Disable-Privileges said that the privileges were now enabled, and the
warning of Get-NTFSEffectiveAccess misspelled the privilege.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The cmdlets that take ownership of an item to repeat a denied operation
left the account that ran them as the owner when the second attempt failed
as well. BaseCmdlet.InvokeAsOwner now restores the previous owner on every
exit path and reports a failed restore as RestoreOwnerError.
Add-NTFSAccess, Add-NTFSAudit, Remove-NTFSAccess, and Remove-NTFSAudit
wrote the unchanged entries of an item with -PassThru after a failed
change; they now continue with the next path.
The inheritance tests assert the error identity and cover a missing path
on every runner.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Defect 19, and the same gap in Remove-NTFSAudit. After the ReadFileError
for a path that doesn't exist, both cmdlets went on with a null item: the
removal failed with a NullReferenceException that they reported as a
second, misleading RemoveAceError, and with -PassThru the null item
stopped the command. Both now continue with the next path.
Tests: Access.Tests.ps1 and Audit.Tests.ps1, 2 tests each.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Defect 17. Both cmdlets carried a removeSpecific field that no parameter
set, so they always took the rights away from matching entries; the
version history documents a -RemoveSpecific switch since 4.1. Both
cmdlets now have the switch, which removes only an entry that matches
exactly. The Security2 list overloads didn't pass the flag on, and the
audit item overload didn't support it; all overloads now do.
The applies-to field of both cmdlets is initialized; -AppliesTo is
mandatory in the Simple sets since defect 14, so it is always set when
used.
Tests: Access.Tests.ps1 3 tests, Audit.Tests.ps1 2 tests, on in-memory
security descriptors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Defect 16. Get-NTFSOrphanedAccess, Get-NTFSOrphanedAudit, and
Get-NTFSSimpleAccess inherit -Account and -SecurityDescriptor from
Get-NTFSAccess or Get-NTFSAudit but override ProcessRecord without them:
- All three now filter by -Account and process security descriptors
(Get-NTFSOrphanedAudit writes an error for one read without its SACL,
like Get-NTFSAudit).
- Get-NTFSOrphanedAudit wrote the entries of each item as one collection;
it now writes one object per entry.
- Get-NTFSOrphanedAccess kept the entries of the previous item and wrote
them in a finally block, like Get-NTFSAccess before; each item now
starts empty.
- SimpleFileSystemAccessRule had no view; it gets a table with Account,
Access Rights, and Type, grouped by folder, with the grouping control
that existed for it but was unused.
Tests: Access.Tests.ps1 6 tests; Audit.Tests.ps1 2 tests, CI-only because
they add audit entries.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Defect 15, all three parts:
- -ExcludeNoneAccessEntries had no effect: the result was written in a
finally block, so "continue" didn't skip it, and the check compared the
rights with None although .NET adds Synchronize to every allow rule. A
result is now written only after the checks, and Synchronize alone
counts as no access.
- Without -Path, BeginProcessing tested the path list for null, which it
never is, so the cmdlet wrote nothing. It now uses the current location,
like the other cmdlets.
- ProcessRecord ignored the SecurityDescriptor parameter set. A new
EffectiveAccess overload computes the effective access from an
in-memory security descriptor; the item overload uses it.
The Security privilege state that selects the error message was read into
a local variable that hid the field; the field is now set.
Tests/Access.Tests.ps1: 4 tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Defect 14. Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and
Remove-NTFSAudit have the sets PathSimple, PathComplex, SDSimple, and
SDComplex; the default PathComplex needs -Path. A command with
-SecurityDescriptor and without -AppliesTo, -InheritanceFlags, or
-PropagationFlags matched both SD sets and failed with "Parameter set
cannot be resolved". -AppliesTo is now mandatory in the Simple sets, so
such a command resolves to the Complex set and its default flags
(ContainerInherit, ObjectInherit / None, which is what AppliesTo
ThisFolderSubfoldersAndFiles means), as a command with -Path already did.
With -AppliesTo nothing changes.
The pages say "Required: True" for -AppliesTo and drop its never
reachable defaults; platyPS takes that metadata from the shipped help
file, so the help file was regenerated before the build.
Tests/Access.Tests.ps1: 6 tests on in-memory security descriptors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Found while fixing defect 4: Get-NTFSAccess has the same pattern as
Get-NTFSAudit. It kept the entries of the previous item and wrote them in
a finally block, so a path whose ACL failed to read returned the previous
item's entries again, next to the error. Each item now starts empty, and
entries are written only after a successful read.
Tests/Access.Tests.ps1 (new): 1 test; it failed before the fix with 6
entries instead of 3.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>