Pred vycistenim

This commit is contained in:
Petr Stepan
2026-06-06 12:16:20 +02:00
parent fb6bb88823
commit 2aaf44ad90
2 changed files with 167 additions and 35 deletions
+167 -35
View File
@@ -112,25 +112,35 @@ $AU_BITS = @(
@{ Bit=0x4000; Name='Conditional CA 2023 guard bit' }
)
# Symboly checklistu (z code-pointů kvůli odolnosti vůči kódování; lze změnit zde)
$SYM_DONE = [string][char]0x2713 # ✓
$SYM_FAIL = [string][char]0x2717 # ✗
# Značky checklistu. ASCII kvůli kompatibilitě — font Consolas (default konzole) nemá blok
# Dingbats, takže ✓/✗ by se zobrazily jako □. Chcete-li v Consolas „fajfku", nastavte
# $SYM_DONE = [string][char]0x221A (√, blok Mathematical Operators, Consolas ho má).
$SYM_DONE = '+'
$SYM_FAIL = '!'
$SYM_PENDING = ' '
#endregion
#region ── Log / barevný výstup ───────────────────────────────────────────────
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { (Get-Location).Path }
$script:LogFile = if ($LogPath) { $LogPath } else {
Join-Path $scriptDir ("SecureBootRemediation-{0}-{1}.log" -f $env:COMPUTERNAME, (Get-Date -Format 'yyyyMMdd-HHmmss'))
}
$script:LogActive = [bool]$LogPath
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { (Get-Location).Path }
# Jeden společný log na LOKÁLNÍM disku serveru (%ProgramData%), připojovaný pod sebe přes běhy.
# Záměrně NE vedle skriptu — ten může být RDP-redirected disk, kde per-řádkový zápis vytváří
# poškozené (null) soubory. Řádky se bufferují a zapíšou jednorázově (Flush-Log), což je odolné.
$script:LogFile = if ($LogPath) { $LogPath } else { Join-Path $WORK_ROOT 'SecureBootRemediation.log' }
$script:LogBuffer = New-Object System.Collections.Generic.List[string]
function Add-LogLine {
param([string]$Text)
if (-not $script:LogActive) { return }
try { ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Text) | Out-File -FilePath $script:LogFile -Append -Encoding UTF8 -Force } catch { }
[void]$script:LogBuffer.Add(('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Text))
}
function Flush-Log {
if ($script:LogBuffer.Count -eq 0) { return }
try {
if (-not (Test-Path $WORK_ROOT)) { New-Item -Path $WORK_ROOT -ItemType Directory -Force | Out-Null }
[System.IO.File]::AppendAllText($script:LogFile, (($script:LogBuffer -join "`r`n") + "`r`n"), (New-Object System.Text.UTF8Encoding($false)))
$script:LogBuffer.Clear()
} catch { }
}
function Write-Line { param([string]$Text='', [string]$Color='Gray', [switch]$NoLog) Write-Host $Text -ForegroundColor $Color; if (-not $NoLog) { Add-LogLine $Text } }
function Write-Rule { param([string]$Color='DarkCyan') Write-Host ('=' * 64) -ForegroundColor $Color }
@@ -465,6 +475,16 @@ function Get-RemediationCategory {
return @{ Code='FIRMWARE_UPDATE_NEEDED'; Tag='[FW]'; Color='Magenta'; Label='Aktualizace pozastavena (známý problém) — zkontrolujte firmware u OEM' }
}
# Build příliš starý: DB/KEK už mají 2023, ale boot-manager servicing hodnoty vůbec neexistují
# (WindowsUEFICA2023Capable i UEFICA2023Status absentní) a Boot Manager není aktivní → OS nemá
# 2023-podepsaný boot manager ani jeho servicing. Restarty nepomohou, pomůže jen Windows Update.
$certApplied = $ph['Kek2023'].Done -or $ph['Db2023Windows'].Done
$auNow = [int]$reg.AvailableUpdates
$bmStaged = ([bool]$Result.BootManager.EspHas2023) -or ($auNow -eq 0x4100) -or ($auNow -eq 0x4000)
if ($certApplied -and -not $ph['BootManager2023'].Done -and -not $bmStaged -and ($null -eq $reg.WindowsUEFICA2023Capable) -and ($null -eq $reg.UEFICA2023Status)) {
return @{ Code='BUILD_OUTDATED'; Tag='[!]'; Color='Magenta'; Label='Build je příliš starý — chybí servicing pro Boot Manager 2023. Nutný Windows Update.' }
}
$req=@('Kek2023','Db2023Windows','BootManager2023')
$missing=@($req|Where-Object{ -not $ph[$_].Done }); $missingLabels=@($missing|ForEach-Object{ $ph[$_].Label })
$anyApplied = $ph['Kek2023'].Done -or $ph['Db2023Windows'].Done -or $ph['BootManager2023'].Done -or $cert.DB.Has2023UEFI -or $cert.DB.Has2023OptionROM -or [bool]$Result.BootManager.EspHas2023
@@ -490,6 +510,7 @@ function Invoke-Detection {
$R = [ordered]@{
AuditTimestamp=(Get-Date).ToString('yyyy-MM-dd HH:mm:ss'); Hostname=$env:COMPUTERNAME
OSCaption=if($os){$os.Caption}else{$null}; OSBuild=if($os){$os.BuildNumber}else{$null}
OSBuildFull=$(try { $cv=Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction Stop; '{0}.{1}' -f $cv.CurrentBuildNumber,$cv.UBR } catch { if($os){[string]$os.BuildNumber}else{'?'} })
EnvironmentType=Get-EnvironmentType; Hardware=Get-HardwareInfo; SecureBoot=Get-SecureBootState
OperatingMode='Unknown'; BitLocker=$null; Certificates=$null; Registry=Get-RegistryStatus
EventLog=Get-EventLogStatus; TaskExists=Get-TaskExists; BootManager=$null; Phases=$null
@@ -517,11 +538,11 @@ function Invoke-Detection {
#region ── Výpis ──────────────────────────────────────────────────────────────
function Show-DetectionSummary {
param($R)
param($R, $Prereqs, $Prev)
$sb=$R.SecureBoot; $c=$R.Certificates; $reg=$R.Registry; $evt=$R.EventLog; $hw=$R.Hardware; $ph=$R.Phases; $bl=$R.BitLocker
Write-Head 'SERVER'
Write-KV 'Stroj' $R.Hostname 'White' ("· {0} (build {1})" -f $R.OSCaption, $R.OSBuild)
Write-KV 'Stroj' $R.Hostname 'White' ("· {0} (build {1})" -f $R.OSCaption, $R.OSBuildFull)
Write-KV 'Prostředí' $R.EnvironmentType 'White' ("· {0} {1}" -f $hw.Manufacturer, $hw.Model)
if ($sb.IsUEFI -and $sb.IsSupported) {
$modeColor = if ($R.OperatingMode -eq 'Setup') {'Red'} elseif ($R.OperatingMode -in @('User','Deployed')) {'White'} else {'Yellow'}
@@ -533,10 +554,14 @@ function Show-DetectionSummary {
Write-KV 'BitLocker' ("{0} [{1}]" -f $bl.Status, $bl.Protectors) $(if($blOn -and $bl.UsesPcr){'Yellow'}else{'White'}) $note $(if($blOn -and $bl.UsesPcr){'Yellow'}else{'DarkGray'})
}
if ($Prereqs) { Show-Prerequisites -Prereqs $Prereqs }
Write-Head 'POSTUP AKTUALIZACE (checklist)'
if ($sb.IsUEFI -and $sb.IsSupported) { foreach ($k in $ph.Keys) { $p=$ph[$k]; Write-Check -State $p.State -Text $p.Label -Note $p.Note } }
else { Write-Check -State 'Fail' -Text 'Secure Boot není podporováno / zapnuto' -Note 'remediace zde nedává smysl' }
Show-Progress -R $R -Prev $Prev
Write-Head 'STAV REGISTRŮ / FIRMWARE'
Write-KV 'AvailableUpdates' (Get-AvailableUpdatesText $reg.AvailableUpdates) 'Cyan'
Write-KV 'UEFICA2023Status' $reg.UEFICA2023StatusText $(if($reg.UEFICA2023StatusText -eq 'Updated'){'Green'}elseif($reg.UEFICA2023StatusText -eq 'Failed'){'Red'}else{'White'})
@@ -597,10 +622,19 @@ function Resolve-RemediationPlan {
'UPDATE_NEEDED' { $plan.Applicable=$true; $plan.AskUser=$true; $plan.Reason='Lze zahájit aktualizaci metodou registry (KB5068202).' }
'UPDATE_PARTIAL' { $plan.Applicable=$true; $plan.AskUser=$true; $plan.Reason='Část už nasazena, zbytek se aplikuje v dalším cyklu.'; $plan.Caution='Po nastavení a tasku bude potřeba RESTART; opakujte, dokud nebude HOTOVO.' }
'UPDATE_PENDING' {
$plan.Applicable=$true; $plan.AskUser=$true
$plan.Reason='KEK i DB hotové. Boot Manager se aktivuje až po RESTARTU.'
$plan.Caution='Nech znovu nastavit registry/task a pak RESTARTUJ.'
$plan.NextSteps=@('Po tomto kroku RESTARTUJTE server.','Po restartu spusťte kontrolu znovu (nebo -RegisterResume).')
$au = [int]$R.Registry.AvailableUpdates
# „Staged" = Boot Manager je už připravený k aktivaci (2023 na ESP, nebo AvailableUpdates
# v boot-manager fázi 0x4100/0x4000). Pak STAČÍ RESTART. Jinak je nutné ho teprve naplánovat.
$staged = ([bool]$R.BootManager.EspHas2023) -or ($au -eq 0x4100) -or ($au -eq 0x4000)
if ($staged) {
$plan.Reason='Boot Manager je připravený (staged). Aktivuje se SAMOTNÝM RESTARTEM — víc nastavovat netřeba.'
$plan.NextSteps=@('RESTARTUJTE server (stačí restart, nic dalšího nenastavujte).','BitLocker (PCR7): před restartem ověřte recovery key.','Po restartu spusťte kontrolu — měl by být zelený HOTOVO.')
} else {
$plan.Applicable=$true; $plan.AskUser=$true
$plan.Reason='KEK i DB hotové, ale Boot Manager ještě NENÍ připravený (AvailableUpdates=0x0, ESP není 2023). Je třeba nastavit registry + spustit task a teprve POTÉ restartovat.'
$plan.Caution='Tímto se naplánuje Boot Manager; aktivuje se až RESTARTEM (re-aplikace už hotových certifikátů je neškodná).'
$plan.NextSteps=@('Po tomto kroku RESTARTUJTE server.','Po restartu spusťte kontrolu znovu (nebo -RegisterResume).')
}
}
'UPDATE_FAILED' {
if ($R.EventLog.ById[1795]) {
@@ -622,6 +656,10 @@ function Resolve-RemediationPlan {
$plan.Reason='Secure Boot je v Setup Mode (chybí enrolled Platform Key) — aktualizaci nelze dokončit.'
$plan.NextSteps=@('V UEFI/BIOS obnovte výchozí Secure Boot klíče (enroll PK) / přepněte do User Mode.','Poté spusťte kontrolu znovu.')
}
'BUILD_OUTDATED' {
$plan.Reason='OS má 2023 certifikáty v DB/KEK, ale chybí servicing pro aktivaci 2023 Boot Manageru (WindowsUEFICA2023Capable i UEFICA2023Status jsou prázdné). Boot Manager je stále podepsaný 2011 a tento build neumí nasadit nový — restarty ani remediace nepomohou.'
$plan.NextSteps=@('Nainstalujte nejnovější kumulativní update Windows (Windows Update) a restartujte.','Poté spusťte kontrolu znovu — pak by se Boot Manager měl dát aktualizovat.','Pozn.: velmi staré buildy (např. Server 2016 RTM) neobsahují 2023 boot-manager servicing.')
}
'TASK_MISSING' {
$plan.Reason='Servicing task neexistuje — typicky chybí build z 10/2025 (KB5066835).'
$plan.NextSteps=@('Nainstalujte nejnovější kumulativní update Windows.','Poté spusťte kontrolu znovu.')
@@ -655,7 +693,7 @@ function Save-ResumeState {
param($R, [int]$Cycle)
try {
if (-not (Test-Path $WORK_ROOT)) { New-Item -Path $WORK_ROOT -ItemType Directory -Force | Out-Null }
@{ ComputerName=$env:COMPUTERNAME; Timestamp=(Get-Date).ToString('o'); Cycle=$Cycle; Category=$R.Category
@{ ComputerName=$env:COMPUTERNAME; Timestamp=(Get-Date -Format 'yyyy-MM-dd HH:mm'); Cycle=$Cycle; Category=$R.Category
AvailableUpdates=('0x{0:X}' -f [int]$R.Registry.AvailableUpdates) } | ConvertTo-Json | Set-Content -LiteralPath $STATE_FILE -Encoding UTF8
} catch { }
}
@@ -680,18 +718,30 @@ function Invoke-Remediation {
$out=[ordered]@{ Status='Unknown'; Message=''; After=$null; LogFile=$script:LogFile }
Write-Head 'REMEDIACE'; Add-LogLine 'REMEDIACE START'
Write-Host ' [1/3] Nastavuji registry (MicrosoftUpdateManagedOptIn=1, AvailableUpdates=0x5944) ... ' -NoNewline
# Přečti AvailableUpdates ještě PŘED zápisem — rozhodnutí, jestli ho nastavit nebo zachovat.
$auBefore = (Get-ItemProperty $REG_SECUREBOOT -ErrorAction SilentlyContinue).AvailableUpdates
# "In progress" = nenulová hodnota → systém ji spravuje sám (dle KB5068202 nastavit jen jednou).
# Null nebo 0 → první start nebo re-trigger (Boot Manager není aktivní přesto, že certifikáty jsou OK).
$auInProgress = ($null -ne $auBefore) -and ([int]$auBefore -ne 0)
$auLabel = if ($auInProgress) { '0x{0:X} zachováno (probíhá)' -f [int]$auBefore } else { '0x5944 (nové/reset)' }
Write-Host (" [1/3] Nastavuji registry (MicrosoftUpdateManagedOptIn=1, AvailableUpdates={0}) ... " -f $auLabel) -NoNewline
try {
if (-not (Test-Path $REG_SECUREBOOT)) { New-Item -Path $REG_SECUREBOOT -Force -ErrorAction Stop | Out-Null }
Set-ItemProperty -Path $REG_SECUREBOOT -Name 'MicrosoftUpdateManagedOptIn' -Value 1 -Type DWord -Force -ErrorAction Stop
Set-ItemProperty -Path $REG_SECUREBOOT -Name 'AvailableUpdates' -Value $AVAILABLE_UPDATES_VALUE -Type DWord -Force -ErrorAction Stop
$o=Get-ItemProperty $REG_SECUREBOOT -Name 'HighConfidenceOptOut' -ErrorAction SilentlyContinue
# AvailableUpdates nastavujeme na 0x5944 POUZE pokud ještě nebyl nastaven (null) nebo je 0.
# Pokud je nenulový, hodnotu zachováme — resetování by smazalo již dosažený postup.
if (-not $auInProgress) {
Set-ItemProperty -Path $REG_SECUREBOOT -Name 'AvailableUpdates' -Value $AVAILABLE_UPDATES_VALUE -Type DWord -Force -ErrorAction Stop
}
$o = Get-ItemProperty $REG_SECUREBOOT -Name 'HighConfidenceOptOut' -ErrorAction SilentlyContinue
if ($o -and $o.HighConfidenceOptOut -ne 0) { Set-ItemProperty -Path $REG_SECUREBOOT -Name 'HighConfidenceOptOut' -Value 0 -Type DWord -Force -ErrorAction Stop }
if (-not (Test-Path $REG_SERVICING)) { New-Item -Path $REG_SERVICING -Force -ErrorAction Stop | Out-Null }
$v=(Get-ItemProperty $REG_SECUREBOOT -Name 'AvailableUpdates' -ErrorAction Stop).AvailableUpdates
if ($v -ne $AVAILABLE_UPDATES_VALUE) { throw "Ověření selhalo — AvailableUpdates=$v" }
$vNow = (Get-ItemProperty $REG_SECUREBOOT -ErrorAction Stop).AvailableUpdates
$vExpected = if ($auInProgress) { [int]$auBefore } else { $AVAILABLE_UPDATES_VALUE }
if ([int]$vNow -ne $vExpected) { throw ('Ověření selhalo — AvailableUpdates=0x{0:X}, očekáváno 0x{1:X}' -f [int]$vNow, $vExpected) }
Write-Host 'hotovo' -ForegroundColor Green
Add-LogLine 'Krok 1: MicrosoftUpdateManagedOptIn=1, AvailableUpdates=0x5944 zapsáno a ověřeno'
$auAction = if ($auInProgress) { 'zachováno' } else { 'nastaveno' }
Add-LogLine ('Krok 1: MicrosoftUpdateManagedOptIn=1, AvailableUpdates=0x{0:X} ({1})' -f [int]$vNow, $auAction)
} catch { Write-Host 'CHYBA' -ForegroundColor Red; Write-Line (" {0}" -f $_.Exception.Message) Red; $out.Status='Error'; $out.Message="Zápis registry selhal: $($_.Exception.Message)"; return $out }
if ($SkipScheduledTask) { Write-Line ' [2/3] Servicing task přeskočen (-SkipScheduledTask).' DarkGray }
@@ -731,6 +781,81 @@ function Invoke-Remediation {
#endregion
#region ── Předpoklady + progress ────────────────────────────────────────────
function Get-StageInfo {
param($v)
if ($null -eq $v) { return @{ Step=0; Total=6; Label='nezahájeno' } }
switch ([int]$v) {
0x5944 { return @{ Step=1; Total=6; Label='naplánováno (start)' } }
0x5904 { return @{ Step=2; Total=6; Label='Windows UEFI CA 2023 v DB' } }
0x5104 { return @{ Step=3; Total=6; Label='Option ROM UEFI CA 2023 v DB' } }
0x4104 { return @{ Step=4; Total=6; Label='Microsoft UEFI CA 2023 v DB' } }
0x4100 { return @{ Step=5; Total=6; Label='Boot Manager nasazen na ESP' } }
0x4000 { return @{ Step=6; Total=6; Label='čeká na finální restart' } }
0 { return @{ Step=6; Total=6; Label='dokončeno' } }
default { return @{ Step=1; Total=6; Label=('mezistav 0x{0:X}' -f [int]$v) } }
}
}
function Show-Progress {
param($R, $Prev)
if ($R.Category -notlike 'UPDATE*' -and $R.Category -notlike 'OK*') { return }
Write-Head 'PRŮBĚH (krok a změna od minulého běhu)'
$st = Get-StageInfo $R.Registry.AvailableUpdates
$bar = ('#' * $st.Step) + ('.' * ($st.Total - $st.Step))
Write-Host (" [{0}] krok {1}/{2} — {3}" -f $bar, $st.Step, $st.Total, $st.Label) -ForegroundColor Cyan
if ($Prev) {
$pv = [string]$Prev.AvailableUpdates
$cv = '0x{0:X}' -f [int]$R.Registry.AvailableUpdates
if ($pv -eq $cv) {
Write-Host (" Beze změny od minulého běhu (#{0}, {1})." -f $Prev.Cycle, $Prev.Timestamp) -ForegroundColor Yellow
if ($R.Category -in @('UPDATE_PENDING','UPDATE_PARTIAL')) {
Write-Host ' -> Proces čeká na RESTART. Pokud jste restartoval, spusťte skript znovu; jinak server restartujte.' -ForegroundColor Yellow
}
} else {
Write-Host (" Od minulého běhu: AvailableUpdates {0} -> {1} (postup)" -f $pv, $cv) -ForegroundColor Green
}
}
}
function Get-Prerequisites {
param($R, [bool]$IsAdmin)
$sb = $R.SecureBoot
$list = @()
$list += @{ Label='Spuštěno jako Administrator'; Ok=$IsAdmin; Hard=$true; Note=$(if(-not $IsAdmin){'spusťte PowerShell „Run as administrator"'}) }
$list += @{ Label='UEFI + Secure Boot podporováno'; Ok=($sb.IsUEFI -and $sb.IsSupported); Hard=$true; Note=$(if(-not ($sb.IsUEFI -and $sb.IsSupported)){'Legacy BIOS / nepodporováno'}) }
$list += @{ Label='Secure Boot zapnutý'; Ok=[bool]$sb.IsEnabled; Hard=$true; Note=$(if($sb.IsUEFI -and $sb.IsSupported -and -not $sb.IsEnabled){'zapněte v UEFI'}) }
$list += @{ Label='Ne Setup Mode (enrolled PK)'; Ok=($R.OperatingMode -ne 'Setup'); Hard=$true; Note=$(if($R.OperatingMode -eq 'Setup'){'obnovte Secure Boot klíče v UEFI'}) }
$buildNote = if ($R.TaskExists) { "build $($R.OSBuildFull)" } else { "build $($R.OSBuildFull) — chybí task, nainstalujte 10/2025+ (KB5066835)" }
$list += @{ Label='Build s podporou aktualizace (servicing task)'; Ok=[bool]$R.TaskExists; Hard=$true; Note=$buildNote }
# Boot-manager servicing přítomný? Když jsou certy v DB/KEK, ale WindowsUEFICA2023Capable i
# UEFICA2023Status chybí a boot manager není aktivní → build je příliš starý (nutný Windows Update).
$auP = [int]$R.Registry.AvailableUpdates
$bmStagedP = ([bool]$R.BootManager.EspHas2023) -or ($auP -eq 0x4100) -or ($auP -eq 0x4000)
$staleServ = ($R.Phases['Kek2023'].Done -or $R.Phases['Db2023Windows'].Done) -and (-not $R.Phases['BootManager2023'].Done) -and (-not $bmStagedP) -and ($null -eq $R.Registry.WindowsUEFICA2023Capable) -and ($null -eq $R.Registry.UEFICA2023Status)
$list += @{ Label='Servicing pro Boot Manager 2023 (aktuální build)'; Ok=(-not $staleServ); Hard=$true; Note=$(if($staleServ){"build $($R.OSBuildFull) je starý — chybí 2023 boot-manager servicing, nutný Windows Update"}) }
$list += @{ Label='Zařízení není „Not Supported"'; Ok=($R.Registry.ConfidenceLevel -notlike 'Not Supported*'); Hard=$false; Note=$(if($R.Registry.ConfidenceLevel -like 'Not Supported*'){'ConfidenceLevel: Not Supported — řešení u OEM'}) }
return $list
}
function Show-Prerequisites {
param($Prereqs)
Write-Head 'PŘEDPOKLADY (lze proces dokončit?)'
foreach ($p in $Prereqs) {
$state = if ($p.Ok) { 'Done' } elseif ($p.Hard) { 'Fail' } else { 'Info' }
$nc = if ($p.Ok) { 'DarkGray' } elseif ($p.Hard) { 'Red' } else { 'Yellow' }
Write-Check -State $state -Text $p.Label -Note $p.Note -NoteColor $nc
}
if (@($Prereqs | Where-Object { $_.Hard -and -not $_.Ok }).Count) {
Write-Host ' ! Než spustíte aktualizaci, vyřešte výše označené řádky — jinak proces nelze dokončit.' -ForegroundColor Red
} else {
Write-Host ' Předpoklady splněny — jakmile spustíte, proces lze dokončit.' -ForegroundColor Green
}
}
#endregion
#region ── Main ───────────────────────────────────────────────────────────────
$isWhatIf = [bool]$WhatIfPreference
@@ -742,25 +867,27 @@ Write-Host (" {0} {1}" -f $env:COMPUTERNAME, (Get-Date -Format 'yyyy-MM-dd HH
Write-Rule 'Cyan'
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
Add-LogLine ('===== SPUŠTĚNO {0} | {1} | admin={2} | CheckOnly={3} AssumeYes={4} Force={5} =====' -f $env:COMPUTERNAME, (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $isAdmin, $CheckOnly.IsPresent, $AssumeYes.IsPresent, $Force.IsPresent)
if (-not $isAdmin) { Write-Host ''; Write-Host ' ! Neběží jako Administrator — část kontrol a remediace nebude dostupná.' -ForegroundColor Yellow }
$prev = Get-ResumeState
if ($prev) { Write-Host ''; Write-Host (" Navazuji na předchozí běh (cyklus #{0}, {1}, stav {2})." -f $prev.Cycle, $prev.Timestamp, $prev.Category) -ForegroundColor DarkCyan }
Write-Host ''; Write-Host ' Zjišťuji stav (vč. ověření Boot Manageru)…' -ForegroundColor DarkGray
$result = Invoke-Detection -SkipBootMgrFile:$SkipBootManagerFileCheck.IsPresent
Show-DetectionSummary -R $result
$result = Invoke-Detection -SkipBootMgrFile:$SkipBootManagerFileCheck.IsPresent
$prereqs = Get-Prerequisites -R $result -IsAdmin $isAdmin
# Pořadí: SERVER -> PŘEDPOKLADY -> POSTUP AKTUALIZACE (checklist) -> PRŮBĚH -> registry -> VÝSLEDEK
Show-DetectionSummary -R $result -Prereqs $prereqs -Prev $prev
if ($Detailed) { Show-DetailedDetection -R $result }
if ($result.SecureBoot.IsEnabled -and -not $result.Registry.ServicingKeyExists) {
Write-Host ''; Write-Host ' ! Chybí klíč SecureBoot\Servicing — pravděpodobně build < 10/2025. Nainstalujte KB5066835+.' -ForegroundColor Yellow
}
if ($CheckOnly) {
Write-Host ''; Write-Rule
$code = switch -Wildcard ($result.Category) {
'OK*' { 0 } 'UPDATE_NEEDED' { 1 } 'UPDATE_PARTIAL' { 1 } 'UPDATE_PENDING' { 1 } default { 2 } }
Write-Host (" CHECK: {0} (exit {1})" -f $result.CategoryLabel, $code) -ForegroundColor $result.CategoryColor
Write-Host (" Log: {0}" -f $script:LogFile) -ForegroundColor DarkGray
Save-ResumeState -R $result -Cycle $(if ($prev) { [int]$prev.Cycle } else { 0 })
Flush-Log
if ($PassThru) { $result }
exit $code
}
@@ -769,10 +896,11 @@ $plan = Resolve-RemediationPlan -R $result -ForceMode:$Force.IsPresent
Write-Head 'VYHODNOCENÍ'
if ($plan.Reason) { Write-Host (" {0}" -f $plan.Reason) -ForegroundColor Gray }
$cycle = if ($prev) { [int]$prev.Cycle } else { 0 }
$remediation = $null
if (-not $plan.Applicable) {
if ($plan.NextSteps.Count) { Write-Host ''; Write-Host ' Další kroky:' -ForegroundColor White; $i=1; foreach ($s in $plan.NextSteps) { Write-Host (" {0}. {1}" -f $i,$s) -ForegroundColor Gray; $i++ } }
elseif ($result.Category -like 'OK*') { Write-Host ' Není potřeba žádná akce.' -ForegroundColor Green; Clear-ResumeState }
elseif ($result.Category -like 'OK*') { Write-Host ' Není potřeba žádná akce.' -ForegroundColor Green }
} else {
if ($plan.Caution) { Write-Host (" Pozor: {0}" -f $plan.Caution) -ForegroundColor Yellow }
if (-not $isAdmin) { Write-Host ''; Write-Host ' Remediaci nelze provést bez práv Administrator.' -ForegroundColor Yellow }
@@ -785,11 +913,10 @@ if (-not $plan.Applicable) {
$q='Chcete nyní zahájit / pokračovat v aktualizaci Secure Boot certifikátů?'
$d='Nastaví registry (KB5068202) a spustí servicing task. Server NEBUDE restartován.'
if (Get-UserConsent -Question $q -Detail $d) {
$script:LogActive=$true
$cycle = if ($prev) { [int]$prev.Cycle + 1 } else { 1 }
$cycle = $cycle + 1
Add-LogLine ("Cyklus #{0} | {1} | kategorie={2}" -f $cycle, $result.Hostname, $result.Category)
$remediation = Invoke-Remediation -SkipBootMgrFile:$SkipBootManagerFileCheck.IsPresent
if ($remediation.After) { Save-ResumeState -R $remediation.After -Cycle $cycle }
Flush-Log
} else { Write-Host ''; Write-Host ' Remediace neprovedena (volba uživatele).' -ForegroundColor Yellow }
}
}
@@ -797,7 +924,7 @@ if (-not $plan.Applicable) {
Write-Host ''; Write-Rule 'Cyan'
if ($remediation -and $remediation.Status -eq 'Applied') {
$after=$remediation.After
if ($after.Category -like 'OK*') { Write-Host (" {0} HOTOVO — server je kompletní." -f $SYM_DONE) -ForegroundColor Green; Clear-ResumeState }
if ($after.Category -like 'OK*') { Write-Host (" {0} HOTOVO — server je kompletní." -f $SYM_DONE) -ForegroundColor Green }
else {
Write-Host ' ČÁSTEČNĚ HOTOVO — proces pokračuje po restartu.' -ForegroundColor Yellow
Write-Host ''; Write-Host ' Další kroky:' -ForegroundColor White
@@ -809,11 +936,16 @@ if ($remediation -and $remediation.Status -eq 'Applied') {
Write-Host ' Cíl: AvailableUpdates=0x0 · UEFICA2023Status=Updated · WinUEFICA2023Capable=2.' -ForegroundColor DarkGray
if ($RegisterResume) { Register-Resume } else { Write-Host ' (Tip: -RegisterResume spustí kontrolu po příštím restartu automaticky.)' -ForegroundColor DarkGray }
}
Write-Host ''; Write-Host (" Log: {0}" -f $script:LogFile) -ForegroundColor DarkGray
} elseif ($remediation -and $remediation.Status -eq 'Error') { Write-Host (' CHYBA REMEDIACE — {0}' -f $remediation.Message) -ForegroundColor Red }
else { Write-Host ' KONEC — bez změn na serveru.' -ForegroundColor Cyan }
Write-Host (" Log: {0}" -f $script:LogFile) -ForegroundColor DarkGray
Write-Rule 'Cyan'; Write-Host ''
# Stav pro příští běh (delta) + jednorázový zápis logu
$finalR = if ($remediation -and $remediation.After) { $remediation.After } else { $result }
if ($finalR.Category -like 'OK*') { Clear-ResumeState } else { Save-ResumeState -R $finalR -Cycle $cycle }
Flush-Log
if ($PassThru) { return [pscustomobject]@{ Detection=$result; Plan=$plan; Remediation=$remediation } }
#endregion