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
This commit is contained in:
Petr Stepan
2026-06-05 14:05:27 +00:00
commit 9a230866a2
5 changed files with 1714 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
+655
View File
@@ -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
+310
View File
@@ -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 (12 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 <server> -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) |
+519
View File
@@ -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-<datum>.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 <server> -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
+230
View File
@@ -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
- ~100150 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 12 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