Browse Source

fix: restore -RemoveSpecific in Remove-NTFSAccess and Remove-NTFSAudit

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>
pull/101/head
Raimund Andree 7 days ago
parent
commit
9fc4959ce2
  1. 3
      CHANGELOG.md
  2. 30
      Docs/Cmdlets/Remove-NTFSAccess.md
  3. 30
      Docs/Cmdlets/Remove-NTFSAudit.md
  4. 18
      NTFSSecurity/AccessCmdlets/RemoveAccess.cs
  5. 18
      NTFSSecurity/AuditCmdlets/RemoveAudit.cs
  6. 118
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  7. 2
      Security2/FileSystem/FileSystemAccessRule2 Class/FileSystemAccessRule2.RemoveFileSystemAccessRules.cs
  8. 16
      Security2/FileSystem/FileSystemAuditRule2 Class/FileSystemAuditRule2.RemoveFileSystemAuditRule.cs
  9. 35
      Tests/Access.Tests.ps1
  10. 25
      Tests/Audit.Tests.ps1

3
CHANGELOG.md

@ -109,5 +109,8 @@ The format is based on
collection per item, `Get-NTFSOrphanedAccess` no longer repeats the entries
of the previous item after a failed read, and the output of
`Get-NTFSSimpleAccess` has a table view
- Restore the `-RemoveSpecific` switch of `Remove-NTFSAccess`, which version
4.1 introduced but later versions lacked, and add it to `Remove-NTFSAudit`:
with it, the cmdlets remove only an entry that matches exactly
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

30
Docs/Cmdlets/Remove-NTFSAccess.md

@ -17,34 +17,34 @@ Removes rights from the access control entries (ACEs) of a file, a folder, or a
```
Remove-NTFSAccess [-Path] <String[]> [-Account] <IdentityReference2[]> [-AccessRights] <FileSystemRights2>
[-AccessType <AccessControlType>] [-InheritanceFlags <InheritanceFlags>]
[-PropagationFlags <PropagationFlags>] [-PassThru] [<CommonParameters>]
[-PropagationFlags <PropagationFlags>] [-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
### PathSimple
```
Remove-NTFSAccess [-Path] <String[]> [-Account] <IdentityReference2[]> [-AccessRights] <FileSystemRights2>
[-AccessType <AccessControlType>] -AppliesTo <ApplyTo> [-PassThru] [<CommonParameters>]
[-AccessType <AccessControlType>] -AppliesTo <ApplyTo> [-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
### SDSimple
```
Remove-NTFSAccess [-SecurityDescriptor] <FileSystemSecurity2[]> [-Account] <IdentityReference2[]>
[-AccessRights] <FileSystemRights2> [-AccessType <AccessControlType>] -AppliesTo <ApplyTo> [-PassThru]
[<CommonParameters>]
[-AccessRights] <FileSystemRights2> [-AccessType <AccessControlType>] -AppliesTo <ApplyTo> [-RemoveSpecific]
[-PassThru] [<CommonParameters>]
```
### SDComplex
```
Remove-NTFSAccess [-SecurityDescriptor] <FileSystemSecurity2[]> [-Account] <IdentityReference2[]>
[-AccessRights] <FileSystemRights2> [-AccessType <AccessControlType>] [-InheritanceFlags <InheritanceFlags>]
[-PropagationFlags <PropagationFlags>] [-PassThru] [<CommonParameters>]
[-PropagationFlags <PropagationFlags>] [-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
## DESCRIPTION
Removes the rights in `-AccessRights` from the access control entries (ACEs) of a file or a folder. An entry is addressed by the account in `-Account`, the access type in `-AccessType`, and the inheritance and propagation flags, which are given either as `-AppliesTo` or as `-InheritanceFlags` and `-PropagationFlags`.
Only the specified rights are taken away: when an entry grants more than `-AccessRights` names, the remaining rights stay in place, and the entry disappears only when all of its rights are removed. An `Allow` entry is always matched with the `Synchronize` right added to the specified rights. The flags must describe the entry as it exists on the item; when they do not, Windows splits the entry instead of removing the rights, so use the values that `Get-NTFSAccess` reports for the entry you want to change.
Only the specified rights are taken away: when an entry grants more than `-AccessRights` names, the remaining rights stay in place, and the entry disappears only when all of its rights are removed. An `Allow` entry is always matched with the `Synchronize` right added to the specified rights. The flags must describe the entry as it exists on the item; when they do not, Windows splits the entry instead of removing the rights, so use the values that `Get-NTFSAccess` reports for the entry you want to change. With `-RemoveSpecific`, the cmdlet removes only an entry that matches exactly.
Inherited entries cannot be removed from the item that inherits them. Remove them from the folder named in the `InheritedFrom` property, or run `Disable-NTFSAccessInheritance` on the item first, which copies the inherited entries into it as explicit ones that this cmdlet can then remove.
@ -237,6 +237,22 @@ Accept pipeline input: True (ByPropertyName, ByValue)
Accept wildcard characters: False
```
### -RemoveSpecific
Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
@ -288,6 +304,8 @@ If the ACL of an item cannot be written because access is denied, the cmdlet tri
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.
## RELATED LINKS
[Get-NTFSAccess](Get-NTFSAccess.md)

30
Docs/Cmdlets/Remove-NTFSAudit.md

@ -17,32 +17,32 @@ Removes an audit entry from a file or folder.
```
Remove-NTFSAudit [-Path] <String[]> [-Account] <IdentityReference2[]> [-AccessRights] <FileSystemRights2>
[-AuditFlags <AuditFlags>] [-InheritanceFlags <InheritanceFlags>] [-PropagationFlags <PropagationFlags>]
[-PassThru] [<CommonParameters>]
[-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
### PathSimple
```
Remove-NTFSAudit [-Path] <String[]> [-Account] <IdentityReference2[]> [-AccessRights] <FileSystemRights2>
[-AuditFlags <AuditFlags>] -AppliesTo <ApplyTo> [-PassThru] [<CommonParameters>]
[-AuditFlags <AuditFlags>] -AppliesTo <ApplyTo> [-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
### SDSimple
```
Remove-NTFSAudit [-SecurityDescriptor] <FileSystemSecurity2[]> [-Account] <IdentityReference2[]>
[-AccessRights] <FileSystemRights2> [-AuditFlags <AuditFlags>] -AppliesTo <ApplyTo> [-PassThru]
[<CommonParameters>]
[-AccessRights] <FileSystemRights2> [-AuditFlags <AuditFlags>] -AppliesTo <ApplyTo> [-RemoveSpecific]
[-PassThru] [<CommonParameters>]
```
### SDComplex
```
Remove-NTFSAudit [-SecurityDescriptor] <FileSystemSecurity2[]> [-Account] <IdentityReference2[]>
[-AccessRights] <FileSystemRights2> [-AuditFlags <AuditFlags>] [-InheritanceFlags <InheritanceFlags>]
[-PropagationFlags <PropagationFlags>] [-PassThru] [<CommonParameters>]
[-PropagationFlags <PropagationFlags>] [-RemoveSpecific] [-PassThru] [<CommonParameters>]
```
## DESCRIPTION
The `Remove-NTFSAudit` cmdlet removes an audit entry from the system access control list (SACL) of a file or folder. The cmdlet builds an audit entry from `-Account`, `-AccessRights`, `-AuditFlags`, and the inheritance and propagation flags, and removes that entry from the SACL. The audit entries of the account are matched by their inheritance and propagation flags, and the requested access rights and audit flags are then taken away from them: an entry that audits further rights keeps those rights and disappears only when nothing is left. To remove an entry completely, pass the same values that `Get-NTFSAudit` reports for it.
The `Remove-NTFSAudit` cmdlet removes an audit entry from the system access control list (SACL) of a file or folder. The cmdlet builds an audit entry from `-Account`, `-AccessRights`, `-AuditFlags`, and the inheritance and propagation flags, and removes that entry from the SACL. The audit entries of the account are matched by their inheritance and propagation flags, and the requested access rights and audit flags are then taken away from them: an entry that audits further rights keeps those rights and disappears only when nothing is left. To remove an entry completely, pass the same values that `Get-NTFSAudit` reports for it. With `-RemoveSpecific`, the cmdlet removes only an entry that matches exactly.
Because the inheritance and propagation flags take part in the match, they must describe the entry you want to remove. `-AppliesTo ThisFolderOnly` removes an entry that is not inherited by child items, which is also the shape of every audit entry on a file, while the default of the complex parameter sets removes an entry that applies to the folder, its subfolders, and its files. An entry that an item inherits from a parent folder is stored on that parent, so remove it there, or use `Clear-NTFSAudit` with `-DisableInheritance` to drop the inherited entries on the item.
@ -237,6 +237,22 @@ Accept pipeline input: True (ByPropertyName, ByValue)
Accept wildcard characters: False
```
### -RemoveSpecific
Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
@ -290,6 +306,8 @@ If the security descriptor cannot be read or written because access is denied, t
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.
## RELATED LINKS
[Get-NTFSAudit](Get-NTFSAudit.md)

18
NTFSSecurity/AccessCmdlets/RemoveAccess.cs

@ -16,7 +16,7 @@ namespace NTFSSecurity
private AccessControlType accessType = AccessControlType.Allow;
private InheritanceFlags inheritanceFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
private PropagationFlags propagationFlags = PropagationFlags.None;
private ApplyTo appliesTo;
private ApplyTo appliesTo = ApplyTo.ThisFolderSubfoldersAndFiles;
private bool removeSpecific;
private bool passThru;
@ -96,6 +96,16 @@ namespace NTFSSecurity
set { appliesTo = value; }
}
/// <summary>
/// Removes only an entry that matches exactly, instead of taking the rights away from matching entries.
/// </summary>
[Parameter]
public SwitchParameter RemoveSpecific
{
get { return removeSpecific; }
set { removeSpecific = value; }
}
[Parameter]
public SwitchParameter PassThru
{
@ -137,7 +147,7 @@ namespace NTFSSecurity
try
{
FileSystemAccessRule2.RemoveFileSystemAccessRule(item, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags);
FileSystemAccessRule2.RemoveFileSystemAccessRule(item, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags, removeSpecific);
}
catch (UnauthorizedAccessException)
{
@ -148,7 +158,7 @@ namespace NTFSSecurity
FileSystemOwner.SetOwner(item, System.Security.Principal.WindowsIdentity.GetCurrent().User);
FileSystemAccessRule2.RemoveFileSystemAccessRule(item, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags);
FileSystemAccessRule2.RemoveFileSystemAccessRule(item, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags, removeSpecific);
FileSystemOwner.SetOwner(item, previousOwner);
}
@ -172,7 +182,7 @@ namespace NTFSSecurity
{
foreach (var sd in securityDescriptors)
{
FileSystemAccessRule2.RemoveFileSystemAccessRule(sd, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags);
FileSystemAccessRule2.RemoveFileSystemAccessRule(sd, account.ToList(), accessRights, accessType, inheritanceFlags, propagationFlags, removeSpecific);
if (passThru == true)
{

18
NTFSSecurity/AuditCmdlets/RemoveAudit.cs

@ -16,7 +16,7 @@ namespace NTFSSecurity
private AuditFlags auditFlags = AuditFlags.Failure | AuditFlags.Success;
private InheritanceFlags inheritanceFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
private PropagationFlags propagationFlags = PropagationFlags.None;
private ApplyTo appliesTo;
private ApplyTo appliesTo = ApplyTo.ThisFolderSubfoldersAndFiles;
private bool removeSpecific;
private bool passThru;
@ -95,6 +95,16 @@ namespace NTFSSecurity
set { appliesTo = value; }
}
/// <summary>
/// Removes only an entry that matches exactly, instead of taking the rights away from matching entries.
/// </summary>
[Parameter]
public SwitchParameter RemoveSpecific
{
get { return removeSpecific; }
set { removeSpecific = value; }
}
[Parameter]
public SwitchParameter PassThru
{
@ -136,7 +146,7 @@ namespace NTFSSecurity
try
{
FileSystemAuditRule2.RemoveFileSystemAuditRule(item, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags);
FileSystemAuditRule2.RemoveFileSystemAuditRule(item, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags, removeSpecific);
}
catch (UnauthorizedAccessException)
{
@ -147,7 +157,7 @@ namespace NTFSSecurity
FileSystemOwner.SetOwner(item, System.Security.Principal.WindowsIdentity.GetCurrent().User);
FileSystemAuditRule2.RemoveFileSystemAuditRule(item, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags);
FileSystemAuditRule2.RemoveFileSystemAuditRule(item, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags, removeSpecific);
FileSystemOwner.SetOwner(item, previousOwner);
}
@ -171,7 +181,7 @@ namespace NTFSSecurity
{
foreach (var sd in securityDescriptors)
{
FileSystemAuditRule2.RemoveFileSystemAuditRule(sd, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags);
FileSystemAuditRule2.RemoveFileSystemAuditRule(sd, account.ToList(), accessRights, auditFlags, inheritanceFlags, propagationFlags, removeSpecific);
if (passThru == true)
{

118
NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml

@ -7622,7 +7622,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</command:details>
<maml:description>
<maml:para>Removes the rights in `-AccessRights` from the access control entries (ACEs) of a file or a folder. An entry is addressed by the account in `-Account`, the access type in `-AccessType`, and the inheritance and propagation flags, which are given either as `-AppliesTo` or as `-InheritanceFlags` and `-PropagationFlags`.</maml:para>
<maml:para>Only the specified rights are taken away: when an entry grants more than `-AccessRights` names, the remaining rights stay in place, and the entry disappears only when all of its rights are removed. An `Allow` entry is always matched with the `Synchronize` right added to the specified rights. The flags must describe the entry as it exists on the item; when they do not, Windows splits the entry instead of removing the rights, so use the values that `Get-NTFSAccess` reports for the entry you want to change.</maml:para>
<maml:para>Only the specified rights are taken away: when an entry grants more than `-AccessRights` names, the remaining rights stay in place, and the entry disappears only when all of its rights are removed. An `Allow` entry is always matched with the `Synchronize` right added to the specified rights. The flags must describe the entry as it exists on the item; when they do not, Windows splits the entry instead of removing the rights, so use the values that `Get-NTFSAccess` reports for the entry you want to change. With `-RemoveSpecific`, the cmdlet removes only an entry that matches exactly.</maml:para>
<maml:para>Inherited entries cannot be removed from the item that inherits them. Remove them from the folder named in the `InheritedFrom` property, or run `Disable-NTFSAccessInheritance` on the item first, which copies the inherited entries into it as explicit ones that this cmdlet can then remove.</maml:para>
<maml:para>The cmdlet has four parameter sets. The `Path` sets read the item from disk and write the changed DACL back immediately, while the `SD` sets change a `Security2.FileSystemSecurity2` object returned by `Get-NTFSSecurityDescriptor` in memory until `Set-NTFSSecurityDescriptor` writes it back. The `Simple` sets take `-AppliesTo`, the `Complex` sets take `-InheritanceFlags` and `-PropagationFlags`, and `PathComplex` is the default. A command without `-AppliesTo` uses a `Complex` set, also when it works on a security descriptor. Before 5.0.0, a command that used `-SecurityDescriptor` without `-AppliesTo`, `-InheritanceFlags`, or `-PropagationFlags` failed, because PowerShell couldn't choose between the two `SD` sets. All relevant parameters bind by property name, so the output of `Get-NTFSAccess` and `Get-NTFSOrphanedAccess` can be piped directly into this cmdlet. The cmdlet writes no output unless `-PassThru` is used.</maml:para>
</maml:description>
@ -7749,6 +7749,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAccess</maml:name>
@ -7873,6 +7884,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAccess</maml:name>
@ -8003,6 +8025,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAccess</maml:name>
@ -8134,6 +8167,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
</command:syntax>
<command:parameters>
@ -8246,6 +8290,18 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an entry that matches the account, the access rights, the access type, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights away from the matching entries.</maml:para>
</maml:description>
<command:parameterValue required="false" variableLength="false">SwitchParameter</command:parameterValue>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:parameters>
<command:inputTypes>
<command:inputType>
@ -8328,6 +8384,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<maml:para>When the module setting `EnablePrivileges` is `$true` (the default in the `PrivateData` section of NTFSSecurity.psd1), this cmdlet tries to enable the Backup, Restore, Take Ownership, and Security privileges while it runs and disables the privileges it enabled when it finishes. These privileges are only available in an elevated session of an account that holds them, such as a member of the local Administrators group. If a privilege cannot be enabled, the cmdlet continues without it and writes a debug message.</maml:para>
<maml:para>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.</maml:para>
<maml:para>Removing rights from an entry that does not exist is not an error; the cmdlet leaves the ACL unchanged.</maml:para>
<maml:para>Before 5.0.0, the `-RemoveSpecific` switch was missing, although version 4.1 had introduced it.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>
@ -8401,7 +8458,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</maml:description>
</command:details>
<maml:description>
<maml:para>The `Remove-NTFSAudit` cmdlet removes an audit entry from the system access control list (SACL) of a file or folder. The cmdlet builds an audit entry from `-Account`, `-AccessRights`, `-AuditFlags`, and the inheritance and propagation flags, and removes that entry from the SACL. The audit entries of the account are matched by their inheritance and propagation flags, and the requested access rights and audit flags are then taken away from them: an entry that audits further rights keeps those rights and disappears only when nothing is left. To remove an entry completely, pass the same values that `Get-NTFSAudit` reports for it.</maml:para>
<maml:para>The `Remove-NTFSAudit` cmdlet removes an audit entry from the system access control list (SACL) of a file or folder. The cmdlet builds an audit entry from `-Account`, `-AccessRights`, `-AuditFlags`, and the inheritance and propagation flags, and removes that entry from the SACL. The audit entries of the account are matched by their inheritance and propagation flags, and the requested access rights and audit flags are then taken away from them: an entry that audits further rights keeps those rights and disappears only when nothing is left. To remove an entry completely, pass the same values that `Get-NTFSAudit` reports for it. With `-RemoveSpecific`, the cmdlet removes only an entry that matches exactly.</maml:para>
<maml:para>Because the inheritance and propagation flags take part in the match, they must describe the entry you want to remove. `-AppliesTo ThisFolderOnly` removes an entry that is not inherited by child items, which is also the shape of every audit entry on a file, while the default of the complex parameter sets removes an entry that applies to the folder, its subfolders, and its files. An entry that an item inherits from a parent folder is stored on that parent, so remove it there, or use `Clear-NTFSAudit` with `-DisableInheritance` to drop the inherited entries on the item.</maml:para>
<maml:para>In the `PathSimple` and `PathComplex` parameter sets the cmdlet reads the security descriptor of every item in `-Path` and writes it back right away. In the `SDSimple` and `SDComplex` parameter sets it changes an in-memory `Security2.FileSystemSecurity2` object that `Get-NTFSSecurityDescriptor` returned, and the change reaches the file system only when you pass the object to `Set-NTFSSecurityDescriptor`. `PathComplex` is the default parameter set. A command without `-AppliesTo` uses a `Complex` set, also when it works on a security descriptor. Before 5.0.0, a command that used `-SecurityDescriptor` without `-AppliesTo`, `-InheritanceFlags`, or `-PropagationFlags` failed, because PowerShell couldn't choose between the two `SD` sets.</maml:para>
<maml:para>When you omit them, `-AuditFlags` is `Success, Failure`, `-InheritanceFlags` is `ContainerInherit, ObjectInherit`, `-PropagationFlags` is `None`. All parameters bind by property name, and `-Path` also binds by value and through its `FullName` alias, so you can pipe the output of `Get-NTFSAudit`, `Get-ChildItem`, `Get-ChildItem2`, and `Get-Item2` into the cmdlet. The cmdlet writes no object unless you use `-PassThru`.</maml:para>
@ -8530,6 +8587,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAudit</maml:name>
@ -8654,6 +8722,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAudit</maml:name>
@ -8785,6 +8864,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Remove-NTFSAudit</maml:name>
@ -8916,6 +9006,17 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.</maml:para>
</maml:description>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:syntaxItem>
</command:syntax>
<command:parameters>
@ -9027,6 +9128,18 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="False" position="named" aliases="none">
<maml:name>RemoveSpecific</maml:name>
<maml:description>
<maml:para>Indicates that the cmdlet removes only an audit entry that matches the account, the access rights, the audit flags, and the inheritance and propagation flags exactly, and leaves all other entries unchanged. Without this switch, the cmdlet takes the specified rights and audit flags away from the matching entries.</maml:para>
</maml:description>
<command:parameterValue required="false" variableLength="false">SwitchParameter</command:parameterValue>
<dev:type>
<maml:name>SwitchParameter</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>False</dev:defaultValue>
</command:parameter>
</command:parameters>
<command:inputTypes>
<command:inputType>
@ -9110,6 +9223,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<maml:para>Reading and writing the SACL requires the Security privilege (`SeSecurityPrivilege`, "Manage auditing and security log"), so run this cmdlet in an elevated session of an account that holds that privilege. Without it, the cmdlet writes a non-terminating `RemoveAceError` whose message states that a required privilege is not held by the client, and the item is left unchanged.</maml:para>
<maml:para>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.</maml:para>
<maml:para>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.</maml:para>
<maml:para>Before 5.0.0, the cmdlet had no `-RemoveSpecific` switch.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>

2
Security2/FileSystem/FileSystemAccessRule2 Class/FileSystemAccessRule2.RemoveFileSystemAccessRules.cs

@ -137,7 +137,7 @@ namespace Security2
foreach (var account in accounts)
{
aces.Add(RemoveFileSystemAccessRule(sd, account, rights, type, inheritanceFlags, propagationFlags));
aces.Add(RemoveFileSystemAccessRule(sd, account, rights, type, inheritanceFlags, propagationFlags, removeSpecific));
}
return aces;

16
Security2/FileSystem/FileSystemAuditRule2 Class/FileSystemAuditRule2.RemoveFileSystemAuditRule.cs

@ -6,7 +6,7 @@ namespace Security2
{
public partial class FileSystemAuditRule2
{
public static void RemoveFileSystemAuditRule(FileSystemInfo item, IdentityReference2 account, FileSystemRights2 rights, AuditFlags type, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags)
public static void RemoveFileSystemAuditRule(FileSystemInfo item, IdentityReference2 account, FileSystemRights2 rights, AuditFlags type, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, bool removeSpecific = false)
{
FileSystemAuditRule ace = null;
@ -17,7 +17,10 @@ namespace Security2
ace = (FileSystemAuditRule)sd.AuditRuleFactory(account, (int)rights, false, inheritanceFlags, propagationFlags, type);
sd.RemoveAuditRule(ace);
if (removeSpecific)
sd.RemoveAuditRuleSpecific(ace);
else
sd.RemoveAuditRule(ace);
file.SetAccessControl(sd);
}
@ -28,7 +31,10 @@ namespace Security2
var sd = directory.GetAccessControl(AccessControlSections.Audit);
ace = (FileSystemAuditRule)sd.AuditRuleFactory(account, (int)rights, false, inheritanceFlags, propagationFlags, type);
sd.RemoveAuditRule(ace);
if (removeSpecific)
sd.RemoveAuditRuleSpecific(ace);
else
sd.RemoveAuditRule(ace);
directory.SetAccessControl(sd);
}
@ -38,7 +44,7 @@ namespace Security2
{
foreach (var account in accounts)
{
RemoveFileSystemAuditRule(item, account, rights, type, inheritanceFlags, propagationFlags);
RemoveFileSystemAuditRule(item, account, rights, type, inheritanceFlags, propagationFlags, removeSpecific);
}
}
@ -106,7 +112,7 @@ namespace Security2
foreach (var account in accounts)
{
aces.Add(RemoveFileSystemAuditRule(sd, account, rights, type, inheritanceFlags, propagationFlags));
aces.Add(RemoveFileSystemAuditRule(sd, account, rights, type, inheritanceFlags, propagationFlags, removeSpecific));
}
return aces;

35
Tests/Access.Tests.ps1

@ -148,6 +148,41 @@ Describe 'Get-NTFSSimpleAccess' {
}
}
Describe 'Remove-NTFSAccess' {
Context 'With -RemoveSpecific' {
BeforeEach {
$removeFolder = New-TestSandboxItem -Sandbox $sandbox -Name 'RemoveSpecific' -Directory
$sd = Get-NTFSSecurityDescriptor -Path $removeFolder
Add-NTFSAccess -SecurityDescriptor $sd -Account 'Everyone' -AccessRights Modify
function Get-EveryoneRule {
$sd.SecurityDescriptor.GetAccessRules($true, $false, [System.Security.Principal.SecurityIdentifier]) |
Where-Object -FilterScript { $_.IdentityReference.Value -eq 'S-1-1-0' }
}
}
It 'Should keep an entry that does not match exactly' {
Remove-NTFSAccess -SecurityDescriptor $sd -Account 'Everyone' -AccessRights ReadData -RemoveSpecific
(Get-EveryoneRule).FileSystemRights.HasFlag([System.Security.AccessControl.FileSystemRights]::Modify) | Should -BeTrue
}
It 'Should remove an entry that matches exactly' {
Remove-NTFSAccess -SecurityDescriptor $sd -Account 'Everyone' -AccessRights Modify -RemoveSpecific
Get-EveryoneRule | Should -BeNullOrEmpty
}
It 'Should take the rights away from a matching entry without -RemoveSpecific' {
Remove-NTFSAccess -SecurityDescriptor $sd -Account 'Everyone' -AccessRights ReadData
$rule = Get-EveryoneRule
$rule | Should -Not -BeNullOrEmpty
$rule.FileSystemRights.HasFlag([System.Security.AccessControl.FileSystemRights]::ReadData) | Should -BeFalse
}
}
}
Describe 'Security descriptor parameter sets' {
BeforeAll {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'ParameterSets' -Directory

25
Tests/Audit.Tests.ps1

@ -148,6 +148,31 @@ Describe 'Get-NTFSOrphanedAudit' {
}
Describe 'Remove-NTFSAudit' {
Context 'With -RemoveSpecific' {
BeforeEach {
$removeFolder = New-TestSandboxItem -Sandbox $sandbox -Name 'RemoveSpecific' -Directory
$sd = Get-NTFSSecurityDescriptor -Path $removeFolder
Add-NTFSAudit -SecurityDescriptor $sd -Account 'Everyone' -AccessRights Modify
function Get-EveryoneAuditRule {
$sd.SecurityDescriptor.GetAuditRules($true, $false, [System.Security.Principal.SecurityIdentifier]) |
Where-Object -FilterScript { $_.IdentityReference.Value -eq 'S-1-1-0' }
}
}
It 'Should keep an audit entry that does not match exactly' {
Remove-NTFSAudit -SecurityDescriptor $sd -Account 'Everyone' -AccessRights ReadData -RemoveSpecific
(Get-EveryoneAuditRule).FileSystemRights.HasFlag([System.Security.AccessControl.FileSystemRights]::Modify) | Should -BeTrue
}
It 'Should remove an audit entry that matches exactly' {
Remove-NTFSAudit -SecurityDescriptor $sd -Account 'Everyone' -AccessRights Modify -RemoveSpecific
Get-EveryoneAuditRule | Should -BeNullOrEmpty
}
}
Context 'With -PassThru' {
It 'Should return the audit entries of the item, not its access entries' -Skip:(-not $canReadAudit) {
$file = New-TestSandboxItem -Sandbox $sandbox -Name 'PassThru'

Loading…
Cancel
Save