Скопіюйте та вставте цей зразок сценарію та змініть його за потреби для свого середовища:
<# . ПІДСУМОК Виявляє стан оновлення сертифіката безпечного завантаження для моніторингу всього флоту.
.DESCRIPTION Цей сценарій виявлення збирає стан безпечного завантаження, значення реєстру оновлення сертифіката, та відомості про пристрій. Він виводить рядок JSON для моніторингу та звітування.
Compatible with Intune Remediations, GPO-based collection, and other management tools. Сценарій виправлення не потрібен – це лише моніторинг.
Exit 0 = "Without issue" (certificates updated) Exit 1 = "With issue" (сертифікати не оновлюються — лише інформаційні)
.PARAMETER OutputPath Необов'язково. Шлях до папки, у якій буде збережено JSON-файл.Якщо вказано, HOSTNAME_latest.json зберігається в цій папці.Якщо цього не вказано, виводить JSON у stdout (початкова поведінка).
.EXAMPLE # Вивід у stdout (виявлення Intune/SCCM) .\Detect-SecureBootCertUpdateStatus.ps1
.EXAMPLE # Збереження в мережевій папці (розгортання GPO) .\Detect-SecureBootCertUpdateStatus.ps1 -OutputPath "\\server\SecureBootLogs$"
.NOTES Шляхи реєстру на https://aka.ms/securebootplaybook: HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR НЕЯВНЕ, В ТОМУ ЧИСЛІ, АЛЕ НЕ ОБМЕЖУЄТЬСЯ ГАРАНТІЯМИ ПРИДАТНОСТІ ДО ПРОДАЖУ, ФІТНЕС ДЛЯ ПЕВНОЇ МЕТИ І НЕІНФРИНГУВАННЯ. У ЖОДНОМУ РАЗІ НЕ ЗОБОВ'ЯЗУЄТЬСЯ АВТОРИ АБО ВЛАСНИКИ АВТОРСЬКИХ ПРАВ НЕСУТЬ ВІДПОВІДАЛЬНІСТЬ ЗА БУДЬ-ЯКІ ПРЕТЕНЗІЇ, ЗБИТКИ АБО ІНШІ ВІДПОВІДАЛЬНОСТІ, НЕЗАЛЕЖНО ВІД ТОГО, ЧИ Є ДІЯ КОНТРАКТУ, ЦИВІЛЬНОГО ПРАВОПОРУШЕННЯ АБО ІНШИМ ЧИНОМ, ЩО ВИНИКАЄ ЧЕРЕЗ, НЕ ПОВ'ЯЗАНІ З ПРОГРАМНИМ ЗАБЕЗПЕЧЕННЯМ АБО ВИКОРИСТАННЯМ ЧИ ІНШИМИ СПРАВАМИ В ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ.#> param( [Parameter(Mandatory = $false)] [string]$OutputPath )
# Download URL: https://aka.ms/getsecureboot -> "Deployment and Monitoring Samples" # Примітка. Цей сценарій виконується в кінцевих точках для збирання даних про стан безпечного завантаження.
# 1. HostName # ВЕРСІЯ PS: Всі | Admin: Ні | Вимоги до системи: немає спробуйте { $hostname = $env:ІМ'Я КОМП'ЮТЕРА якщо ([рядок]::IsNullOrEmpty($hostname)) { Write-Warning "Не вдалося визначити ім'я хоста" $hostname = "Невідомо" } (}) Write-Host "Ім'я хоста: $hostname" } зловити { Write-Warning "Помилка отримання імені хоста: $_" $hostname = "Помилка" Write-Host "Ім'я хоста: $hostname" }
# 2. CollectionTime # ВЕРСІЯ PS: Всі | Admin: Ні | Вимоги до системи: немає спробуйте { $collectionTime = Get-Date якщо ($null -eq $collectionTime) { Write-Warning "Не вдалося отримати поточну дату й час" $collectionTime = "Невідомо" } (}) Write-Host "Час збирання: $collectionTime" } зловити { Write-Warning "Помилка отримання дати й часу: $_" $collectionTime = "Помилка" Write-Host "Час збирання: $collectionTime" }
# Registry: Secure Boot Main Key (3 values)
# 3. SecureBootEnabled # ВЕРСІЯ PS: 3.0+ | Admin: може знадобитися | Системні вимоги: система з підтримкою UEFI/безпечного завантаження спробуйте { $secureBootEnabled = Confirm-SecureBootUEFI -ErrorAction Stop Write-Host "Безпечне завантаження ввімкнуто: $secureBootEnabled" } зловити { Write-Warning "Не вдалося визначити стан безпечного завантаження за допомогою командлета: $_" # Спробуйте резервний реєстр спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -Name UEFISecureBootEnabled -ErrorAction Stop $secureBootEnabled = [bool]$regValue.UEFISecureBootEnabled Write-Host "Безпечне завантаження ввімкнуто: $secureBootEnabled" } зловити { Write-Warning "Не вдалося визначити стан безпечного завантаження за допомогою реєстру. Система може не підтримувати UEFI/безпечне завантаження." $secureBootEnabled = $null Write-Host "Безпечне завантаження ввімкнуто: недоступно" } (}) }
# 4. HighConfidenceOptOut # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name HighConfidenceOptOut -ErrorAction Stop $highConfidenceOptOut = $regValue.HighConfidenceOptOut Write-Host "Висока впевненість відмовитися: $highConfidenceOptOut" } зловити { # HighConfidenceOptOut необов'язковий – відсутній у більшості систем $highConfidenceOptOut = $null Write-Host "Висока впевненість відмовитися: не встановлено" }
# 4b. MicrosoftUpdateManagedOptIn # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name MicrosoftUpdateManagedOptIn -ErrorAction Stop $microsoftUpdateManagedOptIn = $regValue.MicrosoftUpdateManagedOptIn Write-Host "Microsoft Update Managed Opt in: $microsoftUpdateManagedOptIn" } зловити { # MicrosoftUpdateManagedOptIn необов'язковий – відсутній у більшості систем $microsoftUpdateManagedOptIn = $null Write-Host "Microsoft Update Managed Opt in: Not Set" }
# 5. AvailableUpdates # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdates -ErrorAction Stop $availableUpdates = $regValue.AvailableUpdates якщо ($null -ne $availableUpdates) { # Перетворити на шістнадцятковий формат $availableUpdatesHex = "0x{0:X}" -f $availableUpdates Write-Host "Доступні Оновлення: $availableUpdatesHex" } інакше { Write-Host "Доступний Оновлення: недоступно" } (}) } зловити { Write-Warning "Розділ реєстру AvailableUpdates не знайдено або недоступний" $availableUpdates = $null Write-Host "Доступний Оновлення: недоступний" }
# 5b. AvailableUpdatesPolicy (GPO-controlled persistent value) # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdatesPolicy -ErrorAction Stop $availableUpdatesPolicy = $regValue.AvailableUpdatesPolicy якщо ($null -ne $availableUpdatesPolicy) { # Перетворити на шістнадцятковий формат $availableUpdatesPolicyHex = "0x{0:X}" -f $availableUpdatesPolicy Write-Host "Доступна політика Оновлення: $availableUpdatesPolicyHex" } інакше { Write-Host "Доступна політика Оновлення: не встановлено" } (}) } зловити { # AvailableUpdatesPolicy необов'язковий – установлюється лише в разі застосування GPO $availableUpdatesPolicy = $null Write-Host "Доступна політика Оновлення: не встановлено" }
# Registry: Servicing Key (3 values)
# 6. UEFICA2023Status # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Status -ErrorAction Stop $uefica 2023Status = $regValue.UEFICA2023Status Write-Host "Стан Windows UEFI CA 2023: $uefica 2023Status" } зловити { Write-Warning "Windows UEFI CA 2023 Status registry key not found or inaccessible" $uefica 2023Status = $null Write-Host "Стан Windows UEFI CA 2023: недоступний" }
# 7. UEFICA2023Error # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Error -ErrorAction Stop $uefica 2023Error = $regValue.UEFICA2023Error Write-Host "Помилка UEFI CA 2023: $uefica 2023Помилка" } зловити { # UEFICA2023Error існує, тільки якщо сталася помилка - відсутність хороша $uefica 2023Помилка = $null Write-Host "Помилка UEFI CA 2023: немає" }
# 8. UEFICA2023ErrorEvent # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023ErrorEvent -ErrorAction Stop $uefica 2023ErrorEvent = $regValue.UEFICA2023ErrorEvent Write-Host "Подія помилки UEFI CA 2023: $uefica 2023ErrorEvent" } зловити { $uefica 2023ErrorEvent = $null Write-Host "Подія помилки UEFI CA 2023: недоступно" }
# Registry: Device Attributes (7 values: 9-15)
# 9. OEMManufacturerName # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMManufacturerName -ErrorAction Stop $oemManufacturerName = $regValue.OEMManufacturerName якщо ([рядок]::IsNullOrEmpty($oemManufacturerName)) { Write-Warning "OEMManufacturerName пусте" $oemManufacturerName = "Невідомо" } (}) Write-Host "Назва виробника оригінального обладнання: $oemManufacturerName" } зловити { Write-Warning "Розділ реєстру OEMManufacturerName не знайдено або недоступний" $oemManufacturerName = $null Write-Host "Назва виробника оригінального обладнання: недоступний" }
# 10. OEMModelSystemFamily # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMModelSystemFamily -ErrorAction Stop $oemModelSystemFamily = $regValue.OEMModelSystemFamily якщо ([рядок]::IsNullOrEmpty($oemModelSystemFamily)) { Write-Warning "OEMModelSystemFamily пустий" $oemModelSystemFamily = "Невідомо" } (}) Write-Host "Сімейство системи моделі OEM: $oemModelSystemFamily" } зловити { Write-Warning "Розділ реєстру OEMModelSystemFamily не знайдено або недоступний" $oemModelSystemFamily = $null Write-Host "Сімейство системи моделі OEM: недоступно" }
# 11. OEMModelNumber # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMModelNumber -ErrorAction Stop $oemModelNumber = $regValue.OEMModelNumber якщо ([рядок]::IsNullOrEmpty($oemModelNumber)) { Write-Warning "OEMModelNumber пустий" $oemModelNumber = "Невідомо" } (}) Write-Host "Номер моделі OEM: $oemModelNumber" } зловити { Write-Warning "Розділ реєстру OEMModelNumber не знайдено або недоступний" $oemModelNumber = $null Write-Host "Номер моделі OEM: недоступно" }
# 12. FirmwareVersion # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name FirmwareVersion -ErrorAction Stop $firmwareVersion = $regValue.FirmwareVersion якщо ([рядок]::IsNullOrEmpty($firmwareVersion)) { Write-Warning "FirmwareVersion пустий" $firmwareVersion = "Невідомо" } (}) Write-Host "Версія мікропрограми: $firmwareVersion" } зловити { Write-Warning "Розділ реєстру FirmwareVersion не знайдено або недоступний" $firmwareVersion = $null Write-Host "Версія мікропрограми: недоступна" }
# 13. FirmwareReleaseDate # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name FirmwareReleaseDate -ErrorAction Stop $firmwareReleaseDate = $regValue.FirmwareReleaseDate якщо ([рядок]::IsNullOrEmpty($firmwareReleaseDate)) { Write-Warning "FirmwareReleaseDate пустий" $firmwareReleaseDate = "Невідомо" } (}) Write-Host "Дата випуску мікропрограми: $firmwareReleaseDate" } зловити { Write-Warning "Розділ реєстру FirmwareReleaseDate не знайдено або недоступний" $firmwareReleaseDate = $null Write-Host "Дата випуску мікропрограми: недоступний" }
# 14. OSArchitecture # ВЕРСІЯ PS: Всі | Admin: Ні | Вимоги до системи: немає спробуйте { $osArchitecture = $env:PROCESSOR_ARCHITECTURE якщо ([рядок]::IsNullOrEmpty($osArchitecture)) { # Спробуйте резервний реєстр $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OSArchitecture -ErrorAction Stop $osArchitecture = $regValue.OSArchitecture } (}) якщо ([рядок]::IsNullOrEmpty($osArchitecture)) { Write-Warning "Не вдалося визначити параметр OSArchitecture" $osArchitecture = "Невідомо" } (}) Write-Host "Архітектура ОС: $osArchitecture" } зловити { Write-Warning "Помилка отриманняархівації ОС: $_" $osArchitecture = "Невідомо" Write-Host "Архітектура ОС: $osArchitecture" }
# 15. CanAttemptUpdateAfter (FILETIME) # ВЕРСІЯ PS: Всі | Admin: може знадобитися | Вимоги до системи: немає спробуйте { $regValue = Get-ItemProperty -шлях "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name CanAttemptUpdateAfter -ErrorAction Stop $canAttemptUpdateAfter = $regValue.CanAttemptUpdateAfter # Перетворити FILETIME на UTC DateTime – реєстр зберігається як REG_BINARY (байт[]) або REG_QWORD (довгий) якщо ($null -ne $canAttemptUpdateAfter) { спробуйте { якщо ($canAttemptUpdateAfter -це [байт[]]) { $fileTime = [BitConverter]::ToInt64($canAttemptUpdateAfter, 0) $canAttemptUpdateAfter = [Дата й час]::FromFileTime($fileTime). ToUniversalTime() } elseif ($canAttemptUpdateAfter -is [long]) { $canAttemptUpdateAfter = [DateTime]::FromFileTime($canAttemptUpdateAfter). ToUniversalTime() } (}) } зловити { Write-Warning "Не вдалося перетворити CanAttemptUpdateAfter FILETIME на DateTime" } (}) } (}) Write-Host "Може спробувати оновити після: $canAttemptUpdateAfter" } зловити { Write-Warning "CanAttemptUpdateAfter registry key not found or inaccessible" (Розділ реєстру CanAttemptUpdateAfter не знайдено або недоступний) $canAttemptUpdateAfter = $null Write-Host "Може спробувати оновити після: недоступний" }
# Event Logs: System Log (10 values: 16-25)
# 16-25. Event Log queries # Ідентифікатори подій: # 1801 - ініційовано оновлення, потрібне перезавантаження # 1808 – оновлення успішно завершено # 1795 - мікропрограма повернула помилку (код помилки записування) # 1796 – помилка в журналі з кодом помилки (код записування) # 1800 – потрібне перезавантаження (НЕ помилка – оновлення буде продовжуватися після перезавантаження) # 1802 - Відома проблема мікропрограми заблоковано оновлення (запис KI_<номер> з SkipReason) # 1803 - Відповідне оновлення KEK не знайдено (OEM має постачати ПК підписаний KEK) # ВЕРСІЯ PS: 3.0+ | Admin: може знадобитися для системного журналу | Вимоги до системи: немає спробуйте { # Запитувати всі відповідні ідентифікатори подій безпечного завантаження $allEventIds = @(1795, 1796, 1800, 1801, 1802, 1803, 1808) $events = @(Get-WinEvent -FilterHashtable @{LogName='System'; ID=$allEventIds} - MaxEvents 50 -ErrorAction Stop)
if ($events.Count -eq 0) { Write-Warning "У системному журналі не знайдено подій безпечного завантаження" $latestEventId = $null $bucketId = $null $confidence = $null $skipReasonKnownIssue = $null $event 1801Count = 0 $event 1808Count = 0 $event 1795Count = 0 $event 1795КодerrorCode = $null $event 1796Count = 0 $event 1796КодerrorCode = $null $event 1800Count = 0 $rebootPending = $false $event 1802Count = 0 $knownIssueId = $null $event 1803Count = 0 $missingKEK = $false Write-Host "Найновіший ідентифікатор події: недоступно" Write-Host "Код сегмента: недоступний" Write-Host "Впевненість: недоступно" Write-Host "Подія 1801 Count: 0" Write-Host "Подія 1808 Count: 0" } інакше { # 16. LatestEventId (Найновіший ідентифікатор) $latestEvent = $events | Sort-Object час, створений за спаданням | Select-Object –перший 1 якщо ($null -eq $latestEvent) { Write-Warning "Не вдалося визначити останню подію" $latestEventId = $null Write-Host "Найновіший ідентифікатор події: недоступно" } інакше { $latestEventId = $latestEvent.Id Write-Host "Найновіший ідентифікатор події: $latestEventId" }
# 17. BucketID - Extracted from Event 1801/1808 якщо ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { якщо ($latestEvent.Message -match 'BucketId:\s*(.+)') { $bucketId = $matches[1]. Trim() Write-Host "Код сегмента: $bucketId" } інакше { Write-Warning "Код bucketId не знайдено в повідомленні про подію" $bucketId = $null Write-Host "Код сегмента: не знайдено у події" } (}) } інакше { Write-Warning "Остання подія або повідомлення має null-значення, не вдалося видобути BucketId" $bucketId = $null Write-Host "Код сегмента: недоступний" }
# 18. Confidence - Extracted from Event 1801/1808 якщо ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { якщо ($latestEvent.Message -match 'BucketConfidenceLevel:\s*(.+)') { $confidence = $matches[1]. Trim() Write-Host "Впевненість: $confidence" } інакше { Write-Warning "У повідомленні про подію не знайдено довірчий рівень" $confidence = $null Write-Host "Впевненість: не знайдено у події" } (}) } інакше { Write-Warning "Остання подія або повідомлення має null-значення, не вдалося видобути довіру" $confidence = $null Write-Host "Впевненість: недоступно" }
# 18b. SkipReason - Extract KI_<number> from SkipReason in the same event as BucketId # Це записує відомі ідентифікатори проблем, які відображаються поряд із BucketId/Confidence (не тільки подія 1802) $skipReasonKnownIssue = $null якщо ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { якщо ($latestEvent.Message -match 'SkipReason:\s*(KI_\d+)') { $skipReasonKnownIssue = $matches[1] Write-Host "Відома проблема SkipReason: $skipReasonKnownIssue" -ForegroundColor Yellow } (}) }
# 19. Event1801Count $event 1801Array = @($events | Where-Object {$_. Id -eq 1801}) $event 1801Count = $event 1801Array.Count Write-Host "Кількість подій 1801: $event 1801Count"
# 20. Event1808Count $event 1808Array = @($events | Where-Object {$_. Id -eq 1808}) $event 1808Count = $event 1808Array.Count Write-Host "Кількість подій 1808: $event 1808Count" # Ініціалізація змінних подій помилки $event 1795Count = 0 $event 1795КодerrorCode = $null $event 1796Count = 0 $event 1796КодerrorCode = $null $event 1800Count = 0 $rebootPending = $false $event 1802Count = 0 $knownIssueId = $null $event 1803Count = 0 $missingKEK = $false # Перевірте наявність подій помилок, лише якщо оновлення не завершено # Пропустити аналіз помилок, якщо: 1808 є останньою подією OR UEFICA2023Status є "Оновлено" $updateComplete = ($latestEventId -eq 1808) - або ($uefica 2023Status -eq "Оновлено") якщо (-не $updateComplete) { Write-Host "Оновлення не завершено – перевірка наявності подій помилок..." -ForegroundColor Yellow # 21. Подія1795 – помилка мікропрограми (код помилки записування) $event 1795Array = @($events | Where-Object {$_. Id -eq 1795}) $event 1795Count = $event 1795Array.Count якщо ($event 1795Count -gt 0) { $latestEvent 1795 = $event 1795Array | Sort-Object часстворито –за спаданням | Select-Object –перший 1 якщо ($latestEvent 1795.Повідомлення -match '(?:error|code|status)[:\s]*(?:0x)?( [0-9A-Fa-f]{8}|[0-9A-Fa-f]+)') { $event 1795ErrorCode = $matches[1] } (}) Write-Host "Подія 1795 (помилка мікропрограми) Count: $event 1795Count" $(якщо ($event 1795ErrorCode) { "Код: $event 1795ErrorCode" }) } (}) # 22. Event1796 – код помилки, записаний (код помилки записування) $event 1796Array = @($events | Where-Object {$_. Id -eq 1796}) $event 1796Count = $event 1796Array.Count якщо ($event 1796Count -gt 0) { $latestEvent 1796 = $event 1796Array | Sort-Object часстворито –за спаданням | Select-Object –перший 1 якщо ($latestEvent 1796.Повідомлення -match '(?:error|code|status)[:\s]*(?:0x)?( [0-9A-Fa-f]{8}|[0-9A-Fa-f]+)') { $event 1796КодerrorCode = $matches[1] } (}) Write-Host "Event 1796 (Error Logged) Count: $event 1796Count" $(if ($event 1796ErrorCode) { "Код: $event 1796ErrorCode" }) } (}) # 23. Event1800 – потрібне перезавантаження (НЕ помилка – оновлення буде продовжуватися після перезавантаження) $event 1800Array = @($events | Where-Object {$_. Id -eq 1800}) $event 1800Count = $event 1800Array.Count $rebootPending = $event 1800Count -gt 0 якщо ($rebootPending) { Write-Host "Подія 1800 (очікування перезавантаження): оновлення буде продовжуватися після перезавантаження" -ForegroundColor Cyan } (}) # 24. Подія1802 – відома проблема мікропрограми (запис KI_<номер> з SkipReason) $event 1802Array = @($events | Where-Object {$_. Id -eq 1802}) $event 1802Count = $event 1802Array.Count якщо ($event 1802Count -gt 0) { $latestEvent 1802 = $event 1802Array | Sort-Object часстворито –за спаданням | Select-Object –перший 1 якщо ($latestEvent 1802.Message –match 'SkipReason:\s*(KI_\d+)') { $knownIssueId = $matches[1] } (}) Write-Host "Подія 1802 (відома проблема з мікропрограмою):$event 1802Count" $(якщо ($knownIssueId) { "KI: $knownIssueId" }) } (}) # 25. Event1803 – відсутнє оновлення KEK (OEM має надати KEK із підписом PK) $event 1803Array = @($events | Where-Object {$_. Id -eq 1803}) $event 1803Count = $event 1803Array.Count $missingKEK = $event 1803Count -gt 0 якщо ($missingKEK) { Write-Host "Подія 1803 (відсутній KEK): OEM має поставити ПК підписаний KEK" -ForegroundColor Yellow } (}) } інакше { Write-Host "Оновлення завершено (подія 1808 або стан=Оновлено) – пропуск аналізу помилок" -ForegroundColor Green } (}) } (}) } зловити { Write-Warning "Помилка отримання журналів подій. Може вимагати права адміністратора: $_" $latestEventId = $null $bucketId = $null $confidence = $null $skipReasonKnownIssue = $null $event 1801Count = 0 $event 1808Count = 0 $event 1795Count = 0 $event 1795КодerrorCode = $null $event 1796Count = 0 $event 1796КодerrorCode = $null $event 1800Count = 0 $rebootPending = $false $event 1802Count = 0 $knownIssueId = $null $event 1803Count = 0 $missingKEK = $false Write-Host "Найновіший ідентифікатор події: помилка" Write-Host "Код сегмента: помилка" Write-Host "Впевненість: помилка" Write-Host "Подія 1801 Count: 0" Write-Host "Подія 1808 Count: 0" }
# WMI/CIM Queries (5 values)
# 26. OSVersion # ВЕРСІЯ PS: 3.0+ (використовуйте Get-WmiObject для 2.0) | Admin: Ні | Вимоги до системи: немає спробуйте { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop якщо ($null -eq $osInfo -або [рядок]::IsNullOrEmpty($osInfo.Version)) { Write-Warning "Не вдалося отримати версію ОС" $osVersion = "Невідомо" } інакше { $osVersion = $osInfo.Version } (}) Write-Host "Версія ОС: $osVersion" } зловити { # CIM може не вдатися в деяких середовищах - використовувати резервний варіант $osVersion = [System.Environment]::OSVersion.Version.ToString() якщо ([рядок]::IsNullOrEmpty($osVersion)) { $osVersion = "Невідомо" } Write-Host "Версія ОС: $osVersion" }
# 27. LastBootTime # ВЕРСІЯ PS: 3.0+ (використовуйте Get-WmiObject для 2.0) | Admin: Ні | Вимоги до системи: немає спробуйте { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop якщо ($null -eq $osInfo -або $null -eq $osInfo.LastBootUpTime) { Write-Warning "Не вдалося отримати час останнього завантаження" $lastBootTime = $null Write-Host "Час останнього завантаження: недоступний" } інакше { $lastBootTime = $osInfo.LastBootUpTime Write-Host "Час останнього завантаження: $lastBootTime" } (}) } зловити { # CIM може не вдатися в деяких середовищах - використовувати резервний варіант спробуйте { $lastBootTime = (Get-Process -Id 0 -ErrorAction SilentlyContinue). Час початку } зловити { $lastBootTime = $null } (}) якщо ($lastBootTime) { Write-Host "Час останнього завантаження: $lastBootTime" } інакше { Write-Host "Час останнього завантаження: недоступно" } }
# 28. BaseBoardManufacturer # ВЕРСІЯ PS: 3.0+ (використовуйте Get-WmiObject для 2.0) | Admin: Ні | Вимоги до системи: немає спробуйте { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop якщо ($null -eq $baseBoard -або [рядок]::IsNullOrEmpty($baseBoard.Manufacturer)) { Write-Warning "Не вдалося отримати виробника базової плати" $baseBoardManufacturer = "Невідомо" } інакше { $baseBoardManufacturer = $baseBoard.Manufacturer } (}) Write-Host "Виробник базової плати: $baseBoardManufacturer" } зловити { # CIM може не вдаватись – відомості про базову плату додаткові $baseBoardManufacturer = "Невідомо" Write-Host "Виробник базової плати: $baseBoardManufacturer" }
# 29. BaseBoardProduct # ВЕРСІЯ PS: 3.0+ (використовуйте Get-WmiObject для 2.0) | Admin: Ні | Вимоги до системи: немає спробуйте { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop якщо ($null -eq $baseBoard -або [рядок]::IsNullOrEmpty($baseBoard.Product)) { Write-Warning "Не вдалося отримати базовий продукт" $baseBoardProduct = "Невідомо" } інакше { $baseBoardProduct = $baseBoard.Product } (}) Write-Host "Базовий продукт: $baseBoardProduct" } зловити { # CIM може не вдаватись – відомості про базову плату додаткові $baseBoardProduct = "Невідомо" Write-Host "Базовий продукт: $baseBoardProduct" }
# 30. SecureBootTaskEnabled # ВЕРСІЯ PS: Всі | Admin: Ні | Системні вимоги: заплановане завдання існує # Перевіряє, чи ввімкнуто заплановане завдання secure-Boot-Update $secureBootTaskEnabled = $null $secureBootTaskStatus = "Невідомо" спробуйте { $taskOutput = schtasks.exe /Query /TN "\Microsoft\Windows\PI\Secure-Boot-Update" /FO CSV 2>&1 якщо ($LASTEXITCODE -eq 0) { $taskData = $taskOutput | Перетворення файлу CSV якщо ($taskData) { $secureBootTaskStatus = $taskData.Стан $secureBootTaskEnabled = ($taskData.Status - eq "Ready" -or $taskData.Status -eq "Running") } (}) } інакше { $secureBootTaskStatus = "NotFound" $secureBootTaskEnabled = $false } (}) якщо ($secureBootTaskEnabled -eq $false) { Write-Host "Завдання оновлення захищеного завантаження: $secureBootTaskStatus (увімкнуто: $secureBootTaskEnabled)" -ForegroundColor Yellow } інакше { Write-Host "Завдання оновлення захищеного завантаження: $secureBootTaskStatus (увімкнуто: $secureBootTaskEnabled)" -ForegroundColor Green } (}) } зловити { $secureBootTaskStatus = "Помилка" $secureBootTaskEnabled = $false Write-Host "Завдання оновлення secureBoot: перевірка помилок – $_" –червоний колір переднього плану }
# 31. WinCS Key Status (F33E0C8E002 - Secure Boot Certificate Update) # ВЕРСІЯ PS: Всі | Admin: Так (для запиту) | Вимоги до системи: WinCsFlags.exe $wincsKeyApplied = $null $wincsKeyStatus = "Невідомо" спробуйте { # Перевірка поширених розташувань для WinCsFlags.exe $wincsFlagsPath = $null $possiblePaths = @( "$env:SystemRoot\System32\WinCsFlags.exe", "$env:SystemRoot\SysWOW64\WinCsFlags.exe" ) foreach ($p in $possiblePaths) { if ($p test-path) { $wincsFlagsPath = $p; break } } (}) якщо ($wincsFlagsPath) { # Певний ключ запиту – потрібні права адміністратора $queryOutput = & $wincsFlagsPath /query --key F33E0C8E002 2>&1 $queryOutputStr = $queryOutput -join "'n" якщо ($LASTEXITCODE -eq 0) { # Перевірте, чи застосовано ключ (знайдіть "Активна конфігурація" або схожий індикатор) якщо ($queryOutputStr -match "Активна конфігурація.*:.*enabled" -або $queryOutputStr -match "Configuration.*applied") { $wincsKeyApplied = $true $wincsKeyStatus = "Застосовано" Write-Host "WinCS Key F33E0C8E002: Applied" -ForegroundColor Green } elseif ($queryOutputStr -match "не знайдено|Без конфігурації") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "Ключ WinCS F33E0C8E002: Не застосовується" -ForegroundColor Yellow } інакше { # Ключ існує - перевірка результатів для стану $wincsKeyApplied = $true $wincsKeyStatus = "Застосовано" Write-Host "WinCS Key F33E0C8E002: Applied" -ForegroundColor Green } (}) } інакше { # Перевірте наявність конкретних повідомлень про помилки якщо ($queryOutputStr -match "Немає доступу|адміністратор") { $wincsKeyStatus = "AccessDenied" Write-Host "F33E0C8E002 ключа WinCS: немає доступу (запуск із правами адміністратора)" -ForegroundColor DarkGray } elseif ($queryOutputStr -match "не знайдено|Без конфігурації") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "F33E0C8E002 ключа WinCS: Not Applied" -ForegroundColor Yellow } інакше { $wincsKeyStatus = "Запит скасовано" Write-Host "F33E0C8E002 ключа WinCS: запит не виконано" -ForegroundColor Red } (}) } (}) } інакше { $wincsKeyStatus = "WinCsFlagsNotFound" Write-Host "F33E0C8E002 ключа WinCS: WinCsFlags.exe не знайдено" -ForegroundColor Gray } (}) } зловити { $wincsKeyStatus = "Помилка" Write-Host "F33E0C8E002 ключа WinCS: перевірка помилок - $_" -ForegroundColor Red }
# ============================================================================= # Виявлення виправлення – код виходу стану & виходу # =============================================================================
# Build status object from all collected inventory data $status = [ordered]@{ UEFICA2023Status = $uefica 2023Status UEFICA2023Error = $uefica 2023Error UEFICA2023ErrorEvent = $uefica 2023ErrorEvent AvailableUpdates = if ($null -ne $availableUpdates) { $availableUpdatesHex } інакше { $null } AvailableUpdatesPolicy = if ($null -ne $availableUpdatesPolicy) { $availableUpdatesPolicyHex } інакше { $null } Hostname = $hostname CollectionTime = if ($collectionTime -is [datetime]) { $collectionTime.ToString("o") } інакше { "$collectionTime" } SecureBootEnabled = $secureBootEnabled HighConfidenceOptOut = $highConfidenceOptOut MicrosoftUpdateManagedOptIn = $microsoftUpdateManagedOptIn OEMManufacturerName = $oemManufacturerName OEMModelSystemFamily = $oemModelSystemFamily OEMModelNumber = $oemModelNumber FirmwareVersion = $firmwareVersion FirmwareReleaseDate = $firmwareReleaseDate OsArchitecture = $osArchitecture CanAttemptUpdateAfter = if ($canAttemptUpdateAfter -is [datetime]) { $canAttemptUpdateAfter.ToString("o") } інакше { "$canAttemptUpdateAfter" } LatestEventId = $latestEventId Код сегмента = $bucketId Confidence = $confidence SkipReasonKnownIssue = $skipReasonKnownIssue # KI_<номер> з події SkipReason in BucketId Event1801Count = $event 1801Count Event1808Count = $event 1808Count # Події помилок із записаними відомостями Event1795Count = $event 1795Count # мікропрограма повернула помилку Event1795ErrorCode = $event 1795ErrorCode # Код помилки з мікропрограми Event1796Count = $event 1796Count # код помилки записано Event1796ErrorCode = $event 1796ErrorCode # Записаний код помилки Event1800Count = $event 1800Count # Потрібне перезавантаження (НЕ помилка) Триває перезавантаження = $rebootPending # True, якщо подія 1800 присутня Event1802Count = $event 1802Count # Відома проблема з мікропрограмою KnownIssueId = $knownIssueId # KI_<номер> з SkipReason Event1803Count = $event 1803Count # Відсутнє оновлення KEK MissingKEK = $missingKEK # OEM needs to supply PK signed KEK OSVersion = $osVersion LastBootTime = if ($lastBootTime -is [datetime]) { $lastBootTime.ToString("o") } інакше { "$lastBootTime" } BaseBoardManufacturer = $baseBoardManufacturer BaseBoardProduct = $baseBoardProduct SecureBootTaskEnabled = $secureBootTaskEnabled Стан SecureBootTaskStatus = $secureBootTaskStatus WinCSKeyApplied = $wincsKeyApplied # True, якщо застосовується клавіша F33E0C8E002 WinCSKeyStatus = $wincsKeyStatus # Applied, NotApplied, WinCsFlagsNotFound тощо. }
# Output the status - For data aggregation $jsonOutput = $status | ConvertTo-Json –стиснути
# If OutputPath provided, save to file; otherwise output to stdout якщо (-not [рядок]::IsNullOrEmpty($OutputPath)) { # Перевірка OutputPath – пропустіть, чи є запит на довідку або містить неприпустимі символи якщо ($OutputPath -match '^[/\-]' -або $OutputPath -match '[<>:"|? *]') { Write-Host "Вказано неприпустимий вихідний шлях, виводиться в stdout" -ForegroundColor Yellow Write-Output $jsonOutput якщо ($secureBootEnabled -and $uefica 2023Status -eq "Оновлено") { exit 0 } else { exit 1 } } (}) # Переконайтеся, що папка виводу існує if (-not (test-path $OutputPath)) { спробуйте { New-Item -ItemType Directory – шлях $OutputPath -Force | Out-Null } зловити { Write-Warning "Не вдалося створити папку виводу: $OutputPath - $_" } (}) } (}) # Зберегти в HOSTNAME_latest.json $outputFile = Join-Path $OutputPath "$($hostname)_latest.json" спробуйте { $jsonOutput | Out-File -FilePath $outputFile -Encoding UTF8 -Force Write-Host "JSON збережено в: $outputFile" -ForegroundColor Green } зловити { Write-Warning "Не вдалося записати до файлу: $outputFile - $_" # Повернутися до stdout Write-Output $jsonOutput } (}) } інакше { # Початкова поведінка – вивід у stdout Write-Output $jsonOutput }
# Exit code: "Updated" is the success value per the playbook if ($secureBootEnabled -and $uefica 2023Status -eq "Оновлено") { вихід 0 # без проблем } інакше { вихід 1 # з проблемою }