# CONFIGURER ICI $Root = 'D:\' # racine de l’arborescence à corriger $AuditCsv = 'D:\acl-audit.csv' # où écrire l’audit $FixLog = 'D:\acl-fix.log' # où consigner les changements $DoRemoval = $false # laisser à false pour l’audit. mettre à $true pour supprimer # Liste blanche de chemins (optionnel). Tout ce qui se trouve sous ces chemins sera totalement ignoré. $WhitelistPaths = @('D:\$RECYCLE.BIN\', 'D:\Huawei Share\' # 'D:\KeepExplicit\' ) # Liste blanche de comptes (optionnel). Les ACE explicites pour ces identités seront conservés. $WhitelistAccounts = @('BUILTIN\Administrateurs', 'AUTORITE NT\Système','AUTORITE NT\Syst├¿me', 'AUTORITE NT\Utilisateurs authentifiés', 'AUTORITE NT\Utilisateurs authentifi├®s' 'S-1-15-3-1024-2302894289-466761758-1166120688-1039016420-2430351297-4240214049-4028510897-3317428798', 'S-1-15-3-1024-3424233489-972189580-2057154623-747635277-1604371224-316187997-3786583170-1043257646' ) # Aide pour tester le préfixe de chemin function Test-IsUnder { param($Path, $Prefix) return $Path.StartsWith($Prefix, [System.StringComparison]::OrdinalIgnoreCase) } # Collecter les éléments. Ignorer les points de reconnexion pour éviter jonctions/symlinks. $items = @() try { $items += Get-Item -LiteralPath $Root } catch {} $items += Get-ChildItem -LiteralPath $Root -Recurse -Force -Attributes !ReparsePoint -ErrorAction SilentlyContinue # AUDIT $report = New-Object System.Collections.Generic.List[object] $index = 0 foreach ($item in $items) { $index++ Write-Progress -Activity "Auditing ACLs" -Status $item.FullName -PercentComplete (($index / $items.Count) * 100) # Ignorer les chemins en liste blanche $skip = $false foreach ($p in $WhitelistPaths) { if (Test-IsUnder $item.FullName $p) { $skip = $true; break } } if ($skip) { continue } try { $acl = Get-Acl -LiteralPath $item.FullName # S’assurer que l’héritage est activé sur cet élément if ($acl.AreAccessRulesProtected) { $acl.SetAccessRuleProtection($false, $true) Set-Acl -LiteralPath $item.FullName -AclObject $acl $acl = Get-Acl -LiteralPath $item.FullName } $explicitRules = $acl.Access | Where-Object { -not $_.IsInherited } foreach ($r in $explicitRules) { $report.Add([pscustomobject]@{ Path = $item.FullName Identity = $r.IdentityReference.Value Rights = $r.FileSystemRights Type = $r.AccessControlType InheritanceFlags = $r.InheritanceFlags PropagationFlags = $r.PropagationFlags }) } if ($DoRemoval -and $explicitRules.Count -gt 0) { $changed = $false foreach ($r in $explicitRules) { if ($WhitelistAccounts -contains $r.IdentityReference.Value) { continue } # Supprimer la règle explicite exacte $null = $acl.RemoveAccessRuleSpecific($r) $changed = $true } if ($changed) { Set-Acl -LiteralPath $item.FullName -AclObject $acl Add-Content -LiteralPath $FixLog -Value ("Removed explicit ACEs from: " + $item.FullName) } } } catch { Add-Content -LiteralPath $FixLog -Value ("Error on: " + $item.FullName + " - " + $_.Exception.Message) continue } } # Écrire l’audit à la fin pour obtenir systématiquement une capture complète $report | Sort-Object Path, Identity | Export-Csv -LiteralPath $AuditCsv -NoTypeInformation -Encoding UTF8 Write-Host "" Write-Host "Audit written to $AuditCsv" if ($DoRemoval) { Write-Host "Changes logged to $FixLog" } else { Write-Host "Removal is disabled. Set `$DoRemoval = `$true to apply the cleanup." }