Исходная дата публикации: 17 ноября 2025 г.
Идентификатор базы знаний: 5072718
|
Дата изменения |
Описание изменений |
|
24 февраля 2026 г. |
|
|
22 февраля 2026 г. |
|
|
13 февраля 2026 г. |
|
Пример сценария сбора данных инвентаризации безопасной загрузки
Скопируйте и вставьте этот пример скрипта и измените его при необходимости для своей среды: пример сценария сбора данных инвентаризации безопасной загрузки.
<# . ОБЗОР Определяет состояние обновления сертификата безопасной загрузки для мониторинга на уровне всего парка.
. ОПИСАНИЕ Этот скрипт обнаружения собирает сведения о состоянии безопасной загрузки, значениях реестра обновления сертификатов, и сведения об устройстве. Он выводит строку JSON для мониторинга и создания отчетов.
Совместимо с Intune исправлениями, коллекцией на основе объектов групповой политики и другими средствами управления.Скрипт исправления не требуется — это только мониторинг.
Выход 0 = "Без проблем" (сертификаты обновлены) Выход 1 = "С проблемой" (сертификаты не обновлены — только информационные)
. Параметр OutputPath Дополнительные. Путь к папке, в которой будет сохранен JSON-файл.Если этот параметр указан, сохраняет HOSTNAME_latest.json в этой папке.Если это не указано, выводит JSON в stdout (исходное поведение).
. ПРИМЕРЕ # Выходные данные в stdout (обнаружение Intune/SCCM) .\Detect-SecureBootCertUpdateStatus.ps1
. ПРИМЕРЕ # Сохранение в сетевую папку (развертывание объекта групповой политики) .\Detect-SecureBootCertUpdateStatus.ps1 -OutputPath "\\server\SecureBootLogs$"
. ЗАМЕТКИ Пути к реестру на https://aka.ms/securebootplaybook: HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ "КАК ЕСТЬ", БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЭКСПРЕСС ИЛИ ПОДРАЗУМЕВАЕМЫЕ, ВКЛЮЧАЯ, ПОМИМО ПРОЧЕГО, ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕСОВЕРШЕНИЕ. НИ В КАКИХ СЛУЧАЯХ НЕ ДОЛЖЕН АВТОРЫ ИЛИ ВЛАДЕЛЬЦЫ АВТОРСКИХ ПРАВ НЕСУТ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГИЕ ОТВЕТСТВЕННОСТЬ, БУДЬ ТО В ИНОМ ДОГОВОРЕ, ДЕЛИКТЕ ИЛИ ИНЫМ ОБРАЗОМ, ВОЗНИКАЮЩАЯ ИЗ, ВНЕ ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ, ИСПОЛЬЗОВАНИЕ ИЛИ ДРУГИЕ СДЕЛКИ В ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ.#> param( [Parameter(Обязательный = $false)] [строка]$OutputPath )
# URL-адрес для скачивания: https://aka.ms/getsecureboot -> "Примеры развертывания и мониторинга" # Примечание. Этот скрипт выполняется на конечных точках для сбора данных о состоянии безопасной загрузки.
# 1. Узла # Версия PS: Все | Администратор: Нет | Требования к системе: нет try { $hostname = $env:COMPUTERNAME if ([string]::IsNullOrEmpty($hostname)) { Write-Warning "Не удалось определить имя узла" $hostname = "Unknown" } Write-Host "Имя узла: $hostname" } catch { Write-Warning "Ошибка при получении имени узла: $_" $hostname = "Ошибка" Write-Host "Имя узла: $hostname" }
# 2. CollectionTime # Версия PS: Все | Администратор: Нет | Требования к системе: нет try { $collectionTime = Get-Date if ($null -eq $collectionTime) { Write-Warning "Не удалось получить текущую дату и время" $collectionTime = "Unknown" } Write-Host "Время сбора: $collectionTime" } catch { Write-Warning "Ошибка получения даты и времени: $_" $collectionTime = "Error" Write-Host "Время сбора: $collectionTime" }
# Реестр: главный ключ безопасной загрузки (3 значения)
# 3. SecureBootEnabled # PS Version: 3.0+ | Администратор: может потребоваться | Требования к системе: система с поддержкой UEFI и безопасной загрузки try { $secureBootEnabled = Confirm-SecureBootUEFI -ErrorAction Stop Write-Host "Безопасная загрузка включена: $secureBootEnabled" } catch { Write-Warning "Не удается определить состояние безопасной загрузки с помощью командлета: $_" # Попробуйте резервный реестр try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -Name UEFISecureBootEnabled -ErrorAction Stop $secureBootEnabled = [bool]$regValue.UEFISecureBootEnabled Write-Host "Безопасная загрузка включена: $secureBootEnabled" } catch { Write-Warning "Не удается определить состояние безопасной загрузки с помощью реестра. Система может не поддерживать UEFI и безопасную загрузку". $secureBootEnabled = $null Write-Host "Безопасная загрузка включена: недоступна" } }
# 4. HighConfidenceOptOut # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name HighConfidenceOptOut -ErrorAction Stop $highConfidenceOptOut = $regValue.HighConfidenceOptOut Write-Host "Отказ с высокой достоверностью: $highConfidenceOptOut" } catch { # HighConfidenceOptOut является необязательным — отсутствует в большинстве систем $highConfidenceOptOut = $null Write-Host "Отказ с высокой достоверностью: не задано" }
No 4b. MicrosoftUpdateManagedOptIn # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name MicrosoftUpdateManagedOptIn -ErrorAction Stop $microsoftUpdateManagedOptIn = $regValue.MicrosoftUpdateManagedOptIn Write-Host "Управляемое согласие Центра обновления Майкрософт: $microsoftUpdateManagedOptIn" } catch { # MicrosoftUpdateManagedOptIn является необязательным — отсутствует в большинстве систем $microsoftUpdateManagedOptIn = $null Write-Host "Управляемое согласие Центра обновления Майкрософт: не задано" }
# 5. AvailableUpdates # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdates -ErrorAction Stop $availableUpdates = $regValue.AvailableUpdates if ($null -ne $availableUpdates) { # Преобразование в шестнадцатеричный формат $availableUpdatesHex = "0x{0:X}" -f $availableUpdates Write-Host "Доступные Обновления: $availableUpdatesHex" } else { Write-Host "Доступное Обновления: недоступно" } } catch { Write-Warning "AvailableUpdates раздел реестра не найден или недоступен" $availableUpdates = $null Write-Host "Доступное Обновления: недоступно" }
No 5b. AvailableUpdatesPolicy (постоянное значение, управляемое GPO) # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdatesPolicy -ErrorAction Stop $availableUpdatesPolicy = $regValue.AvailableUpdatesPolicy if ($null -ne $availableUpdatesPolicy) { # Преобразование в шестнадцатеричный формат $availableUpdatesPolicyHex = "0x{0:X}" -f $availableUpdatesPolicy Write-Host "Доступная политика Обновления: $availableUpdatesPolicyHex" } else { Write-Host "Доступная политика Обновления: не задано" } } catch { # AvailableUpdatesPolicy является необязательным— устанавливается только при применении объекта групповой политики. $availableUpdatesPolicy = $null Write-Host "Доступная политика Обновления: не задано" }
# Реестр: обслуживающий ключ (3 значения)
# 6. UEFICA2023Status # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Status -ErrorAction Stop $uefica 2023Status = $regValue.UEFICA2023Status Write-Host "Windows UEFI CA 2023 Status: $uefica 2023Status" } catch { Write-Warning "Раздел реестра состояния Windows UEFI CA 2023 не найден или недоступен" $uefica 2023Status = $null Write-Host "Windows UEFI CA 2023 Status: Not Available" (Состояние windows UEFI CA 2023: недоступно) }
# 7. UEFICA2023Error # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Error -ErrorAction Stop $uefica 2023Error = $regValue.UEFICA2023Error Write-Host "Ошибка UEFI CA 2023: $uefica 2023Error" } catch { # UEFICA2023Error существует только в том случае, если произошла ошибка — отсутствие хорошо $uefica 2023Error = $null Write-Host "Ошибка UEFI CA 2023: Нет" }
# 8. UEFICA2023ErrorEvent # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023ErrorEvent -ErrorAction Stop $uefica 2023ErrorEvent = $regValue.UEFICA2023ErrorEvent Write-Host "Событие ошибки UEFI CA 2023: $uefica 2023ErrorEvent" } catch { $uefica 2023ErrorEvent = $null Write-Host "Событие ошибки UEFI CA 2023: недоступно" }
# Реестр: атрибуты устройства (7 значений: 9–15)
# 9. OEMManufacturerName # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMManufacturerName -ErrorAction Stop $oemManufacturerName = $regValue.OEMManufacturerName if ([string]::IsNullOrEmpty($oemManufacturerName)) { Write-Warning "OEMManufacturerName является пустым" $oemManufacturerName = "Unknown" } Write-Host "Имя изготовителя oem: $oemManufacturerName" } catch { Write-Warning "КЛЮЧ реестра OEMManufacturerName не найден или недоступен" $oemManufacturerName = $null Write-Host "Имя изготовителя oem: недоступно" }
# 10. OEMModelSystemFamily # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMModelSystemFamily -ErrorAction Stop $oemModelSystemFamily = $regValue.OEMModelSystemFamily if ([string]::IsNullOrEmpty($oemModelSystemFamily)) { Write-Warning "OEMModelSystemFamily пусто" $oemModelSystemFamily = "Unknown" } Write-Host "Семейство систем моделей OEM: $oemModelSystemFamily" } catch { Write-Warning "РАЗДЕЛ реестра OEMModelSystemFamily не найден или недоступен" $oemModelSystemFamily = $null Write-Host "Семейство систем моделей oem: недоступно" }
# 11. OEMModelNumber # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OEMModelNumber -ErrorAction Stop $oemModelNumber = $regValue.OEMModelNumber if ([string]::IsNullOrEmpty($oemModelNumber)) { Write-Warning "OEMModelNumber is empty" $oemModelNumber = "Unknown" } Write-Host "Номер модели OEM: $oemModelNumber" } catch { Write-Warning "Раздел реестра OEMModelNumber не найден или недоступен" $oemModelNumber = $null Write-Host "Номер модели OEM: недоступно" }
# 12. FirmwareVersion # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name FirmwareVersion -ErrorAction Stop $firmwareVersion = $regValue.FirmwareVersion if ([string]::IsNullOrEmpty($firmwareVersion)) { Write-Warning "FirmwareVersion is empty" $firmwareVersion = "Unknown" } Write-Host "Версия встроенного ПО: $firmwareVersion" } catch { Write-Warning "Раздел реестра FirmwareVersion не найден или недоступен" $firmwareVersion = $null Write-Host "Версия встроенного ПО: недоступна" }
# 13. FirmwareReleaseDate # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name FirmwareReleaseDate -ErrorAction Stop $firmwareReleaseDate = $regValue.FirmwareReleaseDate if ([string]::IsNullOrEmpty($firmwareReleaseDate)) { Write-Warning "FirmwareReleaseDate is empty" $firmwareReleaseDate = "Unknown" } Write-Host "Дата выпуска встроенного ПО: $firmwareReleaseDate" } catch { Write-Warning "FirmwareReleaseDate раздел реестра не найден или недоступен" $firmwareReleaseDate = $null Write-Host "Дата выпуска встроенного ПО: недоступно" }
# 14. OSArchitecture # Версия PS: Все | Администратор: Нет | Требования к системе: нет try { $osArchitecture = $env:PROCESSOR_ARCHITECTURE if ([string]::IsNullOrEmpty($osArchitecture)) { # Попробуйте резервный реестр $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OSArchitecture -ErrorAction Stop $osArchitecture = $regValue.OSArchitecture } if ([string]::IsNullOrEmpty($osArchitecture)) { Write-Warning "Не удалось определить OSArchitecture" $osArchitecture = "Unknown" } Write-Host "Архитектура ОС: $osArchitecture" } catch { Write-Warning "Ошибка при получении OSArchitecture: $_" $osArchitecture = "Unknown" Write-Host "Архитектура ОС: $osArchitecture" }
# 15. CanAttemptUpdateAfter (FILETIME) # Версия PS: Все | Администратор: может потребоваться | Требования к системе: нет try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name CanAttemptUpdateAfter -ErrorAction Stop $canAttemptUpdateAfter = $regValue.CanAttemptUpdateAfter # Преобразование FILETIME в UTC DateTime — реестр хранит как REG_BINARY (байт[]) или REG_QWORD (long) if ($null -ne $canAttemptUpdateAfter) { try { if ($canAttemptUpdateAfter -is [byte[]]) { $fileTime = [BitConverter]::ToInt64($canAttemptUpdateAfter, 0) $canAttemptUpdateAfter = [DateTime]::FromFileTime($fileTime). ToUniversalTime() } elseif ($canAttemptUpdateAfter -is [long]) { $canAttemptUpdateAfter = [DateTime]::FromFileTime($canAttemptUpdateAfter). ToUniversalTime() } } catch { Write-Warning "Не удалось преобразовать CanAttemptUpdateAfter FILETIME в DateTime" } } Write-Host "Можно выполнить попытку обновления после: $canAttemptUpdateAfter" } catch { Write-Warning "CanAttemptUpdateAfter раздел реестра не найден или недоступен" $canAttemptUpdateAfter = $null Write-Host "Может предпринять попытку обновления после: недоступно" }
# Журналы событий: системный журнал (10 значений: 16–25)
# 16-25. Запросы журнала событий # Идентификаторы событий: # 1801 — обновление инициировано, требуется перезагрузка No 1808 — обновление успешно завершено # 1795 — возвращена ошибка встроенного ПО (код ошибки записи) No 1796 — ошибка, зарегистрированная с кодом ошибки (код записи) # 1800 — требуется перезагрузка (не ошибка — обновление будет продолжаться после перезагрузки) No 1802 — известное обновление с блокировкой встроенного ПО (запись номера KI_<> из SkipReason) # 1803 — не найдено соответствующее обновление KEK (oem должен предоставить KEK с подписью PK) # PS Version: 3.0+ | Администратор: может потребоваться для системного журнала | Требования к системе: нет try { # Запрос всех соответствующих идентификаторов событий безопасной загрузки $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 1795ErrorCode = $null $event 1796Count = 0 $event 1796ErrorCode = $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: 0" Write-Host "Число событий 1808: 0" } else { # 16. LatestEventId $latestEvent = $events | Sort-Object TimeCreated -убывание | Select-Object -Первый 1 if ($null -eq $latestEvent) { Write-Warning "Не удалось определить последнее событие" $latestEventId = $null Write-Host "Последнее событие: недоступно" } else { $latestEventId = $latestEvent.Id Write-Host "Последнее событие: $latestEventId" }
# 17. BucketID — извлечено из события 1801/1808 if ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { if ($latestEvent.Message -match 'BucketId:\s*(.+)') { $bucketId = $matches[1]. Trim() Write-Host "Идентификатор контейнера: $bucketId" } else { Write-Warning "BucketId не найден в сообщении о событии" $bucketId = $null Write-Host "Идентификатор контейнера: не найден в событии" } } else { Write-Warning "Последнее событие или сообщение имеет значение NULL, не удается извлечь BucketId" $bucketId = $null Write-Host "Идентификатор контейнера: недоступно" }
# 18. Достоверность — извлечено из события 1801/1808 if ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { if ($latestEvent.Message -match 'BucketConfidenceLevel:\s*(.+)') { $confidence = $matches[1]. Trim() Write-Host "Доверие: $confidence" } else { Write-Warning "Уровень достоверности не найден в сообщении о событии" $confidence = $null Write-Host "Достоверность: не найдена в событии" } } else { Write-Warning "Последнее событие или сообщение имеет значение NULL, не удается извлечь достоверность" $confidence = $null Write-Host "Достоверность: недоступно" }
No 18b. SkipReason — извлечение KI_<числовых> из SkipReason в том же событии, что и BucketId # Записывает идентификаторы известных проблем, которые отображаются вместе с BucketId/Confidence (а не только событие 1802). $skipReasonKnownIssue = $null if ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { if ($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 1795ErrorCode = $null $event 1796Count = 0 $event 1796ErrorCode = $null $event 1800Count = 0 $rebootPending = $false $event 1802Count = 0 $knownIssueId = $null $event 1803Count = 0 $missingKEK = $false # проверка только для событий ошибок, если обновление не завершено # Пропустить анализ ошибок, если: 1808 является последним событием или UEFICA2023Status имеет значение "Обновлено" $updateComplete = ($latestEventId -eq 1808) -or ($uefica 2023Status -eq "Updated") if (-not $updateComplete) { Write-Host "Обновление не завершено - проверка на наличие ошибок..." -ForegroundColor Yellow # 21. Событие1795 — ошибка встроенного ПО (код ошибки записи) $event 1795Array = @($events | Where-Object {$_. Id -eq 1795}) $event 1795Count = $event 1795Array.Count if ($event 1795Count -gt 0) { $latestEvent 1795 = $event 1795Array | Sort-Object TimeCreated -убывание | Select-Object -Первый 1 if ($latestEvent 1795.Message -match '(?:error|code|status)[:\s]*(?:0x)?( [0-9A-Fa-f]{8}|[0-9A-Fa-f]+)') { $event 1795ErrorCode = $matches[1] } Write-Host "Число событий 1795 (ошибка встроенного ПО): $event 1795Count" $(if ($event 1795ErrorCode) { "Code: $event 1795ErrorCode" }) } # 22. Событие1796 — зарегистрированный код ошибки (код ошибки записи) $event 1796Array = @($events | Where-Object {$_. Id -eq 1796}) $event 1796Count = $event 1796Array.Count if ($event 1796Count -gt 0) { $latestEvent 1796 = $event 1796Array | Sort-Object TimeCreated -убывание | Select-Object -Первый 1 if ($latestEvent 1796.Message -match '(?:error|code|status)[:\s]*(?:0x)?( [0-9A-Fa-f]{8}|[0-9A-Fa-f]+)') { $event 1796ErrorCode = $matches[1] } Write-Host "Event 1796 (error logged) Count: $event 1796Count" $(if ($event 1796ErrorCode) { "Code: $event 1796ErrorCode" }) } # 23. Событие1800 — требуется перезагрузка (не ошибка — обновление будет продолжаться после перезагрузки) $event 1800Array = @($events | Where-Object {$_. Id -eq 1800}) $event 1800Count = $event 1800Array.Count $rebootPending = $event 1800Count -gt 0 if ($rebootPending) { Write-Host "Событие 1800 (ожидание перезагрузки): обновление продолжится после перезагрузки" -ForegroundColor Cyan } # 24. Событие1802 — известная проблема с встроенным ПО (запись KI_<номер> из SkipReason) $event 1802Array = @($events | Where-Object {$_. Id -eq 1802}) $event 1802Count = $event 1802Array.Count if ($event 1802Count -gt 0) { $latestEvent 1802 = $event 1802Array | Sort-Object TimeCreated -убывание | Select-Object -Первый 1 if ($latestEvent 1802.Message -match 'SkipReason:\s*(KI_\d+)")) { $knownIssueId = $matches[1] } Write-Host "Число событий 1802 (известная проблема с встроенным ПО): $event 1802Count" $(if ($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 if ($missingKEK) { Write-Host "Событие 1803 (отсутствует KEK): ИЗГОТОВИТЕЛЬ должен предоставить KEK со знаком PK" -ForegroundColor Yellow } } else { Write-Host "Обновление завершено (событие 1808 или Status=Updated) - пропуск анализа ошибок" -ForegroundColor Green } } } catch { Write-Warning "Ошибка получения журналов событий. Могут потребоваться права администратора: $_" $latestEventId = $null $bucketId = $null $confidence = $null $skipReasonKnownIssue = $null $event 1801Count = 0 $event 1808Count = 0 $event 1795Count = 0 $event 1795ErrorCode = $null $event 1796Count = 0 $event 1796ErrorCode = $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: 0" Write-Host "Число событий 1808: 0" }
# Запросы WMI/CIM (5 значений)
# 26. OSVersion # ВЕРСИЯ PS: 3.0+ (используйте Get-WmiObject для версии 2.0) | Администратор: Нет | Требования к системе: нет try { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop if ($null -eq $osInfo -or [string]::IsNullOrEmpty($osInfo.Version)) { Write-Warning "Не удалось получить версию ОС" $osVersion = "Unknown" } else { $osVersion = $osInfo.Version } Write-Host "Версия ОС: $osVersion" } catch { # CIM может завершиться сбоем в некоторых средах — используйте резервный вариант $osVersion = [System.Environment]::OSVersion.Version.ToString() if ([string]::IsNullOrEmpty($osVersion)) { $osVersion = "Unknown" } Write-Host "Версия ОС: $osVersion" }
# 27. LastBootTime # ВЕРСИЯ PS: 3.0+ (используйте Get-WmiObject для версии 2.0) | Администратор: Нет | Требования к системе: нет try { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop if ($null -eq $osInfo -or $null -eq $osInfo.LastBootUpTime) { Write-Warning "Не удалось получить время последней загрузки" $lastBootTime = $null Write-Host "Время последней загрузки: недоступно" } else { $lastBootTime = $osInfo.LastBootUpTime Write-Host "Время последней загрузки: $lastBootTime" } } catch { # CIM может завершиться сбоем в некоторых средах — используйте резервный вариант try { $lastBootTime = (Get-Process -Id 0 -ErrorAction SilentlyContinue). Starttime } catch { $lastBootTime = $null } if ($lastBootTime) { Write-Host "Время последней загрузки: $lastBootTime" } else { Write-Host "Время последней загрузки: недоступно" } }
# 28. BaseBoardManufacturer # ВЕРСИЯ PS: 3.0+ (используйте Get-WmiObject для версии 2.0) | Администратор: Нет | Требования к системе: нет try { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop if ($null -eq $baseBoard -or [string]::IsNullOrEmpty($baseBoard.Manufacturer)) { Write-Warning "Не удалось получить изготовителя основной платы" $baseBoardManufacturer = "Unknown" } else { $baseBoardManufacturer = $baseBoard.Manufacturer } Write-Host "Изготовитель основной платы: $baseBoardManufacturer" } catch { # CIM может завершиться ошибкой — сведения о основной панели являются дополнительными $baseBoardManufacturer = "Unknown" Write-Host "Изготовитель основной платы: $baseBoardManufacturer" }
# 29. BaseBoardProduct # ВЕРСИЯ PS: 3.0+ (используйте Get-WmiObject для версии 2.0) | Администратор: Нет | Требования к системе: нет try { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop if ($null -eq $baseBoard -or [string]::IsNullOrEmpty($baseBoard.Product)) { Write-Warning "Не удалось получить продукт основной платы" $baseBoardProduct = "Unknown" } else { $baseBoardProduct = $baseBoard.Product } Write-Host "Продукт основной платы: $baseBoardProduct" } catch { # CIM может завершиться ошибкой — сведения о основной панели являются дополнительными $baseBoardProduct = "Unknown" Write-Host "Основной продукт: $baseBoardProduct" }
# 30. SecureBootTaskEnabled # Версия PS: Все | Администратор: Нет | Требования к системе: запланированная задача существует # Проверяет, включена ли запланированная задача безопасной загрузки и обновления $secureBootTaskEnabled = $null $secureBootTaskStatus = "Unknown" try { $taskOutput = schtasks.exe /Query /TN "\Microsoft\Windows\PI\Secure-Boot-Update" /FO CSV 2>&1 if ($LASTEXITCODE -eq 0) { $taskData = $taskOutput | ConvertFrom-Csv if ($taskData) { $secureBootTaskStatus = $taskData.Status $secureBootTaskEnabled = ($taskData.Status -eq 'Ready' -or $taskData.Status -eq 'Running') } } else { $secureBootTaskStatus = NotFound $secureBootTaskEnabled = $false } if ($secureBootTaskEnabled -eq $false) { Write-Host "Задача обновления SecureBoot: $secureBootTaskStatus (Включено: $secureBootTaskEnabled)" -ForegroundColor Yellow } else { Write-Host "Задача обновления SecureBoot: $secureBootTaskStatus (Включено: $secureBootTaskEnabled)" - ForegroundColor Green } } catch { $secureBootTaskStatus = "Error" $secureBootTaskEnabled = $false Write-Host "Задача обновления SecureBoot: проверка ошибок - $_" -ForegroundColor Red }
# 31. Состояние ключа WinCS (F33E0C8E002 — обновление сертификата безопасной загрузки) # Версия PS: Все | Администратор: Да (для запроса) | Требования к системе: WinCsFlags.exe $wincsKeyApplied = $null $wincsKeyStatus = "Unknown" try { # Проверка распространенных расположений для WinCsFlags.exe $wincsFlagsPath = $null $possiblePaths = @( "$env:SystemRoot\System32\WinCsFlags.exe", "$env:SystemRoot\SysWOW64\WinCsFlags.exe" ) foreach ($p в $possiblePaths) { if (Test-Path $p) { $wincsFlagsPath = $p; break } } if ($wincsFlagsPath) { # Определенный ключ запроса — требуются права администратора $queryOutput = & $wincsFlagsPath /query --key F33E0C8E002 2>&1 $queryOutputStr = $queryOutput -join "'n" if ($LASTEXITCODE -eq 0) { # Проверьте, применен ли ключ (найдите "Активная конфигурация" или аналогичный индикатор) если ($queryOutputStr -match "Active Configuration.*:*enabled" -или $queryOutputStr -match "Configuration.*applied") { $wincsKeyApplied = $true $wincsKeyStatus = "Применено" Write-Host "F33E0C8E002 ключа WinCS: применено" -ForegroundColor Green } elseif ($queryOutputStr -match "not found|Без конфигурации") { $wincsKeyApplied = $false $wincsKeyStatus = NotApplied Write-Host "F33E0C8E002 ключа WinCS: не применяется" -ForegroundColor Yellow } else { # Key exists — проверка выходные данные для состояния $wincsKeyApplied = $true $wincsKeyStatus = "Применено" Write-Host "F33E0C8E002 ключей WinCS: применено" -ForegroundColor Green } } else { # Проверьте наличие определенных сообщений об ошибках if ($queryOutputStr -match "Access denied|administrator") { $wincsKeyStatus = AccessDenied Write-Host "F33E0C8E002 ключа WinCS: доступ запрещен (запуск от имени администратора)" -ForegroundColor DarkGray } elseif ($queryOutputStr -match "not found|Без конфигурации") { $wincsKeyApplied = $false $wincsKeyStatus = NotApplied Write-Host "F33E0C8E002 ключа WinCS: не применяется" -ForegroundColor Yellow } else { $wincsKeyStatus = "QueryFailed" Write-Host "F33E0C8E002 ключа WinCS: сбой запроса" - ForegroundColor Red } } } else { $wincsKeyStatus = "WinCsFlagsNotFound" Write-Host "F33E0C8E002 ключа WinCS: WinCsFlags.exe не найден" -ForegroundColor Gray } } catch { $wincsKeyStatus = "Ошибка" Write-Host "WinCS Key F33E0C8E002: error checking - $_" -ForegroundColor Red }
# ============================================================================= # Исправление обнаружения — вывод состояния & код выхода # =============================================================================
# Создание объекта состояния из всех собранных данных инвентаризации $status = [упорядочено]@{ UEFICA2023Status = $uefica 2023Status UEFICA2023Error = $uefica 2023Error UEFICA2023ErrorEvent = $uefica 2023ErrorEvent AvailableUpdates = if ($null -ne $availableUpdates) { $availableUpdatesHex } else { $null } AvailableUpdatesPolicy = if ($null -ne $availableUpdatesPolicy) { $availableUpdatesPolicyHex } else { $null } Имя узла = $hostname CollectionTime = if ($collectionTime -is [datetime]) { $collectionTime.ToString("o") } else { "$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") } else { "$canAttemptUpdateAfter" } LatestEventId = $latestEventId BucketId = $bucketId Достоверность = $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 = $rebootPending # True, если присутствует событие 1800 Event1802Count = $event 1802Count # Известная проблема с встроенным ПО KnownIssueId = $knownIssueId # KI_<число> из SkipReason Event1803Count = $event 1803Count # Отсутствует обновление KEK MissingKEK = $missingKEK # OEM должен предоставить KEK с подписью PK OSVersion = $osVersion LastBootTime = if ($lastBootTime -is [datetime]) { $lastBootTime.ToString("o") } else { "$lastBootTime" } BaseBoardManufacturer = $baseBoardManufacturer BaseBoardProduct = $baseBoardProduct SecureBootTaskEnabled = $secureBootTaskEnabled SecureBootTaskStatus = $secureBootTaskStatus WinCSKeyApplied = $wincsKeyApplied # True, если применяется F33E0C8E002 ключ WinCSKeyStatus = $wincsKeyStatus # Applied, NotApplied, WinCsFlagsNotFound и т. д. }
# Вывод состояния — для агрегирования данных $jsonOutput = $status | ConvertTo-Json -Compress
# Если outputPath указан, сохраните в файл; в противном случае выходные данные в stdout if (-not [string]::IsNullOrEmpty($OutputPath)) { # Проверка OutputPath — пропустите, если он выглядит как запрос на помощь или содержит недопустимые символы. если ($OutputPath -match '^[/\-]' -или $OutputPath -match '[<>:"|? *]') { Write-Host "Указан недопустимый выходной путь, вывод в stdout" -ForegroundColor Yellow Write-Output $jsonOutput if ($secureBootEnabled -and $uefica 2023Status -eq "Updated") { exit 0 } else { exit 1 } } # Убедитесь, что выходная папка существует if (-not (Test-Path $OutputPath)) { try { New-Item -ItemType Directory -Path $OutputPath -Force | Out-NULL } catch { Write-Warning "Не удалось создать выходную папку: $OutputPath - $_" } } # Сохранить в HOSTNAME_latest.json $outputFile = Join-Path $OutputPath "$($hostname)_latest.json" try { $jsonOutput | Out-File -FilePath $outputFile -Encoding UTF8 -Force Write-Host "JSON сохранен в: $outputFile" -ForegroundColor Green } catch { Write-Warning "Не удалось записать в файл: $outputFile - $_" # Вернуться к stdout Write-Output $jsonOutput } } else { # Исходное поведение — вывод в stdout Write-Output $jsonOutput }
# Код выхода: "Обновлено" — это значение успешного выполнения в сборнике схем. if ($secureBootEnabled -and $uefica 2023Status -eq "Updated") { Exit 0 # Без проблемы } else { выход 1 # С проблемой }