Browse Source

fix: move Add-NTFSAudit -AccessRights to position 3

Defect 5 (#4). -Account and -AccessRights of Add-NTFSAudit were both
declared at position 2, so a positional call failed with "Cannot bind
positional parameters because no names were given". -AccessRights is now
at position 3 in all four parameter sets, like in Remove-NTFSAudit.

The page's parameter metadata says position 3 as well. platyPS takes the
position from Get-Help, that is from the shipped help file, so
Update-MarkdownHelp kept the old value; the page, the regenerated help
file, and the build now agree.

Tests/Audit.Tests.ps1: 5 tests (positions in each parameter set and a
positional call against an in-memory security descriptor).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/100/head
Raimund Andree 1 week ago
parent
commit
ef1d4262e3
  1. 4
      CHANGELOG.md
  2. 4
      Docs/Cmdlets/Add-NTFSAudit.md
  3. 2
      NTFSSecurity/AuditCmdlets/AddAudit.cs
  4. 108
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  5. 27
      Tests/Audit.Tests.ps1

4
CHANGELOG.md

@ -64,5 +64,9 @@ The format is based on
again after a path whose security descriptor it couldn't read
- Fix `Get-NTFSAccess`, which returned the entries of the previous item again
after a path whose ACL it couldn't read
- Fix `Add-NTFSAudit`, whose `-Account` and `-AccessRights` parameters were
both at position 2, so that positional calls failed; `-AccessRights` is
now at position 3, like in `Remove-NTFSAudit`
([#4](https://github.com/raandree/NTFSSecurity/issues/4))
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

4
Docs/Cmdlets/Add-NTFSAudit.md

@ -101,7 +101,7 @@ Aliases: FileSystemRights
Accepted values: None, ReadData, ListDirectory, WriteData, CreateFiles, AppendData, CreateDirectories, ReadExtendedAttributes, WriteExtendedAttributes, ExecuteFile, Traverse, DeleteSubdirectoriesAndFiles, ReadAttributes, WriteAttributes, Write, Delete, ReadPermissions, Read, ReadAndExecute, Modify, ChangePermissions, TakeOwnership, Synchronize, FullControl, GenericAll, GenericExecute, GenericWrite, GenericRead
Required: True
Position: 2
Position: 3
Default value: None
Accept pipeline input: True (ByPropertyName)
Accept wildcard characters: False
@ -290,7 +290,7 @@ Writing the SACL requires the Security privilege (`SeSecurityPrivilege`, "Manage
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 syntax shows `-Path`, `-Account`, and `-AccessRights` as positional parameters, but `-Account` and `-AccessRights` are both declared at position 2. A command that passes them positionally therefore fails with the error that positional parameters cannot be bound because no names were given, and `Get-Command Add-NTFSAudit -Syntax` leaves `-Account` out for the same reason. Pass `-Account` and `-AccessRights` by name, as the examples above do.
`-Path` or `-SecurityDescriptor`, `-Account`, and `-AccessRights` are positional parameters at positions 1, 2, and 3, like in `Remove-NTFSAudit`. Before 5.0.0, `-Account` and `-AccessRights` were both declared at position 2, so a command that passed them by position failed.
An audit entry alone does not create events. Windows writes the events to the security log only while the "Audit object access" policy, or the corresponding "Audit File System" advanced audit policy, is enabled for success, failure, or both. That policy is a Windows setting and is not managed by this module.

2
NTFSSecurity/AuditCmdlets/AddAudit.cs

@ -54,7 +54,7 @@ namespace NTFSSecurity
set { account = value; }
}
[Parameter(Mandatory = true, Position = 2, ValueFromPipelineByPropertyName = true)]
[Parameter(Mandatory = true, Position = 3, ValueFromPipelineByPropertyName = true)]
[Alias("FileSystemRights")]
public FileSystemRights2 AccessRights
{

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

@ -814,7 +814,19 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="FileSystemRights">
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="3" aliases="FileSystemRights">
<maml:name>AccessRights</maml:name>
<maml:description>
<maml:para>Specifies the access rights to audit. The value accepts the basic rights such as `Read`, `Write`, `Modify`, and `FullControl` as well as the individual rights such as `Delete` or `WriteAttributes`, and it accepts a comma-separated list that combines them. For the meaning of each right, see Concepts (../Concepts.md).</maml:para>
@ -856,18 +868,6 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="named" aliases="none">
<maml:name>AppliesTo</maml:name>
<maml:description>
@ -938,7 +938,19 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="FileSystemRights">
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="3" aliases="FileSystemRights">
<maml:name>AccessRights</maml:name>
<maml:description>
<maml:para>Specifies the access rights to audit. The value accepts the basic rights such as `Read`, `Write`, `Modify`, and `FullControl` as well as the individual rights such as `Delete` or `WriteAttributes`, and it accepts a comma-separated list that combines them. For the meaning of each right, see Concepts (../Concepts.md).</maml:para>
@ -980,18 +992,6 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="named" aliases="none">
<maml:name>AppliesTo</maml:name>
<maml:description>
@ -1062,7 +1062,19 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="FileSystemRights">
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="3" aliases="FileSystemRights">
<maml:name>AccessRights</maml:name>
<maml:description>
<maml:para>Specifies the access rights to audit. The value accepts the basic rights such as `Read`, `Write`, `Modify`, and `FullControl` as well as the individual rights such as `Delete` or `WriteAttributes`, and it accepts a comma-separated list that combines them. For the meaning of each right, see Concepts (../Concepts.md).</maml:para>
@ -1104,18 +1116,6 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="named" aliases="none">
<maml:name>AuditFlags</maml:name>
<maml:description>
@ -1193,7 +1193,19 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="FileSystemRights">
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="3" aliases="FileSystemRights">
<maml:name>AccessRights</maml:name>
<maml:description>
<maml:para>Specifies the access rights to audit. The value accepts the basic rights such as `Read`, `Write`, `Modify`, and `FullControl` as well as the individual rights such as `Delete` or `WriteAttributes`, and it accepts a comma-separated list that combines them. For the meaning of each right, see Concepts (../Concepts.md).</maml:para>
@ -1235,18 +1247,6 @@
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="IdentityReference, ID">
<maml:name>Account</maml:name>
<maml:description>
<maml:para>Specifies the accounts whose access to the item is audited. The value is an account name such as `CONTOSO\JohnDoe`, `CONTOSO\Domain Users`, `BUILTIN\Users`, or `Everyone`, or a SID string such as `S-1-5-32-545`. When you pass several accounts, the cmdlet adds one audit entry per account.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">IdentityReference2[]</command:parameterValue>
<dev:type>
<maml:name>IdentityReference2[]</maml:name>
<maml:uri />
</dev:type>
<dev:defaultValue>None</dev:defaultValue>
</command:parameter>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="named" aliases="none">
<maml:name>AuditFlags</maml:name>
<maml:description>
@ -1312,7 +1312,7 @@
</command:syntaxItem>
</command:syntax>
<command:parameters>
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="2" aliases="FileSystemRights">
<command:parameter required="true" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName)" position="3" aliases="FileSystemRights">
<maml:name>AccessRights</maml:name>
<maml:description>
<maml:para>Specifies the access rights to audit. The value accepts the basic rights such as `Read`, `Write`, `Modify`, and `FullControl` as well as the individual rights such as `Delete` or `WriteAttributes`, and it accepts a comma-separated list that combines them. For the meaning of each right, see Concepts (../Concepts.md).</maml:para>
@ -1502,7 +1502,7 @@
<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>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 `AddAceError` 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 syntax shows `-Path`, `-Account`, and `-AccessRights` as positional parameters, but `-Account` and `-AccessRights` are both declared at position 2. A command that passes them positionally therefore fails with the error that positional parameters cannot be bound because no names were given, and `Get-Command Add-NTFSAudit -Syntax` leaves `-Account` out for the same reason. Pass `-Account` and `-AccessRights` by name, as the examples above do.</maml:para>
<maml:para>`-Path` or `-SecurityDescriptor`, `-Account`, and `-AccessRights` are positional parameters at positions 1, 2, and 3, like in `Remove-NTFSAudit`. Before 5.0.0, `-Account` and `-AccessRights` were both declared at position 2, so a command that passed them by position failed.</maml:para>
<maml:para>An audit entry alone does not create events. Windows writes the events to the security log only while the "Audit object access" policy, or the corresponding "Audit File System" advanced audit policy, is enabled for success, failure, or both. That policy is a Windows setting and is not managed by this module.</maml:para>
</maml:alert>
</maml:alertSet>

27
Tests/Audit.Tests.ps1

@ -67,3 +67,30 @@ Describe 'Get-NTFSAudit' {
}
}
}
Describe 'Add-NTFSAudit' {
Context 'Positional parameters' {
It 'Should take -Account at position 2 and -AccessRights at position 3 in the <_> parameter set' -ForEach @(
'PathSimple', 'PathComplex', 'SDSimple', 'SDComplex'
) {
$parameterSet = (Get-Command -Name Add-NTFSAudit).ParameterSets | Where-Object -Property Name -EQ -Value $_
$positions = @{}
$parameterSet.Parameters | Where-Object -Property Position -GE -Value 0 | ForEach-Object -Process {
$positions[$_.Name] = $_.Position
}
$positions['Account'] | Should -Be 2
$positions['AccessRights'] | Should -Be 3
}
It 'Should bind an account and access rights that are passed by position' {
$file = New-TestSandboxItem -Sandbox $sandbox -Name 'Positional'
$sd = Get-NTFSSecurityDescriptor -Path $file
Add-NTFSAudit -SecurityDescriptor $sd 'Everyone' 'ReadData' -InheritanceFlags None -PropagationFlags None -ErrorAction Stop
$rules = $sd.SecurityDescriptor.GetAuditRules($true, $false, [System.Security.Principal.SecurityIdentifier])
@($rules | Where-Object -FilterScript { $_.IdentityReference.Value -eq 'S-1-1-0' }) | Should -HaveCount 1
}
}
}

Loading…
Cancel
Save