원래 게시 날짜: 2025년 11월 17일
KB ID: 5072718
중요 샘플 스크립트가 포함된 이 문서는 사용 중지되었습니다. 2026년 5월 12일 이후에 릴리스된 Windows 업데이트부터 샘플 스크립트는 디바이스의 %systemroot%\SecureBoot\ExampleRolloutScripts 폴더에 있습니다.
샘플 보안 부팅 인벤토리 데이터 수집 스크립트
이 샘플 스크립트를 복사하여 붙여넣고 사용자 환경에 필요한 대로 수정합니다. 샘플 보안 부팅 인벤토리 데이터 수집 스크립트입니다.
<# . 시놉시스 플릿 전체 모니터링을 위해 보안 부팅 인증서 업데이트 상태 검색합니다.
. 설명 이 검색 스크립트는 보안 부팅 상태, 인증서 업데이트 레지스트리 값을 수집합니다. 및 디바이스 정보입니다. 모니터링 및 보고를 위해 JSON 문자열을 출력합니다.
Intune 수정, GPO 기반 컬렉션 및 기타 관리 도구와 호환됩니다.수정 스크립트가 필요하지 않습니다. 이는 모니터링 전용입니다.
종료 0 = "문제 없음"(인증서 업데이트됨) Exit 1 = "With issue"(인증서가 업데이트되지 않음 - 정보만 해당)
. PARAMETER OutputPath 선택적. JSON 파일이 저장될 폴더의 경로입니다.제공된 경우 이 폴더에 HOSTNAME_latest.json 저장합니다.제공되지 않으면 JSON을 stdout(원래 동작)으로 출력합니다.
. 예제 # stdout에 출력(Intune/SCCM 검색) .\Detect-SecureBootCertUpdateStatus.ps1
. 예제 # 네트워크 공유에 저장(GPO 배포) .\Detect-SecureBootCertUpdateStatus.ps1 -OutputPath "\\server\SecureBootLogs$"
. 노트 https://aka.ms/securebootplaybook 당 레지스트리 경로: HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing
소프트웨어는 어떠한 종류의 보증도 없이 "있는 그대로" 제공됩니다. 가맹점 보증을 포함하지만 이에 국한되지 않는 암시적 특정 목적 및 비침해에 대한 적합성. 어떠한 경우에도 작성자 또는 저작권 소유자는 모든 청구, 손해 또는 기타에 대해 책임을 져야 합니다. 계약, 불법 행위 또는 기타 행위에서 발생하는 책임, 소프트웨어 또는 사용 또는 기타 거래와 관련하여 소프트웨어.#> param( [Parameter(Mandatory = $false)] [string]$OutputPath )
# 다운로드 URL: https://aka.ms/getsecureboot -> "배포 및 모니터링 샘플" # 참고: 이 스크립트는 엔드포인트에서 실행하여 보안 부팅 상태 데이터를 수집합니다.
# 1. 호스트 # PS 버전: 모두 | 관리: 아니요 | 시스템 요구 사항: 없음 try { $hostname = $env:COMPUTERNAME if ([string]::IsNullOrEmpty($hostname)) { Write-Warning "호스트 이름을 확인할 수 없습니다." $hostname = "알 수 없음" } Write-Host "호스트 이름: $hostname" } catch { Write-Warning "호스트 이름을 검색하는 동안 오류가 발생했습니다. $_" $hostname = "오류" Write-Host "호스트 이름: $hostname" }
# 2. CollectionTime # PS 버전: 모두 | 관리: 아니요 | 시스템 요구 사항: 없음 try { $collectionTime = Get-Date if ($null -eq $collectionTime) { Write-Warning "현재 날짜/시간을 검색할 수 없음" $collectionTime = "알 수 없음" } Write-Host "컬렉션 시간: $collectionTime" } catch { Write-Warning "날짜/시간 검색 오류: $_" $collectionTime = "오류" Write-Host "컬렉션 시간: $collectionTime" }
# 레지스트리: 보안 부팅 기본 키(3개 값)
# 3. SecureBootEnabled # PS 버전: 3.0 이상 | 관리: 필요할 수 있음 | 시스템 요구 사항: UEFI/보안 부팅 가능 시스템 try { $secureBootEnabled = Confirm-SecureBootUEFI -ErrorAction 중지 Write-Host "보안 부팅 사용: $secureBootEnabled" } catch { Write-Warning "cmdlet을 통해 보안 부팅 상태 확인할 수 없음: $_" # 레지스트리 대체 시도 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 "높은 신뢰도 옵트아웃: 설정되지 않음" }
# 4b. MicrosoftUpdateManagedOptIn # PS 버전: 모두 | 관리: 필요할 수 있음 | 시스템 요구 사항: 없음 try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name MicrosoftUpdateManagedOptIn -ErrorAction Stop $microsoftUpdateManagedOptIn = $regValue.MicrosoftUpdateManagedOptIn Write-Host "Microsoft 업데이트 관리되는 옵트인: $microsoftUpdateManagedOptIn" } catch { # MicrosoftUpdateManagedOptIn은 선택 사항이며 대부분의 시스템에는 없습니다. $microsoftUpdateManagedOptIn = $null Write-Host "Microsoft 업데이트 관리 옵트인: 설정 안 함" }
# 5. AvailableUpdates # PS 버전: 모두 | 관리: 필요할 수 있음 | 시스템 요구 사항: 없음 try { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdates -ErrorAction Stop $availableUpdates = $regValue.AvailableUpdates if ($null -ne $availableUpdates) { # 16진수 형식으로 변환 $availableUpdatesHex = "0x{0:X}" -f $availableUpdates Write-Host "사용 가능한 업데이트: $availableUpdatesHex" } else { Write-Host "사용 가능한 업데이트: 사용할 수 없음" } } catch { Write-Warning "AvailableUpdates 레지스트리 키를 찾을 수 없거나 액세스할 수 없음" $availableUpdates = $null Write-Host "사용 가능한 업데이트: 사용할 수 없음" }
# 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) { # 16진수 형식으로 변환 $availableUpdatesPolicyHex = "0x{0:X}" -f $availableUpdatesPolicy Write-Host "사용 가능한 업데이트 정책: $availableUpdatesPolicyHex" } else { Write-Host "사용 가능한 업데이트 정책: 설정 안 함" } } catch { # AvailableUpdatesPolicy는 선택 사항이며 GPO가 적용된 경우에만 설정됩니다. $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 상태: $uefica 2023Status" } catch { Write-Warning "Windows UEFI CA 2023 상태 레지스트리 키를 찾을 수 없거나 액세스할 수 없음" $uefica 2023Status = $null Write-Host "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 = "알 수 없음" } 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 = "알 수 없음" } 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가 비어 있음" $oemModelNumber = "알 수 없음" } 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이 비어 있음" $firmwareVersion = "알 수 없음" } 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가 비어 있음" $firmwareReleaseDate = "알 수 없음" } 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 = "알 수 없음" } Write-Host "OS 아키텍처: $osArchitecture" } catch { Write-Warning "OSArchitecture를 검색하는 동안 오류가 발생했습니다. $_" $osArchitecture = "알 수 없음" Write-Host "OS 아키텍처: $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. 이벤트 로그 쿼리 # 이벤트 ID: # 1801 - 업데이트 시작됨, 다시 부팅 필요 # 1808 - 업데이트가 성공적으로 완료됨 # 1795 - 펌웨어가 오류를 반환했습니다(캡처 오류 코드) # 1796 - 오류 코드로 기록된 오류(캡처 코드) # 1800 - 다시 부팅 필요(오류가 아님 - 다시 부팅 후 업데이트가 진행됨) # 1802 - 알려진 펌웨어 문제 차단 업데이트(SkipReason에서 KI_<번호> 캡처) # 1803 - 일치하는 KEK 업데이트를 찾을 수 없음(OEM은 PK 서명된 KEK를 제공해야 합니다.) # PS 버전: 3.0 이상 | 관리: 시스템 로그에 필요할 수 있음 | 시스템 요구 사항: 없음 try { # 모든 관련 보안 부팅 이벤트 ID 쿼리 $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 "최신 이벤트 ID: 사용할 수 없음" Write-Host "버킷 ID: 사용할 수 없음" Write-Host "신뢰도: 사용할 수 없음" Write-Host "이벤트 1801 개수: 0" Write-Host "이벤트 1808 개수: 0" } else { # 16. LatestEventId $latestEvent = $events | Sort-Object TimeCreated -Descending | Select-Object -First 1 if ($null -eq $latestEvent) { Write-Warning "최신 이벤트를 확인할 수 없음" $latestEventId = $null Write-Host "최신 이벤트 ID: 사용할 수 없음" } else { $latestEventId = $latestEvent.Id Write-Host "최신 이벤트 ID: $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 "버킷 ID: $bucketId" } else { Write-Warning "이벤트 메시지에서 BucketId를 찾을 수 없음" $bucketId = $null Write-Host "버킷 ID: 이벤트에서 찾을 수 없음" } } else { Write-Warning "최신 이벤트 또는 메시지가 null이면 BucketId를 추출할 수 없습니다." $bucketId = $null Write-Host "버킷 ID: 사용할 수 없음" }
# 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 "신뢰도: 사용할 수 없음" }
# 18b. SkipReason - BucketId와 동일한 이벤트에서 SkipReason에서 KI_<번호> 추출 # 이 캡처는 BucketId/Confidence와 함께 표시되는 알려진 문제 ID를 캡처합니다(이벤트 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 노란색 } }
# 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) -또는 ($uefica 2023Status -eq "Updated") if (-not $updateComplete) { Write-Host "업데이트가 완료되지 않음 - 오류 이벤트 확인 중..." -ForegroundColor 노란색 # 21. Event1795 - 펌웨어 오류(캡처 오류 코드) $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 -Descending | Select-Object -First 1 if ($latestEvent 1795.Message -match '(?:error|code|상태)[:\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. Event1796 - 기록된 오류 코드(캡처 오류 코드) $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 -Descending | Select-Object -First 1 if ($latestEvent 1796.Message -match '(?:error|code|상태)[:\s]*(?:0x)? ([0-9A-Fa-f]{8}|[0-9A-Fa-f]+)') { $event 1796ErrorCode = $matches[1] } Write-Host "이벤트 1796(오류 기록) 개수: $event 1796Count" $(if ($event 1796ErrorCode) { "Code: $event 1796ErrorCode" }) } # 23. Event1800 - 다시 부팅 필요(오류가 아님 - 다시 부팅 후 업데이트가 진행됨) $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. Event1802 - 알려진 펌웨어 문제(SkipReason에서 KI_<번호> 캡처) $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 -Descending | Select-Object -First 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은 PK 서명된 KEK를 제공해야 합니다). $event 1803Array = @($events | Where-Object {$_. Id -eq 1803}) $event 1803Count = $event 1803Array.Count $missingKEK = $event 1803Count -gt 0 if ($missingKEK) { Write-Host "이벤트 1803(누락된 KEK): OEM은 PK 서명 KEK를 제공해야 합니다." -ForegroundColor Yellow } } else { Write-Host "업데이트 완료(이벤트 1808 또는 상태=업데이트됨) - 오류 분석 건너뛰기" -ForegroundColor 녹색 } } } 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 "최신 이벤트 ID: 오류" Write-Host "버킷 ID: 오류" Write-Host "신뢰도: 오류" Write-Host "이벤트 1801 개수: 0" Write-Host "이벤트 1808 개수: 0" }
# WMI/CIM 쿼리(5개 값)
# 26. OSVersion # PS 버전: 3.0 이상(2.0에 Get-WmiObject 사용) | 관리: 아니요 | 시스템 요구 사항: 없음 try { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction 중지 if ($null -eq $osInfo -또는 [string]::IsNullOrEmpty($osInfo.Version)) { Write-Warning "OS 버전을 검색할 수 없음" $osVersion = "알 수 없음" } else { $osVersion = $osInfo.Version } Write-Host "OS 버전: $osVersion" } catch { # CIM이 일부 환경에서 실패할 수 있음 - 대체 사용 $osVersion = [System.Environment]::OSVersion.Version.ToString() if ([string]::IsNullOrEmpty($osVersion)) { $osVersion = "Unknown" } Write-Host "OS 버전: $osVersion" }
# 27. LastBootTime # PS 버전: 3.0 이상(2.0에 Get-WmiObject 사용) | 관리: 아니요 | 시스템 요구 사항: 없음 try { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction 중지 if ($null -eq $osInfo -또는 $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 "Last Boot Time: $lastBootTime" } else { Write-Host "Last Boot Time: Not Available" } }
# 28. BaseBoardManufacturer # PS 버전: 3.0 이상(2.0에 Get-WmiObject 사용) | 관리: 아니요 | 시스템 요구 사항: 없음 try { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction 중지 if ($null -eq $baseBoard -또는 [string]::IsNullOrEmpty($baseBoard.Manufacturer)) { Write-Warning "베이스보드 제조업체를 검색할 수 없음" $baseBoardManufacturer = "알 수 없음" } else { $baseBoardManufacturer = $baseBoard.Manufacturer } Write-Host "베이스보드 제조업체: $baseBoardManufacturer" } catch { # CIM이 실패할 수 있음 - 베이스보드 정보는 추가 정보입니다. $baseBoardManufacturer = "알 수 없음" Write-Host "베이스보드 제조업체: $baseBoardManufacturer" }
# 29. BaseBoardProduct # PS 버전: 3.0 이상(2.0에 Get-WmiObject 사용) | 관리: 아니요 | 시스템 요구 사항: 없음 try { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction 중지 if ($null -eq $baseBoard -또는 [string]::IsNullOrEmpty($baseBoard.Product)) { Write-Warning "베이스보드 제품을 검색할 수 없음" $baseBoardProduct = "알 수 없음" } else { $baseBoardProduct = $baseBoard.Product } Write-Host "베이스보드 제품: $baseBoardProduct" } catch { # CIM이 실패할 수 있음 - 베이스보드 정보는 추가 정보입니다. $baseBoardProduct = "알 수 없음" Write-Host "베이스보드 제품: $baseBoardProduct" }
# 30. SecureBootTaskEnabled # PS 버전: 모두 | 관리: 아니요 | 시스템 요구 사항: 예약된 작업이 있음 # Secure-Boot-Update 예약된 작업이 사용하도록 설정되어 있는지 확인합니다. $secureBootTaskEnabled = $null $secureBootTaskStatus = "알 수 없음" 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' -또는 $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 = "오류" $secureBootTaskEnabled = $false Write-Host "SecureBoot 업데이트 작업: 오류 검사 - $_" -ForegroundColor Red }
# 31. WinCS 키 상태(F33E0C8E002 - 보안 부팅 인증서 업데이트) # PS 버전: 모두 | 관리: 예(쿼리용) | 시스템 요구 사항: WinCsFlags.exe $wincsKeyApplied = $null $wincsKeyStatus = "알 수 없음" try { # WinCsFlags.exe 대한 공통 위치 확인 $wincsFlagsPath = $null $possiblePaths = @( "$env:SystemRoot\System32\WinCsFlags.exe", "$env:SystemRoot\SysWOW64\WinCsFlags.exe" ) foreach($possiblePaths $p) { if (Test-Path $p) { $wincsFlagsPath = $p; break } } if ($wincsFlagsPath) { # 쿼리 특정 키 - 관리자 권한이 필요합니다. $queryOutput = & $wincsFlagsPath /query --key F33E0C8E002 2>&1 $queryOutputStr = $queryOutput -join "'n" if ($LASTEXITCODE -eq 0) { # 키가 적용되었는지 확인합니다("활성 구성" 또는 유사한 표시기를 찾습니다.) if ($queryOutputStr -match "Active Configuration.*:.*enabled" -or $queryOutputStr -match "Configuration.*applied") { $wincsKeyApplied = $true $wincsKeyStatus = "적용됨" Write-Host "WinCS 키 F33E0C8E002: 적용됨" -ForegroundColor 녹색 } elseif($queryOutputStr -match "찾을 수 없음|구성 없음") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "WinCS 키 F33E0C8E002: 적용되지 않음" -ForegroundColor 노란색 } else { # 키가 있음 - 상태에 대한 출력 검사 $wincsKeyApplied = $true $wincsKeyStatus = "적용됨" Write-Host "WinCS 키 F33E0C8E002: 적용됨" -ForegroundColor 녹색 } } else { # 특정 오류 메시지 확인 if ($queryOutputStr -match "Access denied|administrator") { $wincsKeyStatus = "AccessDenied" Write-Host "WinCS 키 F33E0C8E002: 액세스 거부(관리자 권한으로 실행)" -ForegroundColor DarkGray } elseif($queryOutputStr -match "찾을 수 없음|구성 없음") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "WinCS 키 F33E0C8E002: 적용되지 않음" -ForegroundColor 노란색 } else { $wincsKeyStatus = "QueryFailed" Write-Host "WinCS 키 F33E0C8E002: 쿼리 실패" -ForegroundColor Red } } } else { $wincsKeyStatus = "WinCsFlagsNotFound" Write-Host "WinCS 키 F33E0C8E002: WinCsFlags.exe 찾을 수 없음" -ForegroundColor Gray } } catch { $wincsKeyStatus = "오류" Write-Host "WinCS 키 F33E0C8E002: 오류 검사 - $_" -ForegroundColor Red }
# ============================================================================= # 수정 검색 - 상태 출력 & 종료 코드 # =============================================================================
# 수집된 모든 인벤토리 데이터에서 상태 개체 빌드 $상태 = [ordered]@{ 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 = bucketId 이벤트의 SkipReason에서 $skipReasonKnownIssue # KI_<번호> Event1801Count = $event 1801Count Event1808Count = $event 1808Count # 캡처된 세부 정보가 있는 오류 이벤트 Event1795Count = $event 1795Count # Firmware 반환 오류 Event1795ErrorCode = $event 1795ErrorCode # 펌웨어의 오류 코드 Event1796Count = $event 1796Count # 오류 코드가 기록됨 Event1796ErrorCode = $event 1796ErrorCode # 캡처된 오류 코드 Event1800Count = $event 1800Count # 다시 부팅 필요(오류가 아님) RebootPending = $rebootPending # True이면 이벤트 1800이 존재합니다. Event1802Count = $event 1802Count # 알려진 펌웨어 문제 KnownIssueId = skipReason의 $knownIssueId # KI_<번호> Event1803Count = $event 1803Count # 누락된 KEK 업데이트 MissingKEK = $missingKEK # OEM은 PK 서명 KEK를 제공해야 합니다. 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 = $상태 | ConvertTo-Json -Compress
# OutputPath가 제공된 경우 파일에 저장합니다. 그렇지 않으면 stdout에 출력됩니다. if (-not [string]::IsNullOrEmpty($OutputPath)) { # OutputPath 유효성 검사 - 도움말 요청처럼 보이거나 잘못된 문자가 있는 경우 건너뜁니다. if ($OutputPath -match '^[/\-]' -또는 $OutputPath -match '[<>:"|? *]') { Write-Host "잘못된 OutputPath가 지정되어 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 디렉터리 -경로 $OutputPath -Force | Out-Null } catch { Write-Warning "출력 폴더를 만들 수 없습니다. $OutputPath - $_" } } # HOSTNAME_latest.json 저장 $outputFile = "$($hostname)_latest.json"Join-Path $OutputPath 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 # without issue } else { exit 1 # With issue }
|
날짜 변경 |
설명 변경 |
|
2026년 5월 13일 |
|
|
2026년 2월 24일 |
|
|
2026년 2월 22일 |
|
|
2026년 2월 13일 |
|