Pred vycistenim
This commit is contained in:
@@ -112,9 +112,11 @@ $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
|
||||
@@ -122,15 +124,23 @@ $SYM_PENDING = ' '
|
||||
#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
|
||||
# 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,11 +622,20 @@ 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' {
|
||||
$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é. Boot Manager se aktivuje až po RESTARTU.'
|
||||
$plan.Caution='Nech znovu nastavit registry/task a pak RESTARTUJ.'
|
||||
$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]) {
|
||||
$plan.Reason='Selhání Event 1795 (chyba firmwaru). Příčina je ve firmwaru/hostiteli.'
|
||||
@@ -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
|
||||
# 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,6 +867,7 @@ 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
|
||||
@@ -749,18 +875,19 @@ if ($prev) { Write-Host ''; Write-Host (" Navazuji na předchozí běh (cyklus
|
||||
|
||||
Write-Host ''; Write-Host ' Zjišťuji stav (vč. ověření Boot Manageru)…' -ForegroundColor DarkGray
|
||||
$result = Invoke-Detection -SkipBootMgrFile:$SkipBootManagerFileCheck.IsPresent
|
||||
Show-DetectionSummary -R $result
|
||||
$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
|
||||
|
||||
Reference in New Issue
Block a user