commit 9a230866a2535672d7df3fa3a16238ea3e190338 Author: Petr Stepan Date: Fri Jun 5 14:05:27 2026 +0000 Initial commit: detekční skript, remediační skript a README - Invoke-SecureBootAudit.ps1: audit Secure Boot certifikátů (Fáze 1) - detekce prostředí (Physical/Hyper-V VM/VMware VM) - parsování EFI_SIGNATURE_LIST, detekce 2011/2023 certifikátů - registry stav, Event Log analýza, kategorizace, JSON výstup - Set-SecureBootCertificateUpdate.ps1: remediace dle KB5068202 - AvailableUpdates = 0x5944 - scheduled task s wait smyčkou (timeout 120s) - WhatIf, Force, VerifyOnly, WinRM - README.md: popis problému, detekce stavů, remediační postup diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..c24ff2b Binary files /dev/null and b/.DS_Store differ diff --git a/Invoke-SecureBootAudit.ps1 b/Invoke-SecureBootAudit.ps1 new file mode 100644 index 0000000..56aa9bc --- /dev/null +++ b/Invoke-SecureBootAudit.ps1 @@ -0,0 +1,655 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Audituje stav Secure Boot certifikátů na Windows Serveru. + +.DESCRIPTION + Detekuje podporu Secure Boot, stav povolení, přítomnost certifikátů (expirující 2011 + vs. nové 2023 náhrady), stav v registrech a relevantní záznamy v Event Logu. + Vrací strukturovaný JSON výstup + human-readable souhrn. + + Skript nevyžaduje žádné externí moduly (pure PowerShell 5.1+). + Toleruje prostředí bez Secure Boot (Legacy BIOS, Gen1 VM apod.). + + Spouštění na vzdáleném serveru: + Invoke-Command -ComputerName SERVER01 -FilePath .\Invoke-SecureBootAudit.ps1 + + Spouštění lokálně s uložením výsledku: + .\Invoke-SecureBootAudit.ps1 -OutputPath C:\Audit\result.json + +.PARAMETER OutputPath + Cesta pro uložení JSON výsledku. Pokud není zadána, JSON se nevypisuje na konzoli + (použijte -JsonOnly nebo -PassThru pro programatické zpracování). + +.PARAMETER JsonOnly + Vypíše pouze JSON na stdout, bez human-readable souhrnue. + +.PARAMETER PassThru + Vrátí výsledek jako PowerShell objekt (vhodné pro Invoke-Command pipeline). + +.EXAMPLE + .\Invoke-SecureBootAudit.ps1 + +.EXAMPLE + .\Invoke-SecureBootAudit.ps1 -OutputPath C:\Audit\SERVER01.json + +.EXAMPLE + Invoke-Command -ComputerName SERVER01 -FilePath .\Invoke-SecureBootAudit.ps1 -ArgumentList $null,$false,$true + +.NOTES + Vyžaduje spuštění jako Administrator pro přístup k UEFI databázím a Event Logu. + Relevantní KB: KB5062710, KB5068202, KB5085046 +#> + +[CmdletBinding()] +param( + [string]$OutputPath, + [switch]$JsonOnly, + [switch]$PassThru +) + +$ErrorActionPreference = 'SilentlyContinue' + +#region ── Helper functions ────────────────────────────────────────────────── + +function Get-EnvironmentType { + try { + $cs = Get-WmiObject Win32_ComputerSystem -ErrorAction Stop + $mfr = [string]$cs.Manufacturer + $model = [string]$cs.Model + + if ($mfr -like '*VMware*') { return 'VMware VM' } + if ($mfr -like '*Microsoft*' -and $model -eq 'Virtual Machine') { return 'Hyper-V VM' } + if ($model -like '*Virtual*' -or $mfr -like '*QEMU*' -or $mfr -like '*Xen*') { + return 'Other VM' + } + return 'Physical' + } catch { + return 'Unknown' + } +} + +function Get-HardwareInfo { + $hw = [ordered]@{ + Manufacturer = 'Unknown' + Model = 'Unknown' + SerialNumber = 'Unknown' + FirmwareType = 'Unknown' + BiosVersion = 'Unknown' + BiosReleaseDate = 'Unknown' + } + + try { + $cs = Get-WmiObject Win32_ComputerSystem -ErrorAction Stop + $hw.Manufacturer = [string]$cs.Manufacturer + $hw.Model = [string]$cs.Model + } catch {} + + try { + $bios = Get-WmiObject Win32_BIOS -ErrorAction Stop + $hw.BiosVersion = [string]$bios.SMBIOSBIOSVersion + $hw.SerialNumber = [string]$bios.SerialNumber + if ($bios.ReleaseDate) { + $hw.BiosReleaseDate = [Management.ManagementDateTimeConverter]::ToDateTime( + $bios.ReleaseDate).ToString('yyyy-MM-dd') + } + } catch {} + + # Firmware type — primárně z registry, fallback přes přítomnost SecureBoot klíče + $fwTypeKey = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control' ` + -Name PEFirmwareType -ErrorAction SilentlyContinue + if ($fwTypeKey) { + $hw.FirmwareType = if ($fwTypeKey.PEFirmwareType -eq 2) { 'UEFI' } else { 'Legacy BIOS' } + } elseif (Test-Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot') { + $hw.FirmwareType = 'UEFI' + } else { + $hw.FirmwareType = 'Legacy BIOS' + } + + return $hw +} + +function Get-SecureBootState { + $state = [ordered]@{ + IsUEFI = $false + IsSupported = $false + IsEnabled = $false + ConfirmResult = 'Unknown' + Error = $null + } + + $fwTypeKey = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control' ` + -Name PEFirmwareType -ErrorAction SilentlyContinue + $state.IsUEFI = ($fwTypeKey -and $fwTypeKey.PEFirmwareType -eq 2) ` + -or (Test-Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot') + + if (-not $state.IsUEFI) { return $state } + + try { + $result = Confirm-SecureBootUEFI -ErrorAction Stop + $state.IsSupported = $true + $state.IsEnabled = [bool]$result + $state.ConfirmResult = $result.ToString() + } catch { + $msg = $_.Exception.Message + if ($msg -like '*not supported*' -or $msg -like '*Cmdlet not supported*') { + $state.IsSupported = $false + $state.ConfirmResult = 'NotSupported' + } elseif ($msg -like '*disabled*') { + $state.IsSupported = $true + $state.IsEnabled = $false + $state.ConfirmResult = 'Disabled' + } else { + $state.IsSupported = $true + $state.IsEnabled = $false + $state.ConfirmResult = "Error" + $state.Error = $msg + } + } + + return $state +} + +function Parse-EFISignatureList { + <# + .SYNOPSIS + Parsuje EFI_SIGNATURE_LIST strukturu a vrátí X.509 certifikáty. + #> + param([byte[]]$Bytes) + + $certs = @() + if (-not $Bytes -or $Bytes.Length -lt 28) { return $certs } + + # EFI_CERT_X509_GUID {a5c059a1-94e4-4aa7-87b5-ab155c2bf072} v little-endian + $X509_GUID = [byte[]]( + 0xa1,0x59,0xc0,0xa5, # Data1 LE + 0xe4,0x94, # Data2 LE + 0xa7,0x4a, # Data3 LE + 0x87,0xb5,0xab,0x15,0x5c,0x2b,0xf0,0x72 # Data4 BE + ) + + $offset = 0 + while ($offset + 28 -le $Bytes.Length) { + $sigTypeGUID = $Bytes[$offset..($offset + 15)] + $sigListSize = [BitConverter]::ToUInt32($Bytes, $offset + 16) + $sigHeaderSize = [BitConverter]::ToUInt32($Bytes, $offset + 20) + $sigSize = [BitConverter]::ToUInt32($Bytes, $offset + 24) + + if ($sigListSize -lt 28 -or $sigListSize -gt ($Bytes.Length - $offset)) { break } + + # Porovnat GUID + $isX509 = $true + for ($i = 0; $i -lt 16; $i++) { + if ($sigTypeGUID[$i] -ne $X509_GUID[$i]) { $isX509 = $false; break } + } + + if ($isX509 -and $sigSize -gt 16) { + $sigOffset = $offset + 28 + $sigHeaderSize + $listEnd = $offset + $sigListSize + + while ($sigOffset + $sigSize -le $listEnd) { + # Přeskočit 16 B SignatureOwner GUID, zbytek je DER certifikát + $certOffset = $sigOffset + 16 + $certSize = [int]$sigSize - 16 + + if ($certOffset + $certSize -le $Bytes.Length -and $certSize -gt 0) { + $certBytes = $Bytes[$certOffset..($certOffset + $certSize - 1)] + try { + $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2( + , [byte[]]$certBytes) + $certs += $cert + } catch { } + } + $sigOffset += $sigSize + } + } + + $offset += $sigListSize + } + + return $certs +} + +function Convert-CertToInfo { + param([System.Security.Cryptography.X509Certificates.X509Certificate2]$Cert) + return [ordered]@{ + Subject = $Cert.Subject + Thumbprint = $Cert.Thumbprint + NotBefore = $Cert.NotBefore.ToString('yyyy-MM-dd') + NotAfter = $Cert.NotAfter.ToString('yyyy-MM-dd') + } +} + +function Get-CertificateStatus { + $status = [ordered]@{ + KEK = [ordered]@{ + Has2011 = $false + Has2023 = $false + Certs2011 = @() + Certs2023 = @() + Error = $null + } + DB = [ordered]@{ + Has2011UEFI = $false + Has2011WindowsPCA = $false + Has2023UEFI = $false + Has2023OptionROM = $false + Has2023WindowsUEFI = $false + Certs2011 = @() + Certs2023 = @() + Error = $null + } + AnyExpiring2011 = $false + AllReplacements2023 = $false + } + + # ── KEK databáze ── + try { + $kekObj = Get-SecureBootUEFI -Name KEK -ErrorAction Stop + $kekCerts = Parse-EFISignatureList -Bytes $kekObj.Bytes + + foreach ($cert in $kekCerts) { + $subj = $cert.Subject + $info = Convert-CertToInfo $cert + + if ($subj -like '*KEK CA 2011*') { + $status.KEK.Has2011 = $true + $status.KEK.Certs2011 += $info + } + if ($subj -like '*KEK 2K CA 2023*' -or ($subj -like '*KEK*CA 2023*')) { + $status.KEK.Has2023 = $true + $status.KEK.Certs2023 += $info + } + } + } catch { + $status.KEK.Error = $_.Exception.Message + } + + # ── DB databáze ── + try { + $dbObj = Get-SecureBootUEFI -Name db -ErrorAction Stop + $dbCerts = Parse-EFISignatureList -Bytes $dbObj.Bytes + + foreach ($cert in $dbCerts) { + $subj = $cert.Subject + $info = Convert-CertToInfo $cert + + # 2011 expirující certifikáty + if ($subj -like '*UEFI CA 2011*') { + $status.DB.Has2011UEFI = $true + $status.DB.Certs2011 += $info + } + if ($subj -like '*Windows Production PCA 2011*' -or $subj -like '*Windows PCA 2011*') { + $status.DB.Has2011WindowsPCA = $true + $status.DB.Certs2011 += $info + } + + # 2023 náhradní certifikáty + if ($subj -like '*UEFI CA 2023*' -and + $subj -notlike '*Option ROM*' -and + $subj -notlike '*Windows UEFI*') { + $status.DB.Has2023UEFI = $true + $status.DB.Certs2023 += $info + } + if ($subj -like '*Option ROM UEFI CA 2023*') { + $status.DB.Has2023OptionROM = $true + $status.DB.Certs2023 += $info + } + if ($subj -like '*Windows UEFI CA 2023*') { + $status.DB.Has2023WindowsUEFI = $true + $status.DB.Certs2023 += $info + } + } + } catch { + $status.DB.Error = $_.Exception.Message + } + + $status.AnyExpiring2011 = $status.KEK.Has2011 -or + $status.DB.Has2011UEFI -or + $status.DB.Has2011WindowsPCA + + $status.AllReplacements2023 = $status.KEK.Has2023 -and + $status.DB.Has2023UEFI -and + $status.DB.Has2023OptionROM -and + $status.DB.Has2023WindowsUEFI + + return $status +} + +function Get-RegistryStatus { + $reg = [ordered]@{ + SecureBootEnabled = $null + AvailableUpdates = $null + HighConfidenceOptOut = $null + ServicingKeyExists = $false + UEFICA2023Status = $null + UEFICA2023StatusText = 'KeyNotPresent' + UEFICA2023Error = $null + WindowsUEFICA2023Capable = $null + } + + # Hlavní klíč + $mainProps = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot' ` + -ErrorAction SilentlyContinue + if ($mainProps) { + $reg.SecureBootEnabled = $mainProps.SecureBootEnabled + $reg.AvailableUpdates = $mainProps.AvailableUpdates + $reg.HighConfidenceOptOut = $mainProps.HighConfidenceOptOut + } + + # Servicing podklíč + $svcProps = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing' ` + -ErrorAction SilentlyContinue + if ($svcProps) { + $reg.ServicingKeyExists = $true + $reg.UEFICA2023Status = $svcProps.UEFICA2023Status + $reg.UEFICA2023Error = $svcProps.UEFICA2023Error + $reg.WindowsUEFICA2023Capable = $svcProps.WindowsUEFICA2023Capable + + $reg.UEFICA2023StatusText = switch ($reg.UEFICA2023Status) { + 0 { 'NotStarted' } + 1 { 'InProgress' } + 2 { 'Success' } + 3 { 'Failed' } + $null { 'KeyNotPresent' } + default { "Unknown ($($reg.UEFICA2023Status))" } + } + } + + return $reg +} + +function Get-EventLogStatus { + $evtStatus = [ordered]@{ + LastEventId = $null + LastEventTime = $null + LastEventMessage = $null + ConfidenceLevel = 'NoRelevantEvents' + RelevantEvents = @() + Error = $null + } + + $relevantIds = @(1795, 1796, 1800, 1801, 1802, 1803, 1808) + + try { + $events = Get-WinEvent -FilterHashtable @{ + LogName = 'System' + Id = $relevantIds + } -MaxEvents 20 -ErrorAction Stop + + if ($events) { + $sorted = $events | Sort-Object TimeCreated -Descending + + foreach ($evt in ($sorted | Select-Object -First 10)) { + $msgShort = ($evt.Message -replace '\s+', ' ').TrimStart() + $msgShort = if ($msgShort.Length -gt 250) { $msgShort.Substring(0, 250) + '...' } else { $msgShort } + + $evtStatus.RelevantEvents += [ordered]@{ + EventId = $evt.Id + TimeCreated = $evt.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss') + Level = $evt.LevelDisplayName + Message = $msgShort + } + } + + $last = $sorted | Select-Object -First 1 + $evtStatus.LastEventId = $last.Id + $evtStatus.LastEventTime = $last.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss') + $lastMsg = ($last.Message -replace '\s+', ' ').TrimStart() + $evtStatus.LastEventMessage = if ($lastMsg.Length -gt 300) { + $lastMsg.Substring(0, 300) + '...' + } else { $lastMsg } + + $evtStatus.ConfidenceLevel = switch ($last.Id) { + 1808 { 'HighConfidence-Success' } + 1801 { 'HighConfidence-Failed' } + 1795 { 'Failed-HyperVKnownIssue' } + 1802 { 'Pending' } + 1803 { 'InProgress' } + default { 'Informational' } + } + } + } catch { + $msg = $_.Exception.Message + if ($msg -like '*No events*' -or $_.CategoryInfo.Reason -eq 'NoMatchingEventsException') { + $evtStatus.ConfidenceLevel = 'NoRelevantEvents' + } else { + $evtStatus.Error = $msg + $evtStatus.ConfidenceLevel = 'EventLogError' + } + } + + return $evtStatus +} + +function Get-RemediationCategory { + param($Result) + + $sb = $Result.SecureBoot + $cert = $Result.Certificates + $reg = $Result.Registry + $env = $Result.EnvironmentType + + # Bez UEFI / Secure Boot není podporováno + if (-not $sb.IsUEFI -or -not $sb.IsSupported) { + if ($env -like '*VM*') { + return @{ Code = 'NO_SECUREBOOT_VM'; Emoji = '❌'; Label = 'Secure Boot nepodporováno (VM bez vTPM/UEFI)' } + } + return @{ Code = 'NO_SECUREBOOT'; Emoji = '❌'; Label = 'Secure Boot nepodporováno (Legacy BIOS)' } + } + + if (-not $sb.IsEnabled) { + return @{ Code = 'SECUREBOOT_DISABLED'; Emoji = '⏸️'; Label = 'Secure Boot vypnuto' } + } + + # Secure Boot je zapnutý — zkontrolovat certifikáty + if ($cert.AllReplacements2023 -and -not $cert.AnyExpiring2011) { + return @{ Code = 'OK'; Emoji = '✅'; Label = 'OK — má nové 2023 certifikáty' } + } + if ($cert.AllReplacements2023 -and $cert.AnyExpiring2011) { + return @{ Code = 'OK_TRANSITION'; Emoji = '✅'; Label = 'OK — přechodný stav (2023 i 2011 certifikáty)' } + } + + # Selhání aktualizace + if ($reg.UEFICA2023Status -eq 3 -or + $Result.EventLog.LastEventId -eq 1795 -or + $Result.EventLog.LastEventId -eq 1801) { + return @{ Code = 'UPDATE_FAILED'; Emoji = '🔴'; Label = 'Selhání aktualizace certifikátů' } + } + + # Aktualizace právě probíhá / čeká na restart + if ($reg.UEFICA2023Status -eq 1 -or $reg.UEFICA2023Status -eq 2) { + return @{ Code = 'UPDATE_PENDING'; Emoji = '⏳'; Label = 'Aktualizace dokončena, čeká na restart' } + } + + # Firmware nepodporuje nové certifikáty + if ($null -ne $reg.WindowsUEFICA2023Capable -and $reg.WindowsUEFICA2023Capable -eq 0) { + return @{ Code = 'FIRMWARE_UPDATE_NEEDED'; Emoji = '🔧'; Label = 'Čeká na firmware update (OEM)' } + } + + # Nutná aktualizace certifikátů + return @{ Code = 'UPDATE_NEEDED'; Emoji = '⚠️'; Label = 'Nutná aktualizace certifikátů' } +} + +#endregion + +#region ── Main ────────────────────────────────────────────────────────────── + +$auditStart = Get-Date + +# Předpočítat hodnoty, které by způsobily parse error uvnitř hashtable (try/catch v PS 5.1) +$_fqdn = try { [Net.Dns]::GetHostEntry('').HostName } catch { $env:COMPUTERNAME } +$_osInfo = Get-WmiObject Win32_OperatingSystem -ErrorAction SilentlyContinue +$_osCaption = if ($_osInfo) { $_osInfo.Caption } else { $null } +$_osBuild = if ($_osInfo) { $_osInfo.BuildNumber } else { $null } + +$result = [ordered]@{ + AuditTimestamp = $auditStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") + Hostname = $env:COMPUTERNAME + FQDN = $_fqdn + OSCaption = $_osCaption + OSBuild = $_osBuild + Architecture = $env:PROCESSOR_ARCHITECTURE + EnvironmentType = Get-EnvironmentType + Hardware = Get-HardwareInfo + SecureBoot = Get-SecureBootState + Certificates = $null + Registry = Get-RegistryStatus + EventLog = Get-EventLogStatus + Category = $null + CategoryLabel = $null + RemediationAction = $null +} + +# Certifikáty parsovat pouze pokud je Secure Boot dostupný +if ($result.SecureBoot.IsUEFI -and $result.SecureBoot.IsSupported) { + $result.Certificates = Get-CertificateStatus +} else { + $result.Certificates = [ordered]@{ + KEK = [ordered]@{ + Has2011 = $false; Has2023 = $false + Certs2011 = @(); Certs2023 = @() + Error = 'Secure Boot not available — certificate check skipped' + } + DB = [ordered]@{ + Has2011UEFI = $false; Has2011WindowsPCA = $false + Has2023UEFI = $false; Has2023OptionROM = $false; Has2023WindowsUEFI = $false + Certs2011 = @(); Certs2023 = @() + Error = 'Secure Boot not available — certificate check skipped' + } + AnyExpiring2011 = $false + AllReplacements2023 = $false + } +} + +# Kategorie +$cat = Get-RemediationCategory -Result $result +$result.Category = $cat.Code +$result.CategoryLabel = "$($cat.Emoji) $($cat.Label)" + +$remediationMap = @{ + 'OK' = 'Žádná akce' + 'OK_TRANSITION' = 'Žádná akce (monitorovat dokud nezmizí 2011 certifikáty)' + 'UPDATE_NEEDED' = 'Naplánovat rollout nových certifikátů (KB5068202)' + 'UPDATE_FAILED' = 'Troubleshooting selhání — zkontrolovat Event 1795/1801 (KB5085046)' + 'UPDATE_PENDING' = 'Provést restart serveru pro dokončení aktualizace' + 'FIRMWARE_UPDATE_NEEDED'= 'Kontaktovat OEM / aktualizovat firmware serveru' + 'SECUREBOOT_DISABLED' = 'Rozhodnutí o zapnutí Secure Boot (mimo scope skriptu)' + 'NO_SECUREBOOT' = 'Dokumentovat jako výjimku — Legacy BIOS, Secure Boot nelze' + 'NO_SECUREBOOT_VM' = 'Dokumentovat jako výjimku — VM bez Secure Boot (Gen1 / bez vTPM)' +} +$result.RemediationAction = $remediationMap[$result.Category] + +$result.AuditDurationMs = [int](Get-Date).Subtract($auditStart).TotalMilliseconds + +#endregion + +#region ── Output ──────────────────────────────────────────────────────────── + +$jsonOutput = $result | ConvertTo-Json -Depth 10 + +if ($OutputPath) { + $jsonOutput | Out-File -FilePath $OutputPath -Encoding UTF8 -Force + Write-Host "JSON uložen: $OutputPath" -ForegroundColor Green +} + +if (-not $JsonOnly) { + $sb = $result.SecureBoot + $cert = $result.Certificates + $reg = $result.Registry + $evt = $result.EventLog + $hw = $result.Hardware + + $catColor = switch -Wildcard ($result.Category) { + 'OK*' { 'Green' } + 'UPDATE_NEEDED' { 'Yellow' } + 'UPDATE_PENDING' { 'Cyan' } + 'UPDATE_FAILED' { 'Red' } + 'FIRMWARE*' { 'Magenta' } + 'SECUREBOOT_DISABLED' { 'Yellow' } + default { 'Gray' } + } + + $line = '=' * 60 + Write-Host '' + Write-Host $line -ForegroundColor Cyan + Write-Host " SECURE BOOT AUDIT — $($result.Hostname)" -ForegroundColor Cyan + Write-Host " $($result.AuditTimestamp)" -ForegroundColor DarkGray + Write-Host $line -ForegroundColor Cyan + Write-Host '' + + Write-Host 'SERVER' -ForegroundColor Yellow + Write-Host " Hostname : $($result.Hostname)" + Write-Host " FQDN : $($result.FQDN)" + Write-Host " OS : $($result.OSCaption) (Build $($result.OSBuild))" + Write-Host " Prostředí : $($result.EnvironmentType)" + Write-Host " Hardware : $($hw.Manufacturer) $($hw.Model) [S/N: $($hw.SerialNumber)]" + Write-Host " BIOS/FW : $($hw.BiosVersion) ($($hw.BiosReleaseDate))" + Write-Host " Firmware typ: $($hw.FirmwareType)" + Write-Host '' + + Write-Host 'SECURE BOOT' -ForegroundColor Yellow + Write-Host " UEFI firmware : $($sb.IsUEFI)" + Write-Host " Podporováno : $($sb.IsSupported)" + Write-Host " Povoleno : $($sb.IsEnabled)" + if ($sb.Error) { Write-Host " ! Chyba : $($sb.Error)" -ForegroundColor Red } + Write-Host '' + + Write-Host 'CERTIFIKÁTY' -ForegroundColor Yellow + $c = $cert + Write-Host " ── Expirující 2011 ──────────────────────────────────" + Write-Host " KEK CA 2011 (exp. 24.6.2026) : $(if ($c.KEK.Has2011) {'PŘÍTOMEN ⚠️'} else {'chybí'})" + Write-Host " DB UEFI CA 2011 (exp. 27.6.2026): $(if ($c.DB.Has2011UEFI) {'PŘÍTOMEN ⚠️'} else {'chybí'})" + Write-Host " DB Windows PCA 2011 (19.10.2026) : $(if ($c.DB.Has2011WindowsPCA) {'PŘÍTOMEN ⚠️'} else {'chybí'})" + Write-Host " ── Nové náhrady 2023 ────────────────────────────────" + Write-Host " KEK 2K CA 2023 : $(if ($c.KEK.Has2023) {'přítomen ✓'} else {'CHYBÍ'})" + Write-Host " DB UEFI CA 2023 : $(if ($c.DB.Has2023UEFI) {'přítomen ✓'} else {'CHYBÍ'})" + Write-Host " DB Option ROM UEFI CA 2023 : $(if ($c.DB.Has2023OptionROM) {'přítomen ✓'} else {'CHYBÍ'})" + Write-Host " DB Windows UEFI CA 2023 : $(if ($c.DB.Has2023WindowsUEFI) {'přítomen ✓'} else {'CHYBÍ'})" + if ($c.KEK.Error) { Write-Host " ! KEK chyba : $($c.KEK.Error)" -ForegroundColor Red } + if ($c.DB.Error) { Write-Host " ! DB chyba : $($c.DB.Error)" -ForegroundColor Red } + Write-Host '' + + Write-Host 'REGISTRY STAV' -ForegroundColor Yellow + Write-Host " UEFICA2023Status : $($reg.UEFICA2023Status) ($($reg.UEFICA2023StatusText))" + Write-Host " AvailableUpdates : $($reg.AvailableUpdates)" + Write-Host " WindowsUEFICA2023Capable: $($reg.WindowsUEFICA2023Capable)" + Write-Host " HighConfidenceOptOut : $($reg.HighConfidenceOptOut)" + if ($reg.UEFICA2023Error) { + Write-Host " ! UEFICA2023Error : $($reg.UEFICA2023Error)" -ForegroundColor Red + } + Write-Host '' + + Write-Host 'EVENT LOG (relevantní EventID: 1795/1796/1800-1803/1808)' -ForegroundColor Yellow + Write-Host " Poslední event : EventID $($evt.LastEventId) ($($evt.LastEventTime))" + Write-Host " Confidence level : $($evt.ConfidenceLevel)" + if ($evt.RelevantEvents.Count -gt 0) { + Write-Host " Posledních $([Math]::Min($evt.RelevantEvents.Count,5)) záznamů:" + foreach ($e in ($evt.RelevantEvents | Select-Object -First 5)) { + $ec = if ($e.EventId -eq 1808) { 'Green' } + elseif ($e.EventId -in @(1795,1801)) { 'Red' } + else { 'DarkGray' } + Write-Host " [$($e.TimeCreated)] EventID $($e.EventId) $($e.Level)" -ForegroundColor $ec + } + } else { + Write-Host ' Žádné relevantní záznamy nenalezeny.' -ForegroundColor DarkGray + } + Write-Host '' + + Write-Host 'VÝSLEDEK' -ForegroundColor Yellow + Write-Host " $($result.CategoryLabel)" -ForegroundColor $catColor + Write-Host " Doporučená akce: $($result.RemediationAction)" -ForegroundColor White + Write-Host '' + Write-Host $line -ForegroundColor Cyan + Write-Host '' +} + +if ($JsonOnly) { + Write-Output $jsonOutput +} + +if ($PassThru) { + return $result +} + +#endregion \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c5f8cfc --- /dev/null +++ b/README.md @@ -0,0 +1,310 @@ +# Secure Boot Certificate Remediation + +Sada PowerShell skriptů pro audit a remediari expirujících Secure Boot certifikátů na Windows Serverech (fyzické servery, Hyper-V VM, VMware VM). + +--- + +## 1. Co řešíme + +### Problém + +Microsoft oznámil prostřednictvím [KB5062710](https://support.microsoft.com/en-us/topic/windows-secure-boot-certificate-expiration-and-ca-updates-7ff40d33-95dc-4c3c-8725-a9b95457578e), že původní Secure Boot certifikáty z roku 2011 expirují v průběhu roku 2026. Tyto certifikáty jsou uloženy přímo ve firmware serveru (UEFI KEK a DB databázích) a zajišťují důvěryhodnost celého boot procesu. + +### Expirující certifikáty a termíny + +| Certifikát | Umístění | Expirace | Náhrada | +|---|---|---|---| +| Microsoft Corporation KEK CA 2011 | KEK | **24. června 2026** | Microsoft Corporation KEK 2K CA 2023 | +| Microsoft UEFI CA 2011 | DB | **27. června 2026** | Microsoft UEFI CA 2023 + Microsoft Option ROM UEFI CA 2023 | +| Microsoft Windows Production PCA 2011 | DB | 19. října 2026 | Windows UEFI CA 2023 | + +> **Urgentní:** První dvě expirace jsou 24. a 27. června 2026 — audit je nutné provést okamžitě. + +### Dopad pokud se nic neudělá + +Servery bez nových certifikátů budou **nadále normálně bootovat** — certifikáty sice expirují, ale UEFI firmware je při bootu nevyhodnocuje jako neplatné. Problém nastane postupně: + +- Server přestane být schopen přijímat nové aktualizace Secure Boot databází a revokačních seznamů (DBX) +- Nelze aplikovat mitigace nově objevených boot-level zranitelností +- Mohou být ovlivněny scénáře závislé na Secure Boot důvěře: BitLocker hardening, third-party bootloadery, attestation +- Při případném resetu UEFI na factory defaults nebo reinstalaci firmware může boot selhat + +### Které servery jsou ohroženy + +Ohroženy jsou servery, které splňují **všechny** následující podmínky: + +- Mají UEFI firmware (ne Legacy BIOS) +- Mají zapnutý Secure Boot +- Ještě neobdržely nové 2023 certifikáty (typicky přes Windows Update nebo manuální rollout) + +Servery s Legacy BIOS nebo vypnutým Secure Boot nejsou přímo ohroženy, ale je vhodné je zdokumentovat. + +--- + +## 2. Detekce — jak zjistit aktuální stav + +### Skripty + +| Skript | Účel | +|---|---| +| `Invoke-SecureBootAudit.ps1` | Audit jednoho serveru — vrací JSON + human-readable souhrn | +| `Start-SecureBootFleetAudit.ps1` | Hromadný audit celé sítě — vstup CSV, výstup agregovaný CSV/JSON | + +### Spuštění auditu + +**Lokálně na serveru** (spustit jako Administrator): + +```powershell +.\Invoke-SecureBootAudit.ps1 +``` + +**Vzdáleně z workstation:** + +```powershell +Invoke-Command -ComputerName SERVER01 -FilePath .\Invoke-SecureBootAudit.ps1 -ArgumentList $null, $false, $true +``` + +**Hromadně ze seznamu serverů (CSV soubor se sloupcem `ServerName`):** + +```powershell +.\Start-SecureBootFleetAudit.ps1 -ServerListPath .\servers.csv -OutputPath .\audit_results\ +``` + +**Hromadně přímo ze seznamu:** + +```powershell +.\Start-SecureBootFleetAudit.ps1 -ServerName SERVER01,SERVER02,SERVER03 +``` + +### Výsledné kategorie + +Každý server je zařazen do jedné z těchto kategorií: + +| Kategorie | Popis | Doporučená akce | +|---|---|---| +| ✅ **OK** | Má nové 2023 certifikáty, Secure Boot aktivní | Žádná akce | +| ✅ **OK_TRANSITION** | Má 2023 i stará 2011 certifikáty (přechodný stav) | Žádná akce, monitorovat | +| ⚠️ **UPDATE_NEEDED** | Má pouze 2011 certifikáty, Secure Boot aktivní | Naplánovat rollout | +| ⏳ **UPDATE_PENDING** | Registry nastaveny, čeká na restart | Restartovat server | +| 🔧 **FIRMWARE_UPDATE_NEEDED** | `WindowsUEFICA2023Capable=0` — firmware nepodporuje nové certifikáty | Update firmware u OEM | +| ⏸️ **SECUREBOOT_DISABLED** | Secure Boot existuje v UEFI, ale není zapnuté | Rozhodnutí o enablementu | +| ❌ **NO_SECUREBOOT** | Legacy BIOS — Secure Boot vůbec neexistuje | Dokumentovat jako výjimku | +| ❌ **NO_SECUREBOOT_VM** | VM bez Secure Boot (Gen1 / bez vTPM / BIOS mode) | Dokumentovat jako výjimku | +| 🔴 **UPDATE_FAILED** | Selhání aktualizace (viz EventID níže) | Troubleshooting | + +### Registry hodnoty a jejich výklad + +Klíč `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing`: + +| Hodnota | Typ | Výklad | +|---|---|---| +| `UEFICA2023Status = 0` | NotStarted | Aktualizace ještě nebyla spuštěna | +| `UEFICA2023Status = 1` | InProgress | Aktualizace probíhá | +| `UEFICA2023Status = 2` | Success | Aktualizace proběhla, čeká se na restart | +| `UEFICA2023Status = 3` | Failed | Aktualizace selhala — viz `UEFICA2023Error` | +| `WindowsUEFICA2023Capable = 0` | — | Firmware nepodporuje nové certifikáty (potřeba update OEM firmware) | +| `UEFICA2023Error` | HRESULT kód | Chybový kód při selhání | + +Klíč `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot`: + +| Hodnota | Výklad | +|---|---| +| `AvailableUpdates` | Bitmaska dostupných aktualizací; 0x5944 = plná sada (nastavíme při remediaci) | +| `HighConfidenceOptOut = 1` | Server se odhlásil z high-confidence update path — **zablokuje aktualizaci** | + +### EventID v System logu + +| EventID | Zdroj | Typ | Výklad | +|---|---|---|---| +| **1808** | Microsoft-Windows-Eventlog | Information | ✅ Certifikáty úspěšně aplikovány — aktualizace proběhla v pořádku | +| **1801** | Microsoft-Windows-Eventlog | Error | ❌ Certifikáty NEBYLY aplikovány — selhání high-confidence update | +| **1795** | Microsoft-Windows-Eventlog | Error | ❌ Selhání aktualizace na Hyper-V VM (viz níže) | +| **1796** | Microsoft-Windows-Eventlog | Information | Průběhová informace | +| **1800** | Microsoft-Windows-Eventlog | Information | Průběhová informace | +| **1802** | Microsoft-Windows-Eventlog | Information | Aktualizace čeká na restart | +| **1803** | Microsoft-Windows-Eventlog | Information | Aktualizace probíhá | + +Rychlé ověření z PowerShell: + +```powershell +Get-WinEvent -FilterHashtable @{ LogName = 'System'; Id = @(1795,1801,1808) } -MaxEvents 10 | + Select-Object TimeCreated, Id, Message | Format-List +``` + +### Specifika prostředí + +#### Hyper-V VM + +- Virtuální stroje **Generation 1** (BIOS mode) nemají Secure Boot — kategorie `NO_SECUREBOOT_VM`, není co řešit. +- Virtuální stroje **Generation 2** mají virtualizovaný UEFI s Secure Boot, ale aktualizace certifikátů závisí na verzi hypervizoru. +- **Známý problém (Event 1795):** Na starších hostitelích selhávala aktualizace certifikátů ve VM s EventID 1795. Microsoft vydal opravu v březnu 2026 (KB5085790). Postup: + 1. Ověřit verzi Windows Server na Hyper-V hostiteli + 2. Aplikovat příslušné kumulativní aktualizace na hostitele + 3. Spustit audit znovu na VM + +#### VMware ESXi + +- Secure Boot ve VMware VM závisí na konfiguraci VM hardware (EFI firmware + Secure Boot zaškrtnuto v nastavení VM). +- VMware **nepředává** nové certifikáty automaticky — aktualizace musí proběhnout přes Windows stejně jako na fyzickém stroji. +- Kategorie `NO_SECUREBOOT_VM` u VMware VM = VM nemá Secure Boot vůbec povoleno. + +#### Fyzické servery s Legacy BIOS + +- Kategorie `NO_SECUREBOOT` — Secure Boot není podporováno. Firmware je třeba překonfigurovat (boot mode UEFI) nebo server dokumentovat jako výjimku. + +#### Starší firmware + +- Servery s firmwarem z doby před cca 2018 mohou vyžadovat update firmware od výrobce (Dell, HP, Lenovo, Supermicro) před tím, než lze nové certifikáty aplikovat. +- Poznávacím znamením je `WindowsUEFICA2023Capable = 0` nebo hodnota `UEFICA2023Error`. +- Servery end-of-life bez dostupného firmware update je nutné dokumentovat jako trvalou výjimku. + +--- + +## 3. Remediace — odstranění problému + +### Skript + +``` +Set-SecureBootCertificateUpdate.ps1 +``` + +Metoda: Registry key dle **KB5068202** — nastaví `AvailableUpdates = 0x5944`, čímž Windows signalizuje, že má aplikovat kompletní sadu nových certifikátů (KEK + UEFI CA + Windows UEFI CA + Boot Manager). + +### Doporučený postup rollout (staging) + +**Fáze 1 — Pilotní test (1–2 servery každého typu)** + +```powershell +# Nejdřív WhatIf — ověřit co se stane bez provedení změn +.\Set-SecureBootCertificateUpdate.ps1 -ServerName PILOT-SERVER01 -WhatIf + +# Aplikovat na pilotní server +.\Set-SecureBootCertificateUpdate.ps1 -ServerName PILOT-SERVER01 + +# Restartovat pilotní server +Restart-Computer -ComputerName PILOT-SERVER01 -Force +``` + +**Fáze 2 — Ověření pilotu (po restartu)** + +```powershell +# Zkontrolovat EventID 1808 (úspěch) nebo 1801 (chyba) +Invoke-Command -ComputerName PILOT-SERVER01 -ScriptBlock { + Get-WinEvent -FilterHashtable @{ LogName='System'; Id=@(1801,1808) } -MaxEvents 5 | + Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-List +} + +# Spustit plný audit pro ověření kategorie OK +Invoke-Command -ComputerName PILOT-SERVER01 -FilePath .\Invoke-SecureBootAudit.ps1 -ArgumentList $null, $false, $true +``` + +**Fáze 3 — Rozšíření na další servery** + +```powershell +# Hromadně ze CSV (sloupec ServerName) +.\Set-SecureBootCertificateUpdate.ps1 -ServerName (Import-Csv .\servery-wave1.csv).ServerName + +# Po restartech ověřit hromadně +.\Start-SecureBootFleetAudit.ps1 -ServerListPath .\servery-wave1.csv -OutputPath .\audit_post\ +``` + +### Co se děje po spuštění skriptu + +1. Skript nastaví `AvailableUpdates = 0x5944` v registry a resetuje `HighConfidenceOptOut = 0` +2. Spustí scheduled task `\Microsoft\Windows\PI\Secure-Boot-Update` (pokud existuje; jinak se task spustí sám do 12 hodin) +3. Task zpracuje registry a připraví certifikáty — status přejde z `NotStarted` → `InProgress` → `Success` +4. **Certifikáty se aplikují až při příštím restartu** — Boot Manager zapíše nové certifikáty do UEFI firmware +5. Po restartu se v System logu objeví EventID **1808** (úspěch) nebo **1801** (chyba) + +### Dopad na server + +| Aspekt | Detail | +|---|---| +| **Dostupnost** | Žádný výpadek při nastavení registry. Restart je standardní plánovaný restart. | +| **Riziko selhání bootu** | **Minimální** — neúspěšná aktualizace certifikátů neohrozí boot. Server nastartuje i se starými certifikáty. | +| **Počet restartů** | Obvykle 1 restart. Ve výjimečných případech může být vyžadován druhý. | +| **Čas po restartu** | Certifikáty jsou aplikovány v rané fázi bootu — uživatelé to nepocítí. | +| **BitLocker** | Pokud je BitLocker aktivní s PCR7 (Secure Boot measurement), ověřit recovery key před restartem. | +| **Monitoring** | Po restartu čekat min. 48 hodin než prohlásíme server za stabilní. | + +> **Doporučení pro BitLocker:** Před restartem na serverech s BitLockerem ověřit dostupnost recovery key: `manage-bde -protectors -get C:` + +### Ověření úspěchu + +**1. Event log — primární ověření:** + +```powershell +Get-WinEvent -FilterHashtable @{ LogName='System'; Id=1808 } -MaxEvents 3 | + Select-Object TimeCreated, Message +``` + +EventID **1808** potvrzuje úspěšnou aplikaci certifikátů. + +**2. Audit skript — kompletní ověření:** + +```powershell +.\Invoke-SecureBootAudit.ps1 +# Očekávaný výstup: kategorie "✅ OK" nebo "✅ OK_TRANSITION" +``` + +**3. Ruční kontrola přítomnosti certifikátů:** + +```powershell +# KEK databáze — hledat 2023 certifikáty +$kek = Get-SecureBootUEFI KEK +# DB databáze +$db = Get-SecureBootUEFI db +``` + +**4. Registry stav:** + +```powershell +Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing' | + Select-Object UEFICA2023Status, UEFICA2023Error, WindowsUEFICA2023Capable +# UEFICA2023Status = 2 znamená Success +``` + +### Troubleshooting časté chyby + +**Event 1801 — high-confidence update selhal:** +```powershell +# Zkontrolovat UEFICA2023Error +(Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing').UEFICA2023Error + +# Zkusit znovu s -Force +.\Set-SecureBootCertificateUpdate.ps1 -ServerName -Force +``` + +**Event 1795 — Hyper-V VM selhání:** +- Zkontrolovat verzi Windows Server hostitele a aplikovat kumulativní update (KB5085790) +- Po aktualizaci hostitele spustit remediaci na VM znovu + +**WindowsUEFICA2023Capable = 0 — firmware nepodporuje:** +- Zkontrolovat dostupnost firmware update u výrobce serveru +- Dell: Dell Update Package / iDRAC +- HP: HP Service Pack for ProLiant (SPP) +- Lenovo: Lenovo XClarity +- Supermicro: BIOS update přes IPMI +- Pokud firmware update není dostupný → dokumentovat jako trvalou výjimku + +**HighConfidenceOptOut = 1 — server se odhlásil:** +```powershell +# Resetovat OptOut +Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot' ` + -Name HighConfidenceOptOut -Value 0 -Type DWord +# Pak spustit remediaci znovu +``` + +--- + +## Reference + +| KB | Popis | +|---|---| +| [KB5062710](https://support.microsoft.com/en-us/topic/windows-secure-boot-certificate-expiration-and-ca-updates-7ff40d33-95dc-4c3c-8725-a9b95457578e) | Přehled: expirace certifikátů a CA aktualizace | +| [KB5062713](https://support.microsoft.com/en-us/help/5062713) | IT Pro guidance | +| [KB5068202](https://support.microsoft.com/en-us/help/5068202) | Metoda registry klíčů (použita v tomto projektu) | +| [KB5068198](https://support.microsoft.com/en-us/help/5068198) | Metoda Group Policy | +| [KB5068197](https://support.microsoft.com/en-us/help/5068197) | Metoda WinCS CLI | +| [KB5085046](https://support.microsoft.com/en-us/help/5085046) | Troubleshooting guide | +| [KB5085790](https://support.microsoft.com/en-us/help/5085790) | Known issues a resolutions (vč. Hyper-V fix) | diff --git a/Set-SecureBootCertificateUpdate.ps1 b/Set-SecureBootCertificateUpdate.ps1 new file mode 100644 index 0000000..44cbbe2 --- /dev/null +++ b/Set-SecureBootCertificateUpdate.ps1 @@ -0,0 +1,519 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Remediační skript pro aktualizaci Secure Boot certifikátů (KB5068202). + +.DESCRIPTION + Nastaví registry klíče pro zahájení aktualizace Secure Boot certifikátů + (přechod z 2011 na 2023 sadu) a spustí scheduled task. + + Metoda: Registry key (KB5068202) + Alternativy: GPO (KB5068198), WinCS CLI (KB5068197) + + Postup remediace: + 1. Skript nastaví AvailableUpdates = 0x5944 v registry + 2. Scheduled task \Microsoft\Windows\PI\Secure-Boot-Update se spustí + (nebo čeká na příští plánovaný běh každých 12 hodin) + 3. Certifikáty se aplikují při příštím restartu + 4. Výsledek ověřit přes EventID 1808 (úspěch) nebo 1801/1795 (chyba) + + DŮLEŽITÉ: + - Aktualizace vyžaduje RESTART pro aplikaci certifikátů v Boot Manageru + - Neúspěšná aktualizace NEOHROZÍ boot serveru — server běží dál + - Po aplikaci čekat min. 48 hodin a jeden nebo více restartů + - Na Hyper-V VM s Event 1795: ověřit verzi hostitele (fix dostupný od 3/2026) + +.PARAMETER ServerName + Název nebo pole názvů serverů pro vzdálené spuštění přes WinRM. + Pokud není zadán, skript se spustí lokálně. + +.PARAMETER Credential + Přihlašovací údaje pro vzdálené připojení. + +.PARAMETER Force + Aplikuje registry klíče i na serverech, které již mají 2023 certifikáty + nebo kde již aktualizace proběhla (UEFICA2023Status = 2). + +.PARAMETER SkipScheduledTask + Nespustí scheduled task po nastavení registry. Task se spustí sám + při příštím plánovaném běhu (každých 12 hodin). + +.PARAMETER VerifyOnly + Pouze zobrazí aktuální stav bez provedení změn (read-only, ekvivalent -WhatIf). + +.PARAMETER LogPath + Cesta k logovacímu souboru. Default: .\SecureBootRemediation-.log + +.EXAMPLE + # WhatIf — zobrazí co by se stalo, bez změn + .\Set-SecureBootCertificateUpdate.ps1 -WhatIf + +.EXAMPLE + # Lokální spuštění + .\Set-SecureBootCertificateUpdate.ps1 + +.EXAMPLE + # Vzdálené spuštění na jednom serveru + .\Set-SecureBootCertificateUpdate.ps1 -ServerName SERVER01 + +.EXAMPLE + # Vzdálené spuštění na více serverech + .\Set-SecureBootCertificateUpdate.ps1 -ServerName SERVER01,SERVER02,SERVER03 + +.EXAMPLE + # Pouze ověření bez změn + .\Set-SecureBootCertificateUpdate.ps1 -ServerName SERVER01 -VerifyOnly + +.NOTES + Reference: KB5062710, KB5068202, KB5085046, KB5085790 + Vyžaduje spuštění jako Administrator (lokálně i vzdáleně). + Vzdálené spuštění vyžaduje WinRM (standardně aktivní na Windows Server). + AvailableUpdates = 0x5944 dle KB5068202 (KEK + UEFI CA + Windows UEFI CA + Boot Manager). +#> + +[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] +param( + [Parameter(Position = 0)] + [string[]]$ServerName, + + [System.Management.Automation.PSCredential]$Credential, + + [switch]$Force, + [switch]$SkipScheduledTask, + [switch]$VerifyOnly, + + [string]$LogPath = ".\SecureBootRemediation-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" +) + +$ErrorActionPreference = 'SilentlyContinue' +Set-StrictMode -Off + +#region ── Logging ──────────────────────────────────────────────────────────── + +function Write-Log { + param( + [string]$Message, + [ValidateSet('INFO','WARN','ERROR','SUCCESS','ACTION')] + [string]$Level = 'INFO' + ) + $ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + $line = "[$ts] [$Level] $Message" + + $color = switch ($Level) { + 'SUCCESS' { 'Green' } + 'WARN' { 'Yellow' } + 'ERROR' { 'Red' } + 'ACTION' { 'Cyan' } + default { 'Gray' } + } + Write-Host $line -ForegroundColor $color + + try { + $line | Out-File -FilePath $LogPath -Append -Encoding UTF8 -Force + } catch { } +} + +#endregion + +#region ── Core remediation logic (spouští se lokálně nebo přes Invoke-Command) ── + +$RemediationScriptBlock = { + param( + [bool]$WhatIfMode, + [bool]$ForceMode, + [bool]$VerifyOnlyMode, + [bool]$SkipTask + ) + + $result = [ordered]@{ + Hostname = $env:COMPUTERNAME + Timestamp = (Get-Date).ToString('yyyy-MM-ddTHH:mm:ssZ') + PreState = $null + ActionsApplied = @() + PostState = $null + Status = 'Unknown' + Message = '' + RequiresRestart = $false + } + + # Registry konstanty (KB5068202) + $REG_SECUREBOOT = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot' + $REG_SERVICING = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing' + $AVAILABLE_UPDATES_VALUE = 0x5944 # KEK + UEFI CA + Windows UEFI CA + Boot Manager (KB5068202) + $TASK_PATH = '\Microsoft\Windows\PI\Secure-Boot-Update' + + #-- Funkce: zjistit aktuální stav ----------------------------------------- + function Get-State { + $s = [ordered]@{ + FirmwareType = 'Unknown' + SecureBootEnabled = $false + SecureBootSupported = $false + AvailableUpdates = $null + HighConfidenceOptOut = $null + UEFICA2023Status = $null + UEFICA2023StatusText = 'Unknown' + UEFICA2023Error = $null + WindowsUEFICA2023Capable = $null + LastRelevantEvent = $null + LastRelevantEventTime = $null + } + + # Firmware type + $fw = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control' -Name PEFirmwareType -ErrorAction SilentlyContinue + if ($fw) { + $s.FirmwareType = if ($fw.PEFirmwareType -eq 2) { 'UEFI' } else { 'Legacy BIOS' } + } elseif (Test-Path $REG_SECUREBOOT) { + $s.FirmwareType = 'UEFI' + } else { + $s.FirmwareType = 'Legacy BIOS' + } + + # Secure Boot stav + try { + $r = Confirm-SecureBootUEFI -ErrorAction Stop + $s.SecureBootSupported = $true + $s.SecureBootEnabled = [bool]$r + } catch { } + + # Registry hodnoty + $mainProps = Get-ItemProperty $REG_SECUREBOOT -ErrorAction SilentlyContinue + if ($mainProps) { + $s.AvailableUpdates = $mainProps.AvailableUpdates + $s.HighConfidenceOptOut = $mainProps.HighConfidenceOptOut + } + + $svcProps = Get-ItemProperty $REG_SERVICING -ErrorAction SilentlyContinue + if ($svcProps) { + $s.UEFICA2023Status = $svcProps.UEFICA2023Status + $s.UEFICA2023Error = $svcProps.UEFICA2023Error + $s.WindowsUEFICA2023Capable = $svcProps.WindowsUEFICA2023Capable + + $s.UEFICA2023StatusText = switch ($s.UEFICA2023Status) { + 0 { 'NotStarted' } + 1 { 'InProgress' } + 2 { 'Success' } + 3 { 'Failed' } + $null { 'KeyNotPresent' } + default { "Unknown ($($s.UEFICA2023Status))" } + } + } + + # Poslední relevantní event + try { + $evt = Get-WinEvent -FilterHashtable @{ + LogName = 'System' + Id = @(1795,1801,1808) + } -MaxEvents 1 -ErrorAction Stop | Select-Object -First 1 + + if ($evt) { + $s.LastRelevantEvent = $evt.Id + $s.LastRelevantEventTime = $evt.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss') + } + } catch { } + + return $s + } + + #-- Představ aktuální stav ------------------------------------------------ + $result.PreState = Get-State + + $pre = $result.PreState + + # Abort podmínky (bez -Force) + if (-not $VerifyOnlyMode -and -not $WhatIfMode) { + if ($pre.FirmwareType -ne 'UEFI') { + $result.Status = 'Skipped' + $result.Message = 'Legacy BIOS — Secure Boot není podporováno, remediace není možná.' + return $result + } + if (-not $pre.SecureBootSupported) { + $result.Status = 'Skipped' + $result.Message = 'Secure Boot není podporováno nebo povoleno — remediace přeskočena.' + return $result + } + if ($pre.UEFICA2023Status -eq 2 -and -not $ForceMode) { + $result.Status = 'Skipped' + $result.Message = "Aktualizace již byla úspěšně dokončena (UEFICA2023Status=2). Použijte -Force pro opakované spuštění." + return $result + } + if ($pre.WindowsUEFICA2023Capable -eq 0 -and -not $ForceMode) { + $result.Status = 'Warning' + $result.Message = "WindowsUEFICA2023Capable=0 — firmware nemusí podporovat nové certifikáty. Ověřte firmware u výrobce. Použijte -Force pro vynucení." + return $result + } + if ($pre.LastRelevantEvent -eq 1795) { + $result.Status = 'Warning' + $result.Message = "Detekován Event 1795 (Hyper-V known issue). Ověřte verzi hostitele — fix je dostupný od 3/2026 (KB5085790). Použijte -Force pro pokračování." + if (-not $ForceMode) { return $result } + } + } + + if ($VerifyOnlyMode) { + $result.Status = 'VerifyOnly' + $result.Message = 'VerifyOnly mode — žádné změny neprovedeny.' + return $result + } + + if ($WhatIfMode) { + $result.ActionsApplied += "WhatIf: Nastavil by HKLM:\...\SecureBoot\AvailableUpdates = 0x$($AVAILABLE_UPDATES_VALUE.ToString('X4'))" + $result.ActionsApplied += "WhatIf: Zajistil by HighConfidenceOptOut = 0" + if (-not $SkipTask) { + $result.ActionsApplied += "WhatIf: Spustil by scheduled task '$TASK_PATH'" + } + $result.Status = 'WhatIf' + $result.Message = 'WhatIf mode — žádné změny neprovedeny.' + return $result + } + + #-- Aplikovat registry klíče (KB5068202) ---------------------------------- + + # 1) Zajistit existenci SecureBoot klíče (obvykle existuje) + if (-not (Test-Path $REG_SECUREBOOT)) { + try { + New-Item -Path $REG_SECUREBOOT -Force -ErrorAction Stop | Out-Null + $result.ActionsApplied += "Vytvořen registry klíč: $REG_SECUREBOOT" + } catch { + $result.Status = 'Error' + $result.Message = "Nelze vytvořit registry klíč $REG_SECUREBOOT : $($_.Exception.Message)" + return $result + } + } + + # 2) Nastavit AvailableUpdates = 0x5944 + try { + Set-ItemProperty -Path $REG_SECUREBOOT -Name 'AvailableUpdates' ` + -Value $AVAILABLE_UPDATES_VALUE -Type DWord -Force -ErrorAction Stop + $result.ActionsApplied += "Nastaveno AvailableUpdates = 0x$($AVAILABLE_UPDATES_VALUE.ToString('X4')) (KB5068202)" + } catch { + $result.Status = 'Error' + $result.Message = "Chyba při nastavení AvailableUpdates: $($_.Exception.Message)" + return $result + } + + # 3) HighConfidenceOptOut musí být 0 (nebo neexistovat) — jinak se update neprovede + $optOut = (Get-ItemProperty $REG_SECUREBOOT -Name 'HighConfidenceOptOut' -ErrorAction SilentlyContinue) + if ($optOut -and $optOut.HighConfidenceOptOut -ne 0) { + try { + Set-ItemProperty -Path $REG_SECUREBOOT -Name 'HighConfidenceOptOut' ` + -Value 0 -Type DWord -Force -ErrorAction Stop + $result.ActionsApplied += "Resetován HighConfidenceOptOut = 0 (byl $($optOut.HighConfidenceOptOut))" + } catch { + $result.ActionsApplied += "WARN: Nepodařilo se resetovat HighConfidenceOptOut: $($_.Exception.Message)" + } + } + + # 4) Zajistit existenci Servicing podklíče + if (-not (Test-Path $REG_SERVICING)) { + try { + New-Item -Path $REG_SERVICING -Force -ErrorAction Stop | Out-Null + $result.ActionsApplied += "Vytvořen podklíč: $REG_SERVICING" + } catch { } + } + + #-- Spustit scheduled task ------------------------------------------------ + if (-not $SkipTask) { + try { + $task = Get-ScheduledTask -TaskPath '\Microsoft\Windows\PI\' ` + -TaskName 'Secure-Boot-Update' -ErrorAction Stop + + if ($task) { + Start-ScheduledTask -TaskPath '\Microsoft\Windows\PI\' ` + -TaskName 'Secure-Boot-Update' -ErrorAction Stop + $result.ActionsApplied += "Spuštěn scheduled task: $TASK_PATH" + + # Čekat na dokončení tasku (timeout 120 sekund) + $timeoutSec = 120 + $intervalSec = 3 + $elapsed = 0 + $finalState = 'Unknown' + + do { + Start-Sleep -Seconds $intervalSec + $elapsed += $intervalSec + $finalState = (Get-ScheduledTask -TaskPath '\Microsoft\Windows\PI\' ` + -TaskName 'Secure-Boot-Update' ` + -ErrorAction SilentlyContinue).State + } while ($finalState -eq 'Running' -and $elapsed -lt $timeoutSec) + + if ($elapsed -ge $timeoutSec -and $finalState -eq 'Running') { + $result.ActionsApplied += "WARN: Task stále běží po $timeoutSec s — pokračuji bez čekání. Ověřit stav ručně." + } else { + $result.ActionsApplied += "Task dokončen za ${elapsed}s — stav: $finalState" + } + } + } catch { + $result.ActionsApplied += "INFO: Scheduled task '$TASK_PATH' nebyl nalezen nebo se nepodařilo spustit: $($_.Exception.Message)" + $result.ActionsApplied += "INFO: Task se spustí automaticky při příštím plánovaném běhu (každých 12 hodin)." + } + } else { + $result.ActionsApplied += "INFO: Spuštění scheduled task přeskočeno (-SkipScheduledTask). Task se spustí sám (každých 12 hodin)." + } + + #-- Post-stav (okamžitě po aplikaci, před restartem) --------------------- + Start-Sleep -Seconds 2 + $result.PostState = Get-State + + $result.RequiresRestart = $true + $result.Status = 'Applied' + $result.Message = "Registry klíče nastaveny. Server vyžaduje RESTART pro aplikaci certifikátů. Po restartu ověřit EventID 1808 v System logu." + + return $result +} + +#endregion + +#region ── Výstup výsledku ──────────────────────────────────────────────────── + +function Write-ResultSummary { + param($res) + + $line = '-' * 60 + Write-Log $line + Write-Log "SERVER: $($res.Hostname) | $($res.Timestamp)" + $_statusLevel = switch ($res.Status) { + 'Applied' { 'SUCCESS' } + 'Error' { 'ERROR' } + 'Warning' { 'WARN' } + 'Skipped' { 'WARN' } + default { 'INFO' } + } + Write-Log "STATUS: $($res.Status) — $($res.Message)" -Level $_statusLevel + + $pre = $res.PreState + if ($pre) { + Write-Log " Pre-state:" + Write-Log " Firmware : $($pre.FirmwareType)" + Write-Log " Secure Boot : podporováno=$($pre.SecureBootSupported), povoleno=$($pre.SecureBootEnabled)" + Write-Log " AvailableUpdates : $($pre.AvailableUpdates)" + Write-Log " UEFICA2023Status : $($pre.UEFICA2023Status) ($($pre.UEFICA2023StatusText))" + Write-Log " WindowsCapable : $($pre.WindowsUEFICA2023Capable)" + if ($pre.UEFICA2023Error) { + Write-Log " ! UEFICA2023Error : $($pre.UEFICA2023Error)" -Level 'WARN' + } + if ($pre.LastRelevantEvent) { + Write-Log " Poslední event : EventID $($pre.LastRelevantEvent) ($($pre.LastRelevantEventTime))" + } + } + + if ($res.ActionsApplied -and $res.ActionsApplied.Count -gt 0) { + Write-Log " Provedené akce:" + foreach ($action in $res.ActionsApplied) { + $lvl = if ($action -like 'WhatIf:*' -or $action -like 'INFO:*') { 'INFO' } + elseif ($action -like 'WARN:*') { 'WARN' } + else { 'ACTION' } + Write-Log " $action" -Level $lvl + } + } + + $post = $res.PostState + if ($post -and $res.Status -eq 'Applied') { + Write-Log " Post-state (před restartem):" + Write-Log " AvailableUpdates : $($post.AvailableUpdates)" + Write-Log " UEFICA2023Status : $($post.UEFICA2023Status) ($($post.UEFICA2023StatusText))" + } + + if ($res.RequiresRestart) { + Write-Log " *** VYŽADOVÁN RESTART pro aplikaci certifikátů ***" -Level 'WARN' + Write-Log " Po restartu ověřit: Get-WinEvent -FilterHashtable @{LogName='System';Id=1808} -MaxEvents 5" + } +} + +#endregion + +#region ── Main ─────────────────────────────────────────────────────────────── + +$isWhatIf = $WhatIfPreference -eq [Management.Automation.ActionPreference]::Continue +$isVerify = $VerifyOnly.IsPresent +$isForce = $Force.IsPresent +$isSkipTask = $SkipScheduledTask.IsPresent + +Write-Log ('=' * 60) +Write-Log "Set-SecureBootCertificateUpdate — START" +Write-Log "Parametry: WhatIf=$isWhatIf, Force=$isForce, VerifyOnly=$isVerify, SkipTask=$isSkipTask" +Write-Log "Log: $LogPath" +Write-Log ('=' * 60) + +$results = @() + +if (-not $ServerName -or $ServerName.Count -eq 0) { + # ── Lokální spuštění ── + Write-Log "Spouštím lokálně na: $env:COMPUTERNAME" -Level 'INFO' + + if (-not $isWhatIf -and -not $isVerify) { + if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Nastavit Secure Boot registry klíče (AvailableUpdates=0x5944)")) { + Write-Log "Uživatel zamítl akci — konec." -Level 'WARN' + exit 0 + } + } + + $res = & $RemediationScriptBlock -WhatIfMode $isWhatIf -ForceMode $isForce ` + -VerifyOnlyMode $isVerify -SkipTask $isSkipTask + Write-ResultSummary $res + $results += $res + +} else { + # ── Vzdálené spuštění ── + Write-Log "Cílové servery ($($ServerName.Count)): $($ServerName -join ', ')" -Level 'INFO' + + $invokeParams = @{ + ComputerName = $ServerName + ScriptBlock = $RemediationScriptBlock + ArgumentList = @($isWhatIf, $isForce, $isVerify, $isSkipTask) + ErrorAction = 'SilentlyContinue' + ThrottleLimit = 10 + } + if ($Credential) { $invokeParams['Credential'] = $Credential } + + $remoteResults = Invoke-Command @invokeParams + + foreach ($res in $remoteResults) { + Write-ResultSummary $res + $results += $res + } + + # Servery, které neodpověděly + $respondedHosts = $remoteResults | ForEach-Object { $_.Hostname } + foreach ($srv in $ServerName) { + if ($srv -notin $respondedHosts) { + Write-Log " ! Server '$srv' neodpověděl (WinRM nedostupný nebo přihlášení selhalo)" -Level 'ERROR' + $results += [ordered]@{ + Hostname = $srv; Status = 'Unreachable'; Message = 'WinRM nedostupný' + PreState = $null; PostState = $null; ActionsApplied = @(); RequiresRestart = $false + } + } + } +} + +#-- Souhrn ------------------------------------------------------------------ +Write-Log ('=' * 60) +Write-Log "SOUHRN REMEDIACE" + +$grouped = $results | Group-Object Status +foreach ($g in $grouped) { + $lvl = switch ($g.Name) { + 'Applied' { 'SUCCESS' } + 'Error' { 'ERROR' } + 'Unreachable' { 'ERROR' } + 'Skipped' { 'WARN' } + 'Warning' { 'WARN' } + default { 'INFO' } + } + Write-Log " $($g.Name): $($g.Count) server(ů) [$(($g.Group.Hostname) -join ', ')]" -Level $lvl +} + +$needRestart = @($results | Where-Object { $_.RequiresRestart }) +if ($needRestart.Count -gt 0) { + Write-Log '' + Write-Log "VYŽADOVÁN RESTART ($($needRestart.Count) server(ů)): $($needRestart.Hostname -join ', ')" -Level 'WARN' + Write-Log "Po restartu ověřit EventID 1808 v System logu nebo spustit:" + Write-Log " Invoke-Command -ComputerName -ScriptBlock { Get-WinEvent -FilterHashtable @{LogName='System';Id=@(1801,1808)} -MaxEvents 5 | Select TimeCreated,Id,Message }" -Level 'INFO' +} + +Write-Log ('=' * 60) +Write-Log "Set-SecureBootCertificateUpdate — KONEC | Log: $LogPath" +Write-Log ('=' * 60) + +# Vrátit výsledky jako objekty pro pipeline +$results + +#endregion diff --git a/claude.md b/claude.md new file mode 100644 index 0000000..de70b6a --- /dev/null +++ b/claude.md @@ -0,0 +1,230 @@ +# Projekt: Audit a remediace Secure Boot certifikátů na Windows Serverech + +## Kontext a popis problematiky + +### Co se děje + +Microsoft vydal v červnu 2025 upozornění (KB5062710), že původní Secure Boot certifikáty z roku 2011 expirují v průběhu roku 2026. Jde o certifikáty uložené v UEFI firmware (KEK a DB databázích), které zajišťují důvěryhodnost boot procesu. + +**Expirující certifikáty a termíny:** + +| Certifikát | Expirace | Náhrada | +|---|---|---| +| Microsoft Corporation KEK CA 2011 | **24. června 2026** | Microsoft Corporation KEK 2K CA 2023 | +| Microsoft UEFI CA 2011 | **27. června 2026** | Microsoft UEFI CA 2023 + Microsoft Option ROM UEFI CA 2023 | +| Microsoft Windows Production PCA 2011 | 19. října 2026 | Windows UEFI CA 2023 | + +### Dopad na servery + +Servery, které neobdrží nové 2023 certifikáty, budou dál fungovat a bootovat normálně, ale **přestanou být schopné přijímat nové bezpečnostní ochrany boot procesu** — včetně aktualizací Windows Boot Manageru, Secure Boot databází, revokačních seznamů a mitigací nově objevených boot-level zranitelností. Postupem času to omezí ochranu před hrozbami a může ovlivnit scénáře závislé na Secure Boot důvěře, jako je BitLocker hardening nebo third-party bootloadery. + +### Specifika prostředí (MSP kontext) + +- Windows Server 2016, 2019, 2022, 2025 +- Fyzické servery různých výrobců (Dell, HP, Lenovo, Supermicro, ...) +- Virtuální stroje na **Hyper-V** (na Windows Server hostiteli) +- Virtuální stroje na **VMware ESXi** +- Prostředí spravovaná přes AD/GPO, bez Intune +- ~100–150 klientských prostředí různé velikosti + +### Klíčové technické detaily + +**Registry klíče relevantní pro stav:** +- `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot` — hlavní klíč (SecureBootEnabled, AvailableUpdates, HighConfidenceOptOut) +- `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing` — stav aktualizace (UEFICA2023Status, UEFICA2023Error, WindowsUEFICA2023Capable) +- `HKLM\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes` — atributy zařízení + +**Relevantní Event IDs (System log):** +- **1801** — chybová událost, certifikáty NEBYLY aplikovány +- **1808** — informační událost, certifikáty BYLY úspěšně aplikovány +- **1795** — selhání aktualizace (známý problém zejména u Hyper-V VM) +- **1796**, **1800**, **1802**, **1803** — doplňkové události průběhu + +**PowerShell cmdlet pro základní check:** +```powershell +Confirm-SecureBootUEFI +``` +Vrací `True` (Secure Boot zapnutý), `False`, nebo exception pokud UEFI Secure Boot není podporován. + +**Hyper-V specifikum:** U VM běžících na Hyper-V může selhávat aktualizace certifikátů s Event ID 1795. Tento known issue byl Microsoft řešen (resolved March 30, 2026) — ověřit verzi Hyper-V hostitele a aplikovat příslušné opravy. + +**VMware ESXi specifikum:** Záleží, zda VM má Secure Boot vůbec povolený (nastavení VM hardware). U Generation 1 ekvivalentu (BIOS mode) Secure Boot neexistuje. + +--- + +## Cíl projektu + +### Fáze 1 — Detekce (inventář) + +Vytvořit PowerShell detekční skript, který lze spustit vzdáleně přes `Invoke-Command` nebo lokálně na každém serveru a vrátit strukturovaný přehled stavu. + +**Výstup skriptu musí obsahovat:** + +1. Základní identifikace serveru (hostname, OS verze, architektura) +2. Typ prostředí (fyzický / Hyper-V VM / VMware VM / jiné) +3. Je Secure Boot podporováno? (UEFI vs. Legacy BIOS) +4. Je Secure Boot povoleno? +5. Aktuální stav certifikátů: + - Jsou přítomny expirující 2011 certifikáty? (KEK CA 2011, UEFI CA 2011, Windows PCA 2011) + - Jsou přítomny nové 2023 certifikáty? + - Stav z registry (`UEFICA2023Status`) +6. Confidence level (z event logu 1801/1808) +7. Poslední relevantní Event ID a čas +8. Hardware info (výrobce, model, firmware verze, datum firmware) +9. Dostupné aktualizace (`AvailableUpdates` registry hodnota) +10. Případné chyby (`UEFICA2023Error`) + +**Formát výstupu:** JSON (pro snadné zpracování a agregaci) + human-readable summary + +**Požadavky na skript:** +- Běží bez instalace dalších modulů (pure PowerShell 5.1+) +- Tolerantní vůči chybám — pokud Secure Boot není podporován/povolen, nezhavaruje +- Rozlišuje fyzický vs. VM (Hyper-V / VMware) přes WMI +- Exportuje výsledek lokálně i umožní vzdálené volání +- Wrapper skript pro hromadné spuštění přes seznam serverů z CSV/textového souboru + +### Fáze 2 — Analýza a kategorizace + +Na základě dat z detekce kategorizovat každý server do skupin: + +| Kategorie | Popis | Doporučená akce | +|---|---|---| +| **✅ OK** | Má nové 2023 certifikáty, Secure Boot aktivní | Žádná akce | +| **⚠️ Nutná aktualizace** | Má staré 2011 certifikáty, Secure Boot aktivní, firmware OK | Naplánovat rollout | +| **🔧 Čeká na firmware** | Secure Boot aktivní, ale firmware nepodporuje update | Kontaktovat OEM / update firmware | +| **⏸️ Secure Boot vypnuto** | Secure Boot existuje ale není zapnuto | Rozhodnutí o enablementu | +| **❌ Secure Boot nepodporováno** | Legacy BIOS nebo VM bez vTPM | Dokumentovat jako výjimku | +| **🔴 Selhání aktualizace** | Event 1795/chyba v registry | Troubleshooting | + +### Fáze 3 — Remediace + +Navrhnout a implementovat remediační postup pro prostředí bez Intune: + +**Metody rollout (zvážit dle prostředí klienta):** + +1. **Registry key metoda** — přímé nastavení klíčů přes PowerShell/GPO (KB5068202) +2. **GPO metoda** — Group Policy Objects pro nastavení (KB5068198) +3. **WinCS CLI** — Windows Configuration System nástroj pro domain-joined stroje (KB5068197) +4. **Ruční / skriptovaný rollout** — pro izolovaná prostředí + +**Postup rollout (staging):** +1. Test na 1–2 reprezentativních serverech každého typu (výrobce + firmware verze) +2. Ověření úspěchu přes Event ID 1808 a registry +3. Rozšíření na další skupinu +4. Monitoring (min. 48 hodin po aplikaci, čekat na restart) + +**Remediační PowerShell** musí umět: +- Nastavit registry klíče pro zahájení aktualizace +- Spustit/zkontrolovat scheduled task pro Secure Boot update +- Ověřit výsledek po restartu + +--- + +## Technické požadavky na kód + +### Detekční skript + +``` +Soubor: Invoke-SecureBootAudit.ps1 +``` + +**Logika detekce certifikátů** — kontrolovat přítomnost certifikátů přes `Get-SecureBootUEFI`: +- KEK databáze: hledat thumbprinty/subject odpovídající 2011 a 2023 certifikátům +- DB databáze: hledat Windows Production PCA 2011 / UEFI CA 2011 / jejich 2023 náhrady + +**Detekce typu prostředí:** +```powershell +# Hyper-V VM +(Get-WmiObject Win32_ComputerSystem).Model -eq "Virtual Machine" -and +(Get-WmiObject Win32_ComputerSystem).Manufacturer -like "*Microsoft*" + +# VMware VM +(Get-WmiObject Win32_ComputerSystem).Manufacturer -like "*VMware*" +``` + +**Ošetřit výjimky:** +- `Get-SecureBootUEFI` hodí exception pokud Secure Boot není podporováno nebo povoleno — zachytit a zalogovat +- Na Legacy BIOS strojích `Confirm-SecureBootUEFI` vrátí exception nebo False + +### Wrapper pro hromadné spuštění + +``` +Soubor: Start-SecureBootFleetAudit.ps1 +``` + +- Vstup: seznam serverů (parametr nebo CSV soubor s kolonkou `ServerName`) +- Výstup: agregovaný JSON + CSV soubor pro import do Excelu +- Paralelizace: `Invoke-Command` s `-ThrottleLimit` (doporučeno max 20 paralelně) +- Logování: výpis chyb nedostupných serverů do separátního souboru + +### Remediační skript + +``` +Soubor: Set-SecureBootCertificateUpdate.ps1 +``` + +- Parametry: `-ServerName`, `-WhatIf`, `-Force` +- WhatIf mode pro ověření před spuštěním +- Nastavit příslušné registry klíče dle KB5068202 +- Spustit nebo počkat na scheduled task +- Zalogovat výsledek + +--- + +## Omezení a rizika + +### Hyper-V VM +- Aktualizace Secure Boot certifikátů ve VM závisí na tom, zda **hypervizor poskytuje virtualizovaný UEFI** podporující aktualizace +- Generation 1 VM (BIOS) — Secure Boot nepodporují vůbec +- Generation 2 VM — mají virtualizovaný UEFI, ale aktualizace certifikátů závisí na verzi hypervizoru +- Known issue s Event 1795 byl opraven (březen 2026) — ověřit verzi Windows Server hostitele + +### VMware ESXi +- Secure Boot ve VMware VM závisí na konfiguraci VM (EFI firmware + Secure Boot v nastavení VM) +- VMware neposkytuje automatické předání nových certifikátů do VM — aktualizace musí proběhnout přes Windows jako na fyzickém stroji +- Na starších ESXi verzích může být virtualizovaný UEFI omezený + +### Fyzické servery +- Starší servery (zejména pre-2018) mohou vyžadovat firmware update od OEM před aplikací nových Secure Boot certifikátů +- Servery end-of-life od výrobce mohou nemít dostupný firmware update — dokumentovat jako výjimku + +### Obecná rizika +- Neúspěšná aktualizace certifikátů **NEOHROZÍ boot serveru** — server bude dál fungovat se starými certifikáty +- Aktualizace vyžaduje restart pro aplikaci Boot Manageru (ne jen certifikátů) +- Po aplikaci počítat s min. 48 hodinami a jedním nebo více restarty + +--- + +## Reference dokumentace + +- KB5062710 — [Přehled: Windows Secure Boot certificate expiration and CA updates](https://support.microsoft.com/en-us/topic/windows-secure-boot-certificate-expiration-and-ca-updates-7ff40d33-95dc-4c3c-8725-a9b95457578e) +- KB5062713 — [IT Pro guidance](https://support.microsoft.com/en-us/help/5062713) +- KB5068202 — [Registry key updates](https://support.microsoft.com/en-us/help/5068202) +- KB5068198 — [GPO metoda](https://support.microsoft.com/en-us/help/5068198) +- KB5068197 — [WinCS APIs](https://support.microsoft.com/en-us/help/5068197) +- KB5085046 — [Troubleshooting](https://support.microsoft.com/en-us/help/5085046) +- KB5085790 — [Known issues and resolutions](https://support.microsoft.com/en-us/help/5085790) +- KB5086397 — [Azure Local / HyperConverged Infrastructure](https://support.microsoft.com/en-us/help/5086397) +- [Secure Boot DB and DBX variable update events](https://support.microsoft.com/topic/37e47cf8-608b-4a87-8175-bdead630eb69) + +--- + +## Výstupy projektu (deliverables) + +1. **`Invoke-SecureBootAudit.ps1`** — detekční skript pro jednotlivý server +2. **`Start-SecureBootFleetAudit.ps1`** — wrapper pro hromadný audit celé sítě +3. **`Set-SecureBootCertificateUpdate.ps1`** — remediační skript s WhatIf podporou +4. **`README.md`** — dokumentace použití všech skriptů +5. **Vzorový výstup** — příklad JSON a CSV výstupu auditu + +--- + +## Priorita a časový rámec + +**Urgentní** — první dvě expirace jsou **24. a 27. června 2026** (týden od dnešního data). Audit je nutné provést okamžitě, aby bylo jasné, na kolika serverech je nutná akce. + +**Doporučené pořadí práce:** +1. Detekční skript (Fáze 1) — okamžitě +2. Hromadný wrapper + export do CSV — obratem po detekci +3. Analýza výsledků a kategorizace +4. Remediační skript — po otestování na pilotních serverech