diff --git a/modules/TierModel/public/Repair-TierModelCanonicalAcl.ps1 b/modules/TierModel/public/Repair-TierModelCanonicalAcl.ps1 index a438f20..efedc91 100644 --- a/modules/TierModel/public/Repair-TierModelCanonicalAcl.ps1 +++ b/modules/TierModel/public/Repair-TierModelCanonicalAcl.ps1 @@ -186,6 +186,7 @@ function Repair-TierModelCanonicalAcl { $null -ne $q -and $q.AceQualifier -eq [System.Security.AccessControl.AceQualifier]::AccessAllowed -and -not ((([int]$_.Ace.AceFlags) -band ([int][System.Security.AccessControl.AceFlags]::Inherited)) -ne 0) } + $printedOverlapNotice = $false foreach ($dEntry in $explicitDenies) { $dq = $dEntry.Ace -as [System.Security.AccessControl.QualifiedAce] foreach ($aEntry in $explicitAllows) { @@ -193,8 +194,12 @@ function Repair-TierModelCanonicalAcl { if ($dq.SecurityIdentifier -eq $aq.SecurityIdentifier -and (([int]$dq.AccessMask) -band ([int]$aq.AccessMask)) -ne 0) { $sidName = try { $dq.SecurityIdentifier.Translate([System.Security.Principal.NTAccount]).Value } catch { $dq.SecurityIdentifier.Value } - $warnMsg = "Potential effective-access overlap detected on '$DistinguishedName' for principal '$sidName' — review DACL before applying sort" - Write-Warning $warnMsg + $warnMsg = "Deny/Allow overlap on '$DistinguishedName' for principal '$sidName' — canonical reorder applied (effective access may change)." + if (-not $printedOverlapNotice) { + $ouLeaf = if ([string]::IsNullOrEmpty($DistinguishedName)) { $DistinguishedName } else { (($DistinguishedName -split ',')[0] -replace '^\w+=','') } + Write-Host "REMEDIATED: Canonical ACL overlap on OU: $ouLeaf" -ForegroundColor Green + $printedOverlapNotice = $true + } $warnings.Add($warnMsg) } } diff --git a/tests/Unit.CanonicalAclRepair.Tests.ps1 b/tests/Unit.CanonicalAclRepair.Tests.ps1 index 2a12b22..ff123e0 100644 --- a/tests/Unit.CanonicalAclRepair.Tests.ps1 +++ b/tests/Unit.CanonicalAclRepair.Tests.ps1 @@ -319,15 +319,15 @@ Describe "Repair-TierModelCanonicalAcl — ByBytes path" -Tag 'Unit', 'Canonical # ------------------------------------------------------------------------- Context "Deny/Allow overlap warning" { - It "Emits a warning when same SID has both Deny and Allow on overlapping rights" { - $result = Repair-TierModelCanonicalAcl -SecurityDescriptorBytes $script:OverlapInputBytes -WarningVariable warnVar 3>$null - $warnVar | Should -Not -BeNullOrEmpty + It "Records an overlap entry in Warnings when same SID has both Deny and Allow on overlapping rights" { + $result = Repair-TierModelCanonicalAcl -SecurityDescriptorBytes $script:OverlapInputBytes + $result.Warnings | Should -Not -BeNullOrEmpty } - It "Warning message mentions the overlapping principal" { - $result = Repair-TierModelCanonicalAcl -SecurityDescriptorBytes $script:OverlapInputBytes -WarningVariable warnVar 3>$null + It "Warnings entry mentions the overlapping principal" { + $result = Repair-TierModelCanonicalAcl -SecurityDescriptorBytes $script:OverlapInputBytes # au = Authenticated Users (S-1-5-11) - ($warnVar -join ' ') | Should -Match 'overlap|S-1-5-11|Authenticated' + (($result.Warnings) -join ' ') | Should -Match 'overlap|S-1-5-11|Authenticated' } It "Still repairs (IsCanonical=true) despite the overlap warning" {