Bonjour,
Vous avez déjà fait le plus difficile en rétablissant l’héritage sur D:. La manière la plus propre de supprimer en masse les ACE explicites restants sans toucher aux autorisations héritées consiste à effectuer un premier passage PowerShell pour tout auditer, puis un second passage qui supprime uniquement les règles non héritées. Cela préserve les autorisations héritées et vous permet d’ajouter en liste blanche tout dossier ou compte qui doit conserver des entrées explicites.
Exécutez ces étapes depuis une fenêtre PowerShell avec élévation de privilèges.
Mettez d’abord OneDrive en pause pour éviter l’agitation pendant les modifications d’ACL. Collez ensuite le script ci-dessous tel quel. Il démarre en mode Audit et écrit un CSV afin que vous puissiez examiner exactement ce qui serait supprimé. Lorsque vous êtes satisfait, définissez $DoRemoval sur $true et exécutez-le à nouveau pour effectuer le nettoyage.
# 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:\KeepExplicit\'
)
# Liste blanche de comptes (optionnel). Les ACE explicites pour ces identités seront conservés.
$WhitelistAccounts = @('BUILTIN\Administrators','NT AUTHORITY\SYSTEM','CREATOR OWNER')
# 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." }
Voici comment l’utiliser.
Exécutez-le d’abord exactement tel qu’affiché pour que $DoRemoval reste false. Ouvrez D:\acl-audit.csv et examinez quelques chemins pour confirmer qu’il ne répertorie que les entrées explicites non héritées que vous souhaitez supprimer. S’il existe des dossiers qui doivent conserver des ACE explicites, ajoutez leurs préfixes complets à $WhitelistPaths et ajoutez tout compte spécifique à $WhitelistAccounts, puis relancez en mode audit pour vérifier que le CSV est correct. Lorsque vous êtes prêt, passez $DoRemoval à $true, exécutez-le une fois encore et surveillez D:\acl-fix.log pour le suivi. Reprenez enfin la synchronisation OneDrive.
Si vous préférez une réinitialisation rapide et «brute» pour un sous-arbre où vous savez qu’il n’existe aucune entrée explicite légitime, vous pouvez aussi utiliser icacls pour effacer uniquement ce sous-arbre. Par exemple, pour normaliser D:\DataOnly sans toucher à vos exceptions, exécutez ceci depuis une invite de commandes avec élévation :
icacls "D:\DataOnly" /reset /t /c
Si quelque chose n’est pas clair ou si vous voulez que j’adapte la liste blanche à vos entrées spécifiques, donnez-moi un ou deux exemples issus du CSV et j’adapterai le script pour vous.