Snad už funkční

This commit is contained in:
Petr Stepan
2026-06-08 12:56:19 +02:00
parent da2b734aa1
commit ee4f8db4ea
+278 -19
View File
@@ -46,7 +46,10 @@ param(
[switch]$CheckOnly, [switch]$CheckOnly,
[switch]$AssumeYes, [switch]$AssumeYes,
[switch]$Force, [switch]$Force,
[switch]$AutoRestart [switch]$AutoRestart,
# Písmeno pro dočasný mount ESP (default S:). Změňte pokud S: je obsazeno.
[ValidatePattern('^[A-Za-z]$')]
[string]$EspDriveLetter = 'S'
) )
$ErrorActionPreference = 'SilentlyContinue' $ErrorActionPreference = 'SilentlyContinue'
@@ -520,16 +523,19 @@ function Get-TaskExists {
#region ── Kategorizace ─────────────────────────────────────────────────────── #region ── Kategorizace ───────────────────────────────────────────────────────
function Test-RemediationComplete { function Test-RemediationComplete {
# Ověří všechny 4 post-remediation podmínky úspěchu. # Ověří všechny podmínky úspěchu: 4 registry + ověření bootloaderu.
# Boot Manager ověření: Capable=2 (registry) NEBO podpis souboru (Is2023).
param($R) param($R)
$cert = $R.Certificates $cert = $R.Certificates
$reg = $R.Registry $reg = $R.Registry
$bm = $R.BootManager
$certsOk = $cert.KEK.Has2023 -and $cert.DB.Has2023WindowsUEFI $certsOk = $cert.KEK.Has2023 -and $cert.DB.Has2023WindowsUEFI
$auVal = [int]$reg.AvailableUpdates $auVal = [int]$reg.AvailableUpdates
$auOk = ($null -ne $reg.AvailableUpdates) -and ($auVal -eq 0 -or $auVal -eq 0x4000) $auOk = ($null -ne $reg.AvailableUpdates) -and ($auVal -eq 0 -or $auVal -eq 0x4000)
$statusOk = $reg.UEFICA2023StatusText -eq 'Updated' $statusOk = $reg.UEFICA2023StatusText -eq 'Updated'
$errorOk = ($null -eq $reg.UEFICA2023Error) -or ([int]$reg.UEFICA2023Error -eq 0) $errorOk = ($null -eq $reg.UEFICA2023Error) -or ([int]$reg.UEFICA2023Error -eq 0)
return $certsOk -and $auOk -and $statusOk -and $errorOk $bmOk = ($reg.WindowsUEFICA2023Capable -eq 2) -or ($bm -and $bm.Checked -and $bm.Is2023)
return $certsOk -and $auOk -and $statusOk -and $errorOk -and $bmOk
} }
function Get-RemediationCategory { function Get-RemediationCategory {
@@ -578,14 +584,19 @@ function Get-RemediationCategory {
Label='Aktualizace pozastavena — problém firmwaru, zkontrolujte update u OEM' } Label='Aktualizace pozastavena — problém firmwaru, zkontrolujte update u OEM' }
} }
# ── Hotovo (všechny 4 post-remediation podmínky) ────────────────────────── # ── Hotovo (registry + bootloader ověřen) ─────────────────────────────────
if (Test-RemediationComplete -R $Result) { if (Test-RemediationComplete -R $Result) {
$bm = $Result.BootManager
$bmReason = if ($reg.WindowsUEFICA2023Capable -eq 2) { 'Capable=2' } `
elseif ($bm -and $bm.Checked -and $bm.Is2023) { 'soubor ověřen' } `
else { '' }
$doneLabel = if ($bmReason) { "HOTOVO — 2023 certifikáty + bootloader ověřen ($bmReason)" } `
else { 'HOTOVO — 2023 certifikáty nasazeny' }
if ($cert.AnyExpiring2011) { if ($cert.AnyExpiring2011) {
return @{ Code='OK_TRANSITION'; Color='Green' return @{ Code='OK_TRANSITION'; Color='Green'
Label='HOTOVO — 2023 certifikáty nasazeny (staré 2011 ještě přítomné, je to normální)' } Label="$doneLabel (staré 2011 ještě přítomné, je to normální)" }
} }
return @{ Code='OK'; Color='Green' return @{ Code='OK'; Color='Green'; Label=$doneLabel }
Label='HOTOVO — 2023 certifikáty nasazeny, servisování dokončeno' }
} }
# ── Boot Manager staged, čeká na restart ───────────────────────────────── # ── Boot Manager staged, čeká na restart ─────────────────────────────────
@@ -597,18 +608,36 @@ function Get-RemediationCategory {
$certsRequiredOk = $cert.KEK.Has2023 -and $cert.DB.Has2023WindowsUEFI $certsRequiredOk = $cert.KEK.Has2023 -and $cert.DB.Has2023WindowsUEFI
$auNow = [int]$reg.AvailableUpdates $auNow = [int]$reg.AvailableUpdates
$errOk = ($null -eq $reg.UEFICA2023Error) -or ([int]$reg.UEFICA2023Error -eq 0) $errOk = ($null -eq $reg.UEFICA2023Error) -or ([int]$reg.UEFICA2023Error -eq 0)
$bm = $Result.BootManager
$bmOk = ($reg.WindowsUEFICA2023Capable -eq 2) -or ($bm -and $bm.Checked -and $bm.Is2023)
# ── Certy přítomny + AU=0x0 → hotovo ───────────────────────────────────── # ── Certy přítomny + AU=0x0 + bootloader ověřen → hotovo ─────────────────
# UEFICA2023Status může být NotStarted u strojů kde certy byly nainstalovány # Poznámka: null AU (chybějící Servicing klíč) se neuznává jako hotovo.
# starší cestou (před zavedením nové servicing infrastruktury). Pokud jsou if ($certsRequiredOk -and ($null -ne $reg.AvailableUpdates) -and $auNow -eq 0 -and $errOk -and $bmOk) {
# požadované certifikáty v DB/KEK a AvailableUpdates=0x0, považujeme za hotovo. $bmReason = if ($reg.WindowsUEFICA2023Capable -eq 2) { 'Capable=2' } `
if ($certsRequiredOk -and $auNow -eq 0 -and $errOk) { elseif ($bm -and $bm.Checked -and $bm.Is2023) { 'soubor ověřen' } `
else { '' }
$doneLabel = if ($bmReason) { "Certifikáty aplikovány — bootloader ověřen ($bmReason)" } `
else { 'Certifikáty aplikovány — AvailableUpdates=0x0' }
if ($cert.AnyExpiring2011) { if ($cert.AnyExpiring2011) {
return @{ Code='OK_TRANSITION'; Color='Green' return @{ Code='OK_TRANSITION'; Color='Green'
Label='HOTOVO — 2023 certifikáty nasazeny (staré 2011 ještě přítomné, je to normální)' } Label="$doneLabel (staré 2011 ještě přítomné)" }
} }
return @{ Code='OK'; Color='Green' return @{ Code='OK'; Color='Green'; Label=$doneLabel }
Label='HOTOVO — 2023 certifikáty nasazeny, AvailableUpdates=0x0' } }
# ── Certy přítomny, AU=0x0, ale bootloader dosud nepoužívá 2023 CA ───────
# Systém potřebuje spustit task znovu → staged BM 2023 → restart.
if ($certsRequiredOk -and ($null -ne $reg.AvailableUpdates) -and $auNow -eq 0 -and $errOk -and -not $bmOk) {
$bmNote = if ($bm -and $bm.Checked -and $bm.Is2011) {
"soubor podepsán starší CA: $($bm.IssuerCA)"
} elseif ($bm -and $bm.Error) {
"soubor: $($bm.Error)"
} else {
"Capable=$($reg.WindowsUEFICA2023Capable)"
}
return @{ Code='UPDATE_BOOTMANAGER'; Color='Yellow'
Label="Certifikáty v DB/KEK — bootloader dosud nepoužívá 2023 CA ($bmNote)" }
} }
# ── Starý build: certy přítomny, ale servicing infrastruktura chybí ────── # ── Starý build: certy přítomny, ale servicing infrastruktura chybí ──────
@@ -633,6 +662,187 @@ function Get-RemediationCategory {
#endregion #endregion
#region ── Detekce bootloaderu ────────────────────────────────────────────────
function Get-EspBootmgfwCopy {
# Zkopíruje bootmgfw.efi z aktivního ESP do %TEMP% a vrátí výsledek.
# Logika převzata z referenčního scriptu (mathisokle/SecureBoot-CA2023-Automatic-Update).
# Nikdy nepracuje přímo s live souborem — vždy nejprve kopie.
$out = @{ Success=$false; TempPath=$null; Source=$null; Error=$null }
$tempDir = Join-Path $env:TEMP 'SecureBootCA2023'
if (-not (Test-Path -LiteralPath $tempDir)) {
New-Item -Path $tempDir -ItemType Directory -Force | Out-Null
}
$dst = Join-Path $tempDir ('bootmgfw_{0}_{1}.efi' -f $env:COMPUTERNAME, ([guid]::NewGuid().ToString('N')))
$dl = $EspDriveLetter.ToUpper()
$driveRoot = "${dl}:"
# Pokus 1: ESP má přiřazené písmeno — prohledat všechna písmena AZ
foreach ($d in [char[]]('A'..'Z')) {
$p = "${d}:\EFI\Microsoft\Boot\bootmgfw.efi"
if (Test-Path -LiteralPath $p -ErrorAction SilentlyContinue) {
try {
Copy-Item -LiteralPath $p -Destination $dst -Force -ErrorAction Stop
$out.Success = $true; $out.TempPath = $dst; $out.Source = $p
return $out
} catch { $out.Error = $_.Exception.Message }
}
}
# Pokus 2: mountvol $EspDriveLetter: /S
# Připojí aktivní EFI System Partition na zadané písmeno (default S:).
# Pokud je písmeno obsazeno, změní je parametrem -EspDriveLetter.
if (-not (Get-PSDrive -Name $dl -ErrorAction SilentlyContinue)) {
Add-LogLine ("ESP mount: mountvol ${driveRoot} /S")
& mountvol $driveRoot /S 2>&1 | Out-Null
Start-Sleep -Seconds 2
}
if (-not (Test-Path -LiteralPath "${driveRoot}\" -ErrorAction SilentlyContinue)) {
$out.Error = "Nepodařilo se připojit ESP na ${driveRoot} — zkuste jiné písmeno parametrem -EspDriveLetter"
return $out
}
try {
$src = "${driveRoot}\EFI\Microsoft\Boot\bootmgfw.efi"
if (-not (Test-Path -LiteralPath $src -ErrorAction SilentlyContinue)) {
$out.Error = "bootmgfw.efi nenalezen na ${driveRoot} (ESP připojen, ale soubor chybí)"
return $out
}
Add-LogLine ("ESP copy: ${src}${dst}")
Copy-Item -LiteralPath $src -Destination $dst -Force -ErrorAction Stop
$out.Success = $true; $out.TempPath = $dst; $out.Source = $src
} catch {
$out.Error = "Chyba kopírování z ESP: $($_.Exception.Message)"
} finally {
if (Get-PSDrive -Name $dl -ErrorAction SilentlyContinue) {
Add-LogLine ("ESP dismount: mountvol ${driveRoot} /D")
& mountvol $driveRoot /D 2>&1 | Out-Null
}
}
return $out
}
function Get-BootManagerEvidence {
# Ověří CA verzi Boot Manageru (bootmgfw.efi) třemi vrstvami důkazů:
# 1. certutil -dump — čte embedded PKCS#7 blob přímo z PE, bez local cert store
# 2. X509Chain — záloha pokud certutil chybí (závisí na local store)
# 3. Event ID 1799 — "Boot Manager signed with Windows UEFI CA 2023 was installed"
#
# Vrátí hashtable s: Checked, Is2023, Is2011, CAVersion, IssuerCA,
# SignerSubject, Source, Method, Error
$out = [ordered]@{
Checked = $false # podařilo se ověřit?
Is2023 = $false # bootloader podepsán 2023 CA?
Is2011 = $false # bootloader podepsán 2011 CA?
CAVersion = $null # '2023', '2011', nebo $null
IssuerCA = $null # název CA (krátký)
SignerSubject = $null # leaf cert Subject z AuthSig (pro log)
Source = $null # původní cesta na ESP
Method = $null # 'certutil', 'x509chain', 'event1799'
Error = $null # chybová zpráva
}
# ── Krok 1: Zkopírovat bootmgfw.efi z aktivního ESP ───────────────────────
$espCopy = Get-EspBootmgfwCopy
if (-not $espCopy.Success) {
$out.Error = $espCopy.Error
} else {
$out.Source = $espCopy.Source
$file = $espCopy.TempPath
try {
# ── Krok 2a: certutil -dump (primární) ────────────────────────────
$certutil = Get-Command certutil.exe -ErrorAction SilentlyContinue
if ($certutil) {
$raw = & certutil.exe -dump $file 2>&1 | Out-String
$out.Checked = $true
$out.Method = 'certutil'
if ($raw -match 'Windows Production PCA 2023') {
$out.Is2023 = $true; $out.CAVersion = '2023'
$out.IssuerCA = 'Windows Production PCA 2023'
} elseif ($raw -match 'Windows UEFI CA 2023') {
$out.Is2023 = $true; $out.CAVersion = '2023'
$out.IssuerCA = 'Windows UEFI CA 2023'
} elseif ($raw -match 'Windows Production PCA 2011') {
$out.Is2011 = $true; $out.CAVersion = '2011'
$out.IssuerCA = 'Windows Production PCA 2011'
} elseif ($raw -match 'Windows UEFI CA 2011') {
$out.Is2011 = $true; $out.CAVersion = '2011'
$out.IssuerCA = 'Windows UEFI CA 2011'
}
# Pokud certutil nenašel žádnou CA → out.CAVersion zůstane $null
}
# ── Krok 2b: Get-AuthenticodeSignature ────────────────────────────
# Vždy — pro SignerSubject do logu. Když certutil nebyl dostupný,
# X509Chain slouží jako záloha pro Is2023/Is2011.
try {
$sig = Get-AuthenticodeSignature -FilePath $file -ErrorAction Stop
if ($sig.SignerCertificate) {
$out.SignerSubject = $sig.SignerCertificate.Subject
if (-not $certutil) {
# X509Chain fallback — závisí na local cert store
$out.Checked = $true; $out.Method = 'x509chain'
$chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
$chain.ChainPolicy.RevocationMode = `
[System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck
$chain.Build($sig.SignerCertificate) | Out-Null
foreach ($el in $chain.ChainElements) {
$s = $el.Certificate.Subject
if ($s -like '*Windows UEFI CA 2023*' -or $s -like '*Windows Production PCA 2023*') {
$out.Is2023 = $true; $out.CAVersion = '2023'
$out.IssuerCA = ($s -replace '^CN=([^,]+).*','$1').Trim()
break
}
}
if (-not $out.Is2023) {
foreach ($el in $chain.ChainElements) {
$s = $el.Certificate.Subject
if ($s -like '*Windows Production PCA 2011*' -or $s -like '*Windows UEFI CA 2011*') {
$out.Is2011 = $true; $out.CAVersion = '2011'
$out.IssuerCA = ($s -replace '^CN=([^,]+).*','$1').Trim()
break
}
}
}
}
}
} catch { } # AuthSig je doplňkový — chybu ignorujeme
} catch {
$out.Error = $_.Exception.Message
} finally {
Remove-Item $file -Force -ErrorAction SilentlyContinue
}
}
# ── Krok 3: Event ID 1799 — terciální evidence ────────────────────────────
# Zpráva "Boot Manager signed with Windows UEFI CA 2023 was installed successfully"
# Používá se jen jako podpora pokud certutil/chain ještě neprokázaly 2023.
if (-not $out.Is2023) {
try {
$ev1799 = Get-WinEvent -FilterHashtable @{ LogName='System'; Id=1799 } `
-MaxEvents 5 -ErrorAction SilentlyContinue |
Where-Object { $_.Message -match 'Windows UEFI CA 2023.*installed successfully' } |
Select-Object -First 1
if ($ev1799) {
$out.Is2023 = $true
$out.CAVersion = '2023'
$out.IssuerCA = 'Windows UEFI CA 2023'
$out.Method = if ($out.Method) { "$($out.Method)+event1799" } else { 'event1799' }
$out.Checked = $true
}
} catch { }
}
return $out
}
#endregion
#region ── Detekce — orchestrace ────────────────────────────────────────────── #region ── Detekce — orchestrace ──────────────────────────────────────────────
function Invoke-Detection { function Invoke-Detection {
@@ -655,6 +865,7 @@ function Invoke-Detection {
OperatingMode = 'Unknown' OperatingMode = 'Unknown'
BitLocker = $null BitLocker = $null
Certificates = $null Certificates = $null
BootManager = $null
Registry = Get-RegistryStatus Registry = Get-RegistryStatus
EventLog = Get-EventLogStatus EventLog = Get-EventLogStatus
TaskExists = Get-TaskExists TaskExists = Get-TaskExists
@@ -666,6 +877,9 @@ function Invoke-Detection {
if ($R.SecureBoot.IsUEFI -and $R.SecureBoot.IsSupported) { if ($R.SecureBoot.IsUEFI -and $R.SecureBoot.IsSupported) {
$R.OperatingMode = Get-SecureBootMode $R.OperatingMode = Get-SecureBootMode
$R.Certificates = Get-CertificateStatus $R.Certificates = Get-CertificateStatus
# Verifikace Boot Manageru (certutil + X509Chain + Event 1799)
$R.BootManager = Get-BootManagerEvidence
} else { } else {
$R.Certificates = [ordered]@{ $R.Certificates = [ordered]@{
KEK = [ordered]@{ KEK = [ordered]@{
@@ -683,6 +897,11 @@ function Invoke-Detection {
DbxRevokesPCA2011 = $false DbxRevokesPCA2011 = $false
AnyExpiring2011 = $false AnyExpiring2011 = $false
} }
$R.BootManager = @{
Checked = $false; Is2023 = $false; Is2011 = $false
CAVersion = $null; IssuerCA = $null; SignerSubject = $null
Source = $null; Method = $null; Error = 'Secure Boot nedostupný'
}
} }
$R.BitLocker = Get-BitLockerInfo $R.BitLocker = Get-BitLockerInfo
@@ -720,7 +939,7 @@ function Show-Prerequisites {
} }
function Show-Certificates { function Show-Certificates {
param($Cert) param($Cert, $BM)
Write-Head 'CERTIFIKÁTY' Write-Head 'CERTIFIKÁTY'
# Najdi expiry datum pro přítomné povinné certifikáty # Najdi expiry datum pro přítomné povinné certifikáty
@@ -755,6 +974,34 @@ function Show-Certificates {
Add-LogLine ("[ ] $($item.Label) — chybí (volitelný)") Add-LogLine ("[ ] $($item.Label) — chybí (volitelný)")
} }
} }
# ── Boot Manager — verze CA z verifikace souboru ─────────────────────────
Write-Host ''
$bmLabel = 'Boot Manager (bootmgfw.efi)'
$bmMethod = if ($BM -and $BM.Method) { " [$($BM.Method)]" } else { '' }
if ($BM -and $BM.Is2023) {
$detail = "aktuální — CA: $($BM.IssuerCA)$bmMethod"
Write-Host (" [{0}] {1,-44} {2}" -f $SYM_DONE, $bmLabel, $detail) -ForegroundColor Green
Add-LogLine "[+] Boot Manager: $detail"
} elseif ($BM -and $BM.Is2011) {
$detail = "ZASTARALÝ — CA: $($BM.IssuerCA) → nutná aktualizace$bmMethod"
Write-Host (" [{0}] {1,-44} {2}" -f $SYM_FAIL, $bmLabel, $detail) -ForegroundColor Red
Add-LogLine "[!] Boot Manager: $detail"
} elseif ($BM -and $BM.Checked) {
# Ověření proběhlo ale CA nebyla identifikována
$signerShort = if ($BM.SignerSubject) {
($BM.SignerSubject -replace '^CN=([^,]+).*','$1').Trim()
} else { '?' }
$detail = "CA nezjištěna — signer: $signerShort$bmMethod"
Write-Host (" [{0}] {1,-44} {2}" -f $SYM_PENDING, $bmLabel, $detail) -ForegroundColor DarkGray
Add-LogLine "[ ] Boot Manager: $detail"
} elseif ($BM) {
$errNote = if ($BM.Error) { " ($($BM.Error))" } else { '' }
$detail = "nedostupný$errNote"
Write-Host (" [{0}] {1,-44} {2}" -f $SYM_PENDING, $bmLabel, $detail) -ForegroundColor DarkGray
Add-LogLine "[ ] Boot Manager: $detail"
}
} }
function Show-Registry { function Show-Registry {
@@ -807,16 +1054,21 @@ function Show-Events {
function Show-Status { function Show-Status {
# Zobrazí všechny 4 sekce + celkový stav. # Zobrazí všechny 4 sekce + celkový stav.
# STAV se nezobrazí, pokud některá hard prerekvizita selhala — ta musí být
# vyřešena dřív, než má kategorie (computed z neúplných dat) jakýkoliv smysl.
param($R, $Prereqs) param($R, $Prereqs)
Show-Prerequisites -Prereqs $Prereqs Show-Prerequisites -Prereqs $Prereqs
Show-Certificates -Cert $R.Certificates Show-Certificates -Cert $R.Certificates -BM $R.BootManager
Show-Registry -Reg $R.Registry Show-Registry -Reg $R.Registry
Show-Events -Evt $R.EventLog Show-Events -Evt $R.EventLog
$anyHardFail = [bool]@($Prereqs | Where-Object { $_.Hard -and -not $_.Ok }).Count
if (-not $anyHardFail) {
Write-Host '' Write-Host ''
Write-Host ' STAV: ' -ForegroundColor Gray -NoNewline Write-Host ' STAV: ' -ForegroundColor Gray -NoNewline
Write-Host $R.CategoryLabel -ForegroundColor $R.CategoryColor Write-Host $R.CategoryLabel -ForegroundColor $R.CategoryColor
Add-LogLine ("STAV: {0}" -f $R.CategoryLabel) Add-LogLine ("STAV: {0}" -f $R.CategoryLabel)
} }
}
function Show-TwoRestartBlock { function Show-TwoRestartBlock {
param($R) param($R)
@@ -1193,8 +1445,8 @@ $cycle = if ($prev) { [int]$prev.Cycle } else { 0 }
$certsReady = $result.Certificates.KEK.Has2023 -and $result.Certificates.DB.Has2023WindowsUEFI $certsReady = $result.Certificates.KEK.Has2023 -and $result.Certificates.DB.Has2023WindowsUEFI
if ($certsReady -and ($result.Category -like 'OK*') -and -not $Force) { if ($certsReady -and ($result.Category -like 'OK*') -and -not $Force) {
Write-Host '' Write-Host ''
Write-Host ' Povinné 2023 certifikáty (Windows UEFI CA 2023 + KEK 2K CA 2023) jsou' -ForegroundColor Green Write-Host (" {0}" -f $result.CategoryLabel) -ForegroundColor $result.CategoryColor
Write-Host ' již přítomny v UEFI databázích. Na tomto serveru není nutná žádná akce.' -ForegroundColor Green Write-Host ' Na tomto serveru není nutná žádná remediace.' -ForegroundColor Green
Write-Host ' (Tip: parametr -Force vynutí remediaci i v tomto stavu.)' -ForegroundColor DarkGray Write-Host ' (Tip: parametr -Force vynutí remediaci i v tomto stavu.)' -ForegroundColor DarkGray
Write-Host ''; Write-Rule 'Cyan' Write-Host ''; Write-Rule 'Cyan'
Write-Host (" Log: {0}" -f $script:LogFile) -ForegroundColor DarkGray Write-Host (" Log: {0}" -f $script:LogFile) -ForegroundColor DarkGray
@@ -1209,6 +1461,13 @@ if ($certsReady -and $Force) {
Write-Host ' ! Certifikáty jsou přítomny, ale -Force umožňuje spustit remediaci znovu.' -ForegroundColor Yellow Write-Host ' ! Certifikáty jsou přítomny, ale -Force umožňuje spustit remediaci znovu.' -ForegroundColor Yellow
} }
# ── UPDATE_BOOTMANAGER: certy OK, ale bootloader nepoužívá 2023 CA ───────────
if ($result.Category -eq 'UPDATE_BOOTMANAGER') {
Write-Host ''
Write-Host ' Certifikáty jsou v UEFI databázích, ale Boot Manager dosud nepoužívá 2023 CA.' -ForegroundColor Yellow
Write-Host ' Remediace spustí task, který Boot Manager 2023 připraví — poté bude nutný restart.' -ForegroundColor Gray
}
# ── AU=0x4100: Boot Manager staged, stačí RESTART ──────────────────────────── # ── AU=0x4100: Boot Manager staged, stačí RESTART ────────────────────────────
$auNow = [int]$result.Registry.AvailableUpdates $auNow = [int]$result.Registry.AvailableUpdates
if ($auNow -eq 0x4100) { if ($auNow -eq 0x4100) {