param([switch]$Full) try { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding } catch {} $here = $PSScriptRoot; if(-not $here){ $here = Split-Path -Parent $MyInvocation.MyCommand.Path } $registry = Split-Path -Parent $here $dirScripts = Join-Path $registry 'scripts' $dirBin = Join-Path $registry 'bin' $dirReports = Join-Path $registry 'reports' if(!(Test-Path $dirReports)){ New-Item -ItemType Directory -Force -Path $dirReports | Out-Null } $ts = Get-Date -Format 'yyyyMMdd_HHmmss' $report = Join-Path $dirReports ('scripts_baseline_dashboard_'+$ts+'.txt') # bases critiques (doivent etre OK) $critical = @( 'gov_profile_launcher', 'rebuild_bootpack_full_hub', 'rebuild_bootpack_full_seedbox', 'writer_posthook_runner', 'text_encoding_guard', 'ps_script_linter', 'safe_write_text', 'write_devlock_debugkit_rule', 'project_profile_echo', 'encoding_policy_resolver', 'view_utf8', 'run_encoding_maintenance', 'ps_scripts_sanitize_and_quarantine', 'gov_pipeline_guard', 'kb_guard_validator', 'kb_emit_bootpack_dual', 'export_bootpack_txt', 'fix_manifest_sha', 'kb_quicklog_and_sync' ) function Get-Version([string]$name){ $m=[regex]::Match($name,'_v([0-9]+(?:\.[0-9]+)*)\.ps1$') if($m.Success){ try { return [version]$m.Groups[1].Value } catch { } } return [version]'0.0' } # collect alias mapping: base -> found $aliasFiles = Get-ChildItem -LiteralPath $dirBin -Filter '*_latest.cmd' -File -EA SilentlyContinue $aliasFiles += Get-ChildItem -LiteralPath $dirScripts -Filter '*_latest.cmd' -File -EA SilentlyContinue $aliasMap = @{} foreach($a in $aliasFiles){ $raw = Get-Content -LiteralPath $a.FullName -Raw -Encoding UTF8 $m = [regex]::Match($raw,'-Base\s+"([^"]+)"') if($m.Success){ $b=$m.Groups[1].Value if(-not $aliasMap.ContainsKey($b)){ $aliasMap[$b]=@() } $aliasMap[$b]+=$a.FullName } else { $m2=[regex]::Match($raw,'scripts\\([a-zA-Z0-9_\-]+)_v[0-9.]+\.ps1') if($m2.Success){ $b=$m2.Groups[1].Value if(-not $aliasMap.ContainsKey($b)){ $aliasMap[$b]=@() } $aliasMap[$b]+=$a.FullName } } } # build inventory rows $rows = @() $allBases = New-Object System.Collections.Generic.HashSet[string] foreach($b in $critical){ [void]$allBases.Add($b) } if($Full){ $all = Get-ChildItem -LiteralPath $dirScripts -Filter '*_v*.ps1' -File -EA SilentlyContinue | ForEach-Object { ($_ .BaseName -replace '_v[0-9.]+$','') } | Sort-Object -Unique foreach($b in $all){ [void]$allBases.Add($b) } } foreach($base in $allBases){ $pattern = $base + '_v*.ps1' $cands = Get-ChildItem -LiteralPath $dirScripts -Filter $pattern -File -EA SilentlyContinue $best = $null if($cands){ $best = ($cands | Sort-Object @{Expression={ Get-Version $_.Name };Descending=$true}, @{Expression={$_.LastWriteTime};Descending=$true} | Select-Object -First 1) } $qCount = (Get-ChildItem -LiteralPath $dirScripts -Filter ($base+'.ps1.bad_*') -File -EA SilentlyContinue | Measure-Object).Count $aliasList = $null if($aliasMap.ContainsKey($base)){ $aliasList = $aliasMap[$base] } $status='OK' if(-not $best){ $status='FAIL_NO_ACTIVE' } elseif(-not $aliasList){ if($critical -contains $base){ $status='WARN_NO_ALIAS' } else { $status='INFO_NO_ALIAS' } } if($qCount -gt 0 -and $status -eq 'OK'){ $status='OK_QUAR_EXISTS' } $rows += [PSCustomObject]@{ Base = $base LatestPS1 = if($best){ $best.Name } else { '' } LatestVersion = if($best){ (Get-Version $best.Name).ToString() } else { '' } AliasFound = if($aliasList){ 'Yes' } else { 'No' } AliasCount = if($aliasList){ ($aliasList.Count) } else { 0 } QuarantineCount = $qCount Status = $status } } # Order: critical first, fail/warn first $rows = $rows | Sort-Object @{Expression={ if($critical -contains $_.Base){0}else{1} }}, @{Expression={ switch($_.Status){ 'FAIL_NO_ACTIVE'{0}; 'WARN_NO_ALIAS'{1}; 'OK_QUAR_EXISTS'{2}; 'OK'{3}; default{4} } }}, Base # output "=== SCRIPTS BASELINE DASHBOARD - "+(Get-Date -Format s) | Out-File -LiteralPath $report -Encoding UTF8 "Root = "+$registry | Out-File -LiteralPath $report -Append -Encoding UTF8 "" | Out-File -LiteralPath $report -Append -Encoding UTF8 "{0,-34} {1,-34} {2,-8} {3,-5} {4,-5} {5,-4} {6}" -f 'Base','LatestPS1','Version','Alias','Alias#','Qbad','Status' | Out-File -LiteralPath $report -Append -Encoding UTF8 $rows | ForEach-Object { "{0,-34} {1,-34} {2,-8} {3,-5} {4,-5} {5,-4} {6}" -f $_.Base, $_.LatestPS1, $_.LatestVersion, $_.AliasFound, $_.AliasCount, $_.QuarantineCount, $_.Status | Out-File -LiteralPath $report -Append -Encoding UTF8 } Write-Host ('Report -> '+$report) # also echo top issues to console $issues = $rows | Where-Object { $_.Status -like 'FAIL*' -or $_.Status -like 'WARN*' } if($issues){ Write-Host "`nIssues:"; $issues | Format-Table -AutoSize }