Browse Source

test(inheritance): read the SACL alone where a test asserts the audit protection flag

Get-Acl -Audit reads the SACL together with the other sections. On a domain
member (Windows Server 2019, 2022, and 2025 of the operating-system matrix)
that read reports the SACL of an item without audit entries as protected from
inheritance, where the read of the SACL alone and Get-NTFSInheritance report
it as not protected (FileSystemSecurity2 documents the same difference).

The test 'Disable-NTFSAuditInheritance -SecurityDescriptor should take two
piped descriptors ...' asserted the on-disk flag of a fresh file with
Get-Acl -Audit, and failed in all six elevated configurations of the three
file servers. Diagnostic runs on 2019 and 2025 show both reads side by side.
Four more assertions read the flag of an item that ends without audit entries
and expect "protected"; there they could not tell a written flag from none.

The five assertions now read the SACL alone through .NET, as the module does.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
ai/coverage-unknowns
Raimund Andree 1 day ago
parent
commit
f1f3d8f078
  1. 23
      Tests/ParameterSets.Audit.Tests.ps1
  2. 29
      Tests/ParameterSets.Inheritance.Tests.ps1

23
Tests/ParameterSets.Audit.Tests.ps1

@ -41,6 +41,27 @@ BeforeAll {
(Get-Acl -LiteralPath $Path).Sddl (Get-Acl -LiteralPath $Path).Sddl
} }
function Get-TestAuditAcl {
# The SACL read alone, through .NET. Get-Acl -Audit reads it together with the other sections, and on a domain
# member that reports the SACL of an item without audit entries as protected from inheritance, which is not its
# state (see Security2\FileSystem\FileSystemSecurity2.cs). Matches the helper of ParameterSets.Inheritance.Tests.ps1.
param ([Parameter(Mandatory)] [string] $Path)
$sections = [System.Security.AccessControl.AccessControlSections]::Audit
$info = if (Test-Path -LiteralPath $Path -PathType Container) {
New-Object -TypeName 'System.IO.DirectoryInfo' -ArgumentList $Path
}
else {
New-Object -TypeName 'System.IO.FileInfo' -ArgumentList $Path
}
if ($PSVersionTable.PSEdition -eq 'Desktop') {
$info.GetAccessControl($sections)
}
else {
[System.IO.FileSystemAclExtensions]::GetAccessControl($info, $sections)
}
}
function Get-TestAccessOnlyDescriptor { function Get-TestAccessOnlyDescriptor {
# A descriptor read with the Access section only, like one that Get-NTFSSecurityDescriptor returns without # A descriptor read with the Access section only, like one that Get-NTFSSecurityDescriptor returns without
# the Security privilege: the audit cmdlets have nothing to read or change and report it the same way. # the Security privilege: the audit cmdlets have nothing to read or change and report it the same way.
@ -337,7 +358,7 @@ Describe 'Clear-NTFSAudit' {
Clear-NTFSAudit -Path $child -DisableInheritance -ErrorVariable clearErrors -ErrorAction SilentlyContinue Clear-NTFSAudit -Path $child -DisableInheritance -ErrorVariable clearErrors -ErrorAction SilentlyContinue
$clearErrors | Should -BeNullOrEmpty $clearErrors | Should -BeNullOrEmpty
(Get-Acl -LiteralPath $child -Audit).AreAuditRulesProtected | Should -BeTrue (Get-TestAuditAcl -Path $child).AreAuditRulesProtected | Should -BeTrue
@((Get-Acl -LiteralPath $child -Audit).GetAuditRules($true, $true, $sidType)) | Should -BeNullOrEmpty @((Get-Acl -LiteralPath $child -Audit).GetAuditRules($true, $true, $sidType)) | Should -BeNullOrEmpty
Get-TestDaclSddl -Path $child | Should -BeExactly $daclBefore Get-TestDaclSddl -Path $child | Should -BeExactly $daclBefore
} }

29
Tests/ParameterSets.Inheritance.Tests.ps1

@ -123,6 +123,27 @@ BeforeAll {
[System.IO.FileSystemAclExtensions]::GetAccessControl($info) [System.IO.FileSystemAclExtensions]::GetAccessControl($info)
} }
} }
function Get-TestAuditAcl {
# The SACL read alone, through .NET. Get-Acl -Audit reads it together with the other sections, and on a domain
# member that reports the SACL of an item without audit entries as protected from inheritance, which is not its
# state (see Security2\FileSystem\FileSystemSecurity2.cs). Matches the helper of ParameterSets.Audit.Tests.ps1.
param ([string] $Path)
$sections = [System.Security.AccessControl.AccessControlSections]::Audit
$info = if (Test-Path -LiteralPath $Path -PathType Container) {
New-Object -TypeName 'System.IO.DirectoryInfo' -ArgumentList $Path
}
else {
New-Object -TypeName 'System.IO.FileInfo' -ArgumentList $Path
}
if ($PSVersionTable.PSEdition -eq 'Desktop') {
$info.GetAccessControl($sections)
}
else {
[System.IO.FileSystemAclExtensions]::GetAccessControl($info, $sections)
}
}
} }
AfterAll { AfterAll {
@ -276,7 +297,7 @@ Describe 'State: independent .NET oracles for inheritance transitions and descri
Set-NTFSSecurityDescriptor -SecurityDescriptor $sd -ErrorAction Stop Set-NTFSSecurityDescriptor -SecurityDescriptor $sd -ErrorAction Stop
(Get-Acl -LiteralPath $file).AreAccessRulesProtected | Should -BeTrue (Get-Acl -LiteralPath $file).AreAccessRulesProtected | Should -BeTrue
(Get-Acl -LiteralPath $file -Audit).AreAuditRulesProtected | Should -BeTrue (Get-TestAuditAcl -Path $file).AreAuditRulesProtected | Should -BeTrue
} }
It 'Set-NTFSOwner should change only the owner and leave the Access entries and the group unchanged' { It 'Set-NTFSOwner should change only the owner and leave the Access entries and the group unchanged' {
@ -469,7 +490,7 @@ Describe 'Pipeline: binding into the -Path and -SecurityDescriptor sets that no
} }
else { else {
$item.AuditInheritanceEnabled | Should -Be $Expected $item.AuditInheritanceEnabled | Should -Be $Expected
(Get-Acl -LiteralPath $child -Audit).AreAuditRulesProtected | Should -Be (-not $Expected) (Get-TestAuditAcl -Path $child).AreAuditRulesProtected | Should -Be (-not $Expected)
} }
} }
} }
@ -500,7 +521,7 @@ Describe 'Pipeline: binding into the -Path and -SecurityDescriptor sets that no
} }
else { else {
$descriptors[$i].SecurityDescriptor.AreAuditRulesProtected | Should -Be (-not $Expected) $descriptors[$i].SecurityDescriptor.AreAuditRulesProtected | Should -Be (-not $Expected)
(Get-Acl -LiteralPath $files[$i] -Audit).AreAuditRulesProtected | Should -Be $PreDisable (Get-TestAuditAcl -Path $files[$i]).AreAuditRulesProtected | Should -Be $PreDisable
} }
} }
@ -508,7 +529,7 @@ Describe 'Pipeline: binding into the -Path and -SecurityDescriptor sets that no
foreach ($file in $files) { foreach ($file in $files) {
if ($Scope -eq 'access') { (Get-Acl -LiteralPath $file).AreAccessRulesProtected | Should -Be (-not $Expected) } if ($Scope -eq 'access') { (Get-Acl -LiteralPath $file).AreAccessRulesProtected | Should -Be (-not $Expected) }
else { (Get-Acl -LiteralPath $file -Audit).AreAuditRulesProtected | Should -Be (-not $Expected) } else { (Get-TestAuditAcl -Path $file).AreAuditRulesProtected | Should -Be (-not $Expected) }
} }
# A direct array binds both descriptors within one ProcessRecord call, unlike the pipeline above, which # A direct array binds both descriptors within one ProcessRecord call, unlike the pipeline above, which

Loading…
Cancel
Save