Param( [string]$Root = "." ) $ErrorActionPreference = "Stop" $files = Get-ChildItem -Path $Root -Recurse -Filter *.md | Where-Object { $_.FullName -notmatch '\\archive\\' } $had = $false foreach ($f in $files) { try { $lines = Get-Content -LiteralPath $f.FullName -Encoding UTF8 -ErrorAction Stop } catch { Write-Warning ("Impossible de lire: {0} — {1}" -f $f.FullName, $_.Exception.Message) continue } $map = @{} $firstMap = @{} $dups = @{} for ($i = 0; $i -lt $lines.Count; $i++) { $line = $lines[$i] if ($line -match '^\s{0,3}#{1,6}\s+(.*)$') { $t = $Matches[1].Trim() $norm = ([regex]::Replace($t, '\s+', ' ')).ToLowerInvariant() if ($map.ContainsKey($norm)) { if (-not $dups.ContainsKey($norm)) { $dups[$norm] = New-Object System.Collections.ArrayList $firstMap[$norm] = $map[$norm] } [void]$dups[$norm].Add($i + 1) } else { $map[$norm] = $i + 1 } } } if ($dups.Keys.Count -gt 0) { $had = $true Write-Output "=== $($f.FullName) ===" foreach ($k in $dups.Keys) { $first = $firstMap[$k] $others = ($dups[$k] -join ', ') Write-Output ("Heading: '{0}' first@{1} duplicates@[{2}]" -f $k, $first, $others) } } } if (-not $had) { Write-Output "No duplicate headings detected." }