# rebuild_bootpack_full_hub_v1.1.ps1 (WRITE path fixed, PS 5.1, ASCII-safe) # Rôle : Mettre à jour la section [BUG_KB_JSON_POINTER] dans bootpack.txt et bootpack_paste.txt # à partir de l'état réel du fichier bug_kb\BUG_KB.json.txt. # Mode : -Preview (lecture seule) / -Write (écriture SAFE-WRITE). Aucune autre écriture. # Règles : PS 5.1 pur, pas de here-strings, pas de ternaires, pas d'opérateurs PS7. # Encod. : Ce script = UTF-8 avec BOM. Écritures .txt = UTF-8 sans BOM. ASCII-safe dans le code. # Affich. : Conserve la forme des lignes imprimées que tu utilises dans tes contrôles. [CmdletBinding()] param( [switch]$Preview, [switch]$Write, [string]$Root = "\\DS-918\\chatgpt\\ChatGPT-Gouvernance-Projets\\_registry" ) # ---------------- Utils ---------------- function Ensure-Dir([string]$Path){ if([string]::IsNullOrWhiteSpace($Path)){ return } if(-not (Test-Path -LiteralPath $Path)){ New-Item -ItemType Directory -Path $Path -Force | Out-Null } } function Ensure-Parent([string]$Target){ if([string]::IsNullOrWhiteSpace($Target)){ return } $p = Split-Path -Parent $Target if($p){ Ensure-Dir $p } } function Read-All([string]$Path){ if(-not (Test-Path -LiteralPath $Path)){ return "" } $t = Get-Content -LiteralPath $Path -Raw -Encoding UTF8 $t = $t -replace "`uFEFF","" return $t } function Write-SafeText([string]$Target,[string]$Content){ # UTF-8 WITHOUT BOM + staging + .bak + atomic move $stage = "C:\\Temp_Gouvernance\\stage_io" Ensure-Dir $stage Ensure-Parent $Target $tmp = Join-Path $stage ("__tmp_" + [guid]::NewGuid().ToString("N") + ".txt") $enc = New-Object System.Text.UTF8Encoding($false) [System.IO.File]::WriteAllText($tmp,$Content,$enc) $bak = $null if(Test-Path -LiteralPath $Target){ $bak = $Target + "." + (Get-Date).ToString("yyyyMMdd_HHmmss") + ".bak" Copy-Item -LiteralPath $Target -Destination $bak -Force } $destTmp = $Target + ".__tmp__" if(Test-Path -LiteralPath $destTmp){ Remove-Item -LiteralPath $destTmp -Force } Copy-Item -LiteralPath $tmp -Destination $destTmp -Force Move-Item -LiteralPath $destTmp -Destination $Target -Force return $bak } function Count-EntriesFromJson([string]$JsonPath){ if(-not (Test-Path -LiteralPath $JsonPath)){ return -1 } $raw = Get-Content -LiteralPath $JsonPath -Raw -Encoding UTF8 $raw = $raw -replace "`uFEFF","" $last = $raw.LastIndexOf('}') if($last -gt 0){ $raw = $raw.Substring(0,$last+1) } try{ $obj = $raw | ConvertFrom-Json -ErrorAction Stop if($null -ne $obj -and $obj.PSObject.Properties.Match("entries").Count -gt 0 -and $null -ne $obj.entries){ return @($obj.entries).Count } else { return -1 } }catch{ return -1 } } function Replace-PointerBlock([string]$BootPackPath,[string]$KbPath,[string]$KbSha,[int]$Entries,[long]$Size,[string]$Updated){ $txt = Read-All $BootPackPath $lines = $txt -split "(`r`n|`n|`r)" $out = @() $i = 0 $n = $lines.Length $state = 0 # 0 normal, 1 in-pointer $replaced = $false while($i -lt $n){ $line = $lines[$i] $t = $line.Trim() if($state -eq 0 -and $t -ceq "[BUG_KB_JSON_POINTER]"){ # write new block $out += "[BUG_KB_JSON_POINTER]" $out += ("Path={0}" -f $KbPath) $out += ("SHA256={0}" -f $KbSha) $out += ("Entries={0}" -f $Entries) $out += ("Size={0}" -f $Size) $out += ("Updated={0}" -f $Updated) # skip old block lines until next section or EOF $state = 1 $replaced = $true $i = $i + 1 while($i -lt $n){ $peek = $lines[$i] $pt = $peek.Trim() if($pt -match "^\[.+\]\s*$"){ break } $i = $i + 1 } continue } if($state -eq 1){ # we just broke out because next section starts; do not append current line yet, loop continues $state = 0 continue } $out += $line $i = $i + 1 } if(-not $replaced){ if($out.Count -gt 0 -and $out[$out.Count-1] -ne ""){ $out += "" } $out += "[BUG_KB_JSON_POINTER]" $out += ("Path={0}" -f $KbPath) $out += ("SHA256={0}" -f $KbSha) $out += ("Entries={0}" -f $Entries) $out += ("Size={0}" -f $Size) $out += ("Updated={0}" -f $Updated) } $nl = "`r`n" return ($out -join $nl) } # ---------------- Paths & facts ---------------- $BootPack1 = Join-Path $Root "bootpack\\bootpack.txt" $BootPack2 = Join-Path $Root "bootpack\\bootpack_paste.txt" $Profile = Join-Path $Root "profiles\\project\\HUB\\PROJECT_PROFILE.txt" $KbPath = Join-Path $Root "bug_kb\\BUG_KB.json.txt" $kbSha = "MISSING" $kbSize = "MISSING" $kbEntries = -1 if(Test-Path -LiteralPath $KbPath){ try{ $kbSha = (Get-FileHash -LiteralPath $KbPath -Algorithm SHA256).Hash.ToUpperInvariant() }catch{ $kbSha = "ERROR" } try{ $kbSize = (Get-Item -LiteralPath $KbPath).Length }catch{ $kbSize = "ERROR" } $kbEntries = Count-EntriesFromJson $KbPath } $profileSha = "MISSING" if(Test-Path -LiteralPath $Profile){ try{ $profileSha = (Get-FileHash -LiteralPath $Profile -Algorithm SHA256).Hash.ToUpperInvariant() }catch{ $profileSha = "ERROR" } } # Pick a snapshot file if exists $snapDir = Join-Path $Root "snapshots" $snapshot = Join-Path $snapDir "snapshot_2025-10-21.json" if(-not (Test-Path -LiteralPath $snapshot) -and (Test-Path -LiteralPath $snapDir)){ $cands = Get-ChildItem -LiteralPath $snapDir -Filter "snapshot_*.json" -File | Sort-Object Name -Descending if($cands.Count -gt 0){ $snapshot = $cands[0].FullName } } $snapSha = "MISSING" if(Test-Path -LiteralPath $snapshot){ try{ $snapSha = (Get-FileHash -LiteralPath $snapshot -Algorithm SHA256).Hash.ToUpperInvariant() }catch{ $snapSha = "ERROR" } } $memId = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss") # ---------------- Preview banner ---------------- Write-Host "== PREVIEW :: REBUILD BOOTPACK (HUB) ==" Write-Host ("Target BootPack : {0}" -f $BootPack1) Write-Host ("PROFILE_FILE : {0} (SHA={1})" -f $Profile,$profileSha) Write-Host ("KB Pointer : {0} (SHA={1}, Entries={2}, Size={3}, Updated={4})" -f $KbPath,$kbSha,$kbEntries,$kbSize,(Get-Date).ToString("yyyy-MM-ddTHH:mm:ssK")) Write-Host ("SNAPSHOT_FILE : {0} (SHA={1})" -f $snapshot,$snapSha) Write-Host ("RULESET_ACTIVE : {0}" -f "GOV_SCRIPT_GATE v1.4 ; SAFE-WRITE v1.1 ; TXT-ONLY v1.0 ; SYNC-MEM-ARCHIVE-RULE v1.0 ; SYNC-GUARD v1.1") Write-Host ("MEM_SYNC_ID : {0}" -f $memId) Write-Host ("MANIFEST_SHA256 : {0}" -f "UNKNOWN") if(-not $Write){ Write-Host "Mode PREVIEW : aucune ecriture effectuee." exit 0 } # ---------------- WRITE path ---------------- $updatedIso = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ssK") $buf1 = Replace-PointerBlock $BootPack1 $KbPath $kbSha $kbEntries $kbSize $updatedIso $buf2 = Replace-PointerBlock $BootPack2 $KbPath $kbSha $kbEntries $kbSize $updatedIso $bak1 = Write-SafeText -Target $BootPack1 -Content $buf1 $bak2 = Write-SafeText -Target $BootPack2 -Content $buf2 $bak1Msg = $bak1; if(-not $bak1Msg){ $bak1Msg = "" } $bak2Msg = $bak2; if(-not $bak2Msg){ $bak2Msg = "" } Write-Host ("[OK] BootPack updated (HUB) -> {0}" -f $BootPack1) Write-Host ("Backup1: {0}" -f $bak1Msg) Write-Host ("Backup2: {0}" -f $bak2Msg) exit 0