9a230866a2
- 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
520 lines
21 KiB
PowerShell
520 lines
21 KiB
PowerShell
#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
|