# write_kb_compare_lite_v1.1.ps1 -- regenerate scripts\kb_compare_lite_v1.1.ps1 (UTF-8 no BOM, CRLF) Param([switch]$Write) try { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false) } catch {} $scriptPath = $PSCommandPath if (-not $scriptPath) { Write-Host "[ERROR] This writer must be run via -File (not pasted line-by-line)." exit 2 } $here = Split-Path -Parent $scriptPath $root = Split-Path -Parent $here $scripts= Join-Path $root 'scripts' $target = Join-Path $scripts 'kb_compare_lite_v1.1.ps1' $body = @" Param( [Parameter(Mandatory=\$true)][string]\$RegistryRoot ) try { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding(\$false) } catch {} function Read-Text([string]\$p){ if(-not (Test-Path -LiteralPath \$p)){ return '' } try { return Get-Content -LiteralPath \$p -Raw -Encoding UTF8 } catch { return (Get-Content -LiteralPath \$p -Raw) } } function Extract-PointerField([string]\$raw,[string]\$name){ # Read field from [BUG_KB_JSON_POINTER] section (first match) $(if($(if(\$pat = '(){ ms)^\[BUG_KB_JSON_POINTER\].*){ ^\s*' + [regex] } else { } else { Escape(\$name) + '\s*:\s*(.+?)\s*$' }) }) \$m = [regex]::Match(\$raw,\$pat) if(\$m.Success){ return \$m.Groups[1].Value.Trim() } else { return '' } } function To-IntSafe([object]\$v){ if(\$null -eq \$v){ return -1 } if(\$v -is [array]){ if(\$v.Length -gt 0){ \$v = \$v[0] } else { return -1 } } try { return [int]\$v } catch { return -1 } } function Count-EntriesFromJson([string]\$jsonText){ if([string]::IsNullOrWhiteSpace(\$jsonText)){ return -1 } # Strip BOM if present if(\$jsonText.Length -gt 0 -and ([int]\$jsonText[0] -eq 0xFEFF)){ \$jsonText = \$jsonText.Substring(1) } try{ \$obj = \$jsonText | ConvertFrom-Json if(\$null -ne \$obj -and \$obj.PSObject.Properties.Name -contains 'entries'){ \$arr = @(\$obj.entries) return \$arr.Count } }catch{} # Fallback: count "id" occurrences inside entries array try{ \$m = [regex]::$(if(Match(\$jsonText,'(){ ms)\"entries\"\s* } else { \s*\[(.*?)\]') }) if(\$m.Success){ \$block = \$m.Groups[1].Value return ([regex]::$(if(Matches(\$block,'(){ i)\"id\"\s* } else { ')).Count }) } }catch{} return -1 } # Read bootpack \$bp = Join-Path \$RegistryRoot 'bootpack\bootpack.txt' if(-not (Test-Path -LiteralPath \$bp)){ Write-Host "[ERROR] bootpack.txt not found: \$bp" exit 2 } \$raw = Read-Text \$bp # Pointer fields \$P_path = Extract-PointerField \$raw 'Path' \$P_sha = Extract-PointerField \$raw 'SHA256' \$P_entS = Extract-PointerField \$raw 'Entries' \$P_szS = Extract-PointerField \$raw 'SizeBytes' # Normalize if(\$null -eq \$P_path){ \$P_path='' } if(\$null -eq \$P_sha ){ \$P_sha ='' } \$P_ent = To-IntSafe \$P_entS \$P_sz = To-IntSafe \$P_szS if(-not [string]::IsNullOrWhiteSpace(\$P_sha)){ \$P_sha = (\$P_sha -replace '\s','').ToUpperInvariant() } # Actual metrics if([string]::IsNullOrWhiteSpace(\$P_path) -or -not (Test-Path -LiteralPath \$P_path)){ Write-Host "[ERROR] Pointer Path invalid or missing: \$P_path" exit 2 } try{ \$psSha = (Get-FileHash -Algorithm SHA256 -LiteralPath \$P_path).Hash.ToUpperInvariant() }catch{ Write-Host "[ERROR] Cannot compute SHA256 on: \$P_path" exit 2 } try{ \$psSize = (Get-Item -LiteralPath \$P_path).Length }catch{ \$psSize = -1 } \$ptrRaw = Read-Text \$P_path \$psEnt = Count-EntriesFromJson \$ptrRaw # Compare \$okSha = (\$P_sha -eq \$psSha) \$okEnt = (\$P_ent -eq \$psEnt) \$okSize = (\$P_sz -eq [int]\$psSize) Write-Host "[KB POINTER] \$P_path" Write-Host ("Expect : SHA={0} Entries={1} Size={2}" -f \$P_sha, \$P_ent, \$P_sz) Write-Host ("Actual : SHA={0} Entries={1} Size={2}" -f \$psSha, \$psEnt, \$psSize) if(\$okSha -and \$okEnt -and \$okSize){ Write-Host "STATUS=OK" exit 0 }else{ if(-not \$okSha ){ Write-Host "MISMATCH: SHA" } if(-not \$okEnt ){ Write-Host "MISMATCH: Entries" } if(-not \$okSize){ Write-Host "MISMATCH: SizeBytes" } exit 2 } "@ function SafeWrite([string]$p,[string]$text){ $dir = Split-Path -Parent $p if(-not (Test-Path -LiteralPath $dir)){ New-Item -ItemType Directory -Path $dir | Out-Null } $bak = $p + '.bak_' + (Get-Date -Format 'yyyyMMdd_HHmmss') if(Test-Path -LiteralPath $p){ Copy-Item -LiteralPath $p -Destination $bak -Force } $tmp = $p + '.tmp' $utf8noBom = New-Object System.Text.UTF8Encoding($false) [IO.File]::WriteAllText($tmp,$text,$utf8noBom) Move-Item -LiteralPath $tmp -Destination $p -Force $sha = (Get-FileHash -Algorithm SHA256 -LiteralPath $p).Hash Write-Host ("WROTE: {0}" -f $p) Write-Host ("SHA : {0}" -f $sha) } if($Write){ SafeWrite -p $target -text $body $encCmd = Join-Path (Join-Path $root 'bin') 'text_encoding_guard_latest.cmd' if(Test-Path $encCmd){ & $encCmd -Scope Scripts -Write | Out-Null } }else{ Write-Host ("PREVIEW -> would write: {0}" -f $target) }