Copie y pegue este script de ejemplo y modifíquelo según sea necesario para su entorno:
<# . SINOOPSIS Detecta el estado de actualización del certificado de arranque seguro para la supervisión de toda la flota.
.DESCRIPTION Este script de detección recopila el estado de arranque seguro, los valores del registro de actualización de certificados, y la información del dispositivo. Genera una cadena JSON para supervisar e informar.
Compatible with Intune Remediations, GPO-based collection, and other management tools. No es necesario ningún script de corrección: solo se trata de supervisión.
Exit 0 = "Without issue" (certificates updated) Salida 1 = "Con problema" (certificados no actualizados, solo informativos)
.PARAMETER OutputPath Opcional. Ruta de acceso a una carpeta donde se guardará el archivo JSON.Si se proporciona, guarda HOSTNAME_latest.json en esta carpeta.Si no se proporciona, genera JSON en stdout (comportamiento original).
.EXAMPLE # Salida a stdout (detección de Intune/SCCM) .\Detect-SecureBootCertUpdateStatus.ps1
.EXAMPLE # Guardar en recurso compartido de red (implementación de GPO) .\Detect-SecureBootCertUpdateStatus.ps1 -OutputPath "\\servidor\SecureBootLogs$"
.NOTES Rutas de registro por 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 IMPLÍCITA, INCLUIDAS, ENTRE OTRAS, LAS GARANTÍAS DE COMERCIABILIDAD, IDONEIDAD PARA UN PROPÓSITO PARTICULAR Y AUSENCIA DE INFRACCIONES. EN NINGÚN CASO LA LOS AUTORES Y LOS TITULARES DE LOS DERECHOS DE PROPIEDAD INTELECTUAL SERÁN RESPONSABLES DE CUALQUIER RECLAMACIÓN, DAÑOS U OTROS RESPONSABILIDAD CIVIL, YA SEA POR ACCIÓN CONTRACTUAL, RESPONSABILIDAD EXTRACONTRACTUAL U OTRA CAUSA, QUE DERIVE DE, FUERA O EN RELACIÓN CON EL SOFTWARE, EL USO U OTROS PROCEDIMIENTOS DE LA SOFTWARE.#> parámetro( [Parameter(Mandatory = $false)] [cadena]$OutputPath )
# Download URL: https://aka.ms/getsecureboot -> "Deployment and Monitoring Samples" # Nota: este script se ejecuta en puntos de conexión para recopilar datos de estado de arranque seguro.
# 1. HostName # Versión PS: Todo | Administración: No | Requisitos del sistema: Ninguno prueba { $hostname = $env:NOMBREEQUIPO if ([string]::IsNullOrEmpty($hostname)) { Write-Warning "No se pudo determinar el nombre de host" $hostname = "Desconocido" } Write-Host "Nombre de host: $hostname" } captura { Write-Warning "Error al recuperar el nombre de host: $_" $hostname = "Error" Write-Host "Nombre de host: $hostname" }
# 2. CollectionTime # Versión PS: Todo | Administración: No | Requisitos del sistema: Ninguno prueba { $collectionTime = Get-Date if ($null -eq $collectionTime) { Write-Warning "No se pudo recuperar la fecha y hora actuales" $collectionTime = "Desconocido" } Write-Host "Hora de recogida: $collectionTime" } captura { Write-Warning "Error al recuperar la fecha y hora: $_" $collectionTime = "Error" Write-Host "Hora de recogida: $collectionTime" }
# Registry: Secure Boot Main Key (3 values)
# 3. SecureBootEnabled # Versión PS: 3.0+ | Administración: puede ser necesario | Requisitos del sistema: sistema compatible con UEFI/Arranque seguro prueba { $secureBootEnabled = Confirm-SecureBootUEFI -ErrorAction Stop Write-Host "Arranque seguro habilitado: $secureBootEnabled" } captura { Write-Warning "No se puede determinar el estado de arranque seguro a través del cmdlet: $_" # Prueba la reserva del Registro prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -Name UEFISecureBootEnabled -ErrorAction Stop $secureBootEnabled = [bool]$regValue.UEFISecureBootEnabled Write-Host "Arranque seguro habilitado: $secureBootEnabled" } captura { Write-Warning "No se puede determinar el estado de arranque seguro a través del Registro. Es posible que el sistema no admita UEFI/arranque seguro". $secureBootEnabled = $null Write-Host "Arranque seguro habilitado: no disponible" } }
# 4. HighConfidenceOptOut # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name HighConfidenceOptOut -ErrorAction Stop $highConfidenceOptOut = $regValue.HighConfidenceOptOut Write-Host "Rechazo de confianza alta: $highConfidenceOptOut" } captura { # HighConfidenceOptOut es opcional, no está presente en la mayoría de los sistemas $highConfidenceOptOut = $null Write-Host "Rechazo de confianza alta: no establecido" }
# 4b. MicrosoftUpdateManagedOptIn # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name MicrosoftUpdateManagedOptIn -ErrorAction Stop $microsoftUpdateManagedOptIn = $regValue.MicrosoftUpdateManagedOptIn Write-Host "Suscripción administrada de Microsoft Update: $microsoftUpdateManagedOptIn" } captura { # MicrosoftUpdateManagedOptIn es opcional, no está presente en la mayoría de los sistemas $microsoftUpdateManagedOptIn = $null Write-Host "Participar administrado de Microsoft Update: no establecido" }
# 5. AvailableUpdates # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdates -ErrorAction Stop $availableUpdates = $regValue.AvailableUpdates if ($null -ne $availableUpdates) { # Convertir a formato hexadecimal $availableUpdatesHex = "0x{0:X}" -f $availableUpdates Write-Host "Novedades disponible: $availableUpdatesHex" } else { Write-Host "Novedades disponible: no disponible" } } captura { Write-Warning "No se encuentra o no se puede acceder a la clave del registro AvailableUpdates" $availableUpdates = $null Write-Host "Novedades disponible: no disponible" }
# 5b. AvailableUpdatesPolicy (GPO-controlled persistent value) # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" -Name AvailableUpdatesPolicy -ErrorAction Stop $availableUpdatesPolicy = $regValue.AvailableUpdatesPolicy if ($null -ne $availableUpdatesPolicy) { # Convertir a formato hexadecimal $availableUpdatesPolicyHex = "0x{0:X}" -f $availableUpdatesPolicy Write-Host "Directiva de Novedades disponible: $availableUpdatesPolicyHex" } else { Write-Host "Directiva de Novedades disponible: no establecida" } } captura { # AvailableUpdatesPolicy es opcional: solo se establece cuando se aplica gpo $availableUpdatesPolicy = $null Write-Host "Directiva de Novedades disponible: no establecida" }
# Registry: Servicing Key (3 values)
# 6. UEFICA2023Status # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Status -ErrorAction Stop $uefica 2023Status = $regValue.UEFICA2023Status Write-Host "Estado de Windows UEFI CA 2023: $uefica 2023Status" } captura { Write-Warning "Clave de registro de estado de Windows UEFI CA 2023 no encontrada o inaccesible" $uefica 2023Status = $null Write-Host "Estado de Windows UEFI CA 2023: no disponible" }
# 7. UEFICA2023Error # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023Error -ErrorAction Stop $uefica 2023Error = $regValue.UEFICA2023Error Write-Host "Error de UEFI CA 2023: $uefica 2023Error" } captura { # UEFICA2023Error solo existe si se produjo un error - la ausencia es buena $uefica 2023Error = $null Write-Host "Error UEFI CA 2023: Ninguno" }
# 8. UEFICA2023ErrorEvent # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" -Name UEFICA2023ErrorEvent -ErrorAction Stop $uefica 2023ErrorEvent = $regValue.UEFICA2023ErrorEvent Write-Host "Evento de error de UEFI CA 2023: $uefica 2023ErrorEvent" } captura { $uefica 2023ErrorEvent = $null Write-Host "Evento de error de UEFI CA 2023: no disponible" }
# Registry: Device Attributes (7 values: 9-15)
# 9. OEMManufacturerName # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $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 está vacío" $oemManufacturerName = "Desconocido" } Write-Host "Nombre del fabricante OEM: $oemManufacturerName" } captura { Write-Warning "No se encuentra o no se puede acceder a la clave del Registro OEMManufacturerName" $oemManufacturerName = $null Write-Host "Nombre del fabricante OEM: no disponible" }
# 10. OEMModelSystemFamily # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $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 está vacío" $oemModelSystemFamily = "Desconocido" } Write-Host "Familia de modelos OEM: $oemModelSystemFamily" } captura { Write-Warning "NO se encuentra o no se puede acceder a la clave del registro OEMModelSystemFamily" $oemModelSystemFamily = $null Write-Host "Familia de modelos oem: no disponible" }
# 11. OEMModelNumber # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $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 está vacío" $oemModelNumber = "Desconocido" } Write-Host "Número de modelo oem: $oemModelNumber" } captura { Write-Warning "NO se encuentra o no se puede acceder a la clave del registro OEMModelNumber" $oemModelNumber = $null Write-Host "Número de modelo OEM: no disponible" }
# 12. FirmwareVersion # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $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 está vacío" $firmwareVersion = "Desconocido" } Write-Host "Versión de firmware: $firmwareVersion" } captura { Write-Warning "No se encuentra o no se puede acceder a la clave del Registro firmwareVersion" $firmwareVersion = $null Write-Host "Versión de firmware: no disponible" }
# 13. FirmwareReleaseDate # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $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 está vacío" $firmwareReleaseDate = "Desconocido" } Write-Host "Fecha de lanzamiento del firmware: $firmwareReleaseDate" } captura { Write-Warning "No se encuentra o no se puede acceder a la clave del Registro FirmwareReleaseDate" $firmwareReleaseDate = $null Write-Host "Fecha de lanzamiento del firmware: no disponible" }
# 14. OSArchitecture # Versión PS: Todo | Administración: No | Requisitos del sistema: Ninguno prueba { $osArchitecture = $env:PROCESSOR_ARCHITECTURE if ([string]::IsNullOrEmpty($osArchitecture)) { # Prueba la reserva del Registro $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name OSArchitecture -ErrorAction Stop $osArchitecture = $regValue.OSArchitecture } if ([string]::IsNullOrEmpty($osArchitecture)) { Write-Warning "No se pudo determinar la OSArchitecture" $osArchitecture = "Desconocido" } Write-Host "Arquitectura del SO: $osArchitecture" } captura { Write-Warning "Error al recuperar OSArchitecture: $_" $osArchitecture = "Desconocido" Write-Host "Arquitectura del SO: $osArchitecture" }
# 15. CanAttemptUpdateAfter (FILETIME) # Versión PS: Todo | Administración: puede ser necesario | Requisitos del sistema: Ninguno prueba { $regValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing\DeviceAttributes" -Name CanAttemptUpdateAfter -ErrorAction Stop $canAttemptUpdateAfter = $regValue.CanAttemptUpdateAfter # Convertir FILETIME a UTC DateTime: el Registro almacena como REG_BINARY (byte[]) o REG_QWORD (long) if ($null -ne $canAttemptUpdateAfter) { prueba { if ($canAttemptUpdateAfter -is [byte[]]) { $fileTime = [BitConverter]::ToInt64($canAttemptUpdateAfter, 0) $canAttemptUpdateAfter = [DateTime]::FromFileTime($fileTime). ToUniversalTime() } elseif ($canAttemptUpdateAfter -is [long]) { $canAttemptUpdateAfter = [DateTime]::FromFileTime($canAttemptUpdateAfter). ToUniversalTime() } } captura { Write-Warning "No se pudo convertir CanAttemptUpdateAfter FILETIME a DateTime" } } Write-Host "Puede intentar actualizar después de: $canAttemptUpdateAfter" } captura { Write-Warning "CanAttemptUpdateAfter clave de registro no encontrada o inaccesible" $canAttemptUpdateAfter = $null Write-Host "Puede intentar actualizar después de: no disponible" }
# Event Logs: System Log (10 values: 16-25)
# 16-25. Event Log queries # Id. de evento: n.º 1801: actualización iniciada, es necesario reiniciar N.º 1808: la actualización se completó correctamente N.º 1795: error devuelto por firmware (código de error de captura) N.º 1796: error registrado con código de error (código de captura) N.º 1800- Es necesario reiniciar (NO es un error: la actualización se realizará después del reinicio) n.º 1802: actualización bloqueada del problema de firmware conocido (captura KI_<número> de SkipReason) n.º 1803: no se encuentra la actualización de KEK coincidente (el OEM debe proporcionar la KEK firmada por LA PK) # Versión PS: 3.0+ | Administración: puede ser necesario para el registro del sistema | Requisitos del sistema: Ninguno prueba { # Consulta todos los identificadores de evento de arranque seguro relevantes $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 "No se encontraron eventos de arranque seguro en el registro del sistema" $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. de evento más reciente: no disponible" Write-Host "Id. del cubo: no disponible" Write-Host "Confianza: no disponible" Write-Host "Recuento de eventos 1801: 0" Write-Host "Recuento del evento 1808: 0" } else { # 16. LatestEventId $latestEvent = $events | Sort-Object TimeCreated -Descending | Select-Object - Primeros 1 if ($null -eq $latestEvent) { Write-Warning "No se pudo determinar el evento más reciente" $latestEventId = $null Write-Host "Id. de evento más reciente: no disponible" } else { $latestEventId = $latestEvent.Id Write-Host "Id. de evento más reciente: $latestEventId" }
# 17. BucketID - Extracted from Event 1801/1808 if ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { if ($latestEvent.Message -match 'BucketId:\s*(.+)') { $bucketId = $matches[1]. Trim() Write-Host "Id. del cubo: $bucketId" } else { Write-Warning "BucketId no se encuentra en el mensaje de evento" $bucketId = $null Write-Host "Id. del cubo: no se encuentra en el evento" } } else { Write-Warning "El último evento o mensaje es nulo, no se puede extraer BucketId" $bucketId = $null Write-Host "Id. del cubo: no disponible" }
# 18. Confidence - Extracted from Event 1801/1808 if ($null -ne $latestEvent -and $null -ne $latestEvent.Message) { if ($latestEvent.Message -match 'BucketConfidenceLevel:\s*(.+)') { $confidence = $matches[1]. Trim() Write-Host "Confianza: $confidence" } else { Write-Warning "Nivel de confianza no se encuentra en el mensaje de evento" $confidence = $null Write-Host "Confianza: No se encuentra en el evento" } } else { Write-Warning "El último evento o mensaje es nulo, no se puede extraer la confianza" $confidence = $null Write-Host "Confidence: Not Available" }
# 18b. SkipReason - Extract KI_<number> from SkipReason in the same event as BucketId # Esto captura los identificadores de problema conocido que aparecen junto a BucketId/Confidence (no solo el evento 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 "Problema conocido de SkipReason: $skipReasonKnownIssue" -ForegroundColor Yellow } }
# 19. Event1801Count $event 1801Array = @($events | Where-Object {$_. Id -eq 1801}) $event 1801Count = $event 1801Array.Count Write-Host "Recuento de eventos 1801: $event 1801Count"
# 20. Event1808Count $event 1808Array = @($events | Where-Object {$_. Id -eq 1808}) $event 1808Count = $event 1808Array.Count Write-Host "Recuento de eventos 1808: $event 1808Count" # Inicializar variables de evento de error $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 # Comprobar solo si hay eventos de error si la actualización NO está completa # Omite el análisis de errores si: 1808 es el evento más reciente O UEFICA2023Status es "Actualizado" $updateComplete = ($latestEventId -eq 1808) -o ($uefica 2023Status -eq "Updated") if (-not $updateComplete) { Write-Host "Update not complete - checking for error events..." -ForegroundColor Yellow # 21. Event1795: error de firmware (código de error de captura) $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 - Primeros 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 "Recuento de eventos 1795 (error de firmware): $event 1795Count" $(if ($event 1795ErrorCode) { "Código: $event 1795ErrorCode" }) } # 22. Event1796: código de error registrado (código de error de captura) $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 - Primeros 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 "Recuento de eventos 1796 (error registrado): $event 1796Count" $(if ($event 1796ErrorCode) { "Código: $event 1796ErrorCode" }) } # 23. Event1800: es necesario reiniciar (NO es un error: la actualización se realizará después del reinicio) $event 1800Array = @($events | Where-Object {$_. Id -eq 1800}) $event 1800Count = $event 1800Array.Count $rebootPending = $event 1800Count -gt 0 if ($rebootPending) { Write-Host "Evento 1800 (reinicio pendiente): la actualización continuará después del reinicio" -ForegroundColor Cyan } # 24. Event1802: problema de firmware conocido (capturar KI_<número> de 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 -Descending | Select-Object - Primeros 1 if ($latestEvent 1802.Message -match 'SkipReason:\s*(KI_\d+)') { $knownIssueId = $matches[1] } Write-Host "Recuento de eventos 1802 (problema de firmware conocido): $event 1802Count" $(if ($knownIssueId) { "KI: $knownIssueId" }) } # 25. Event1803: falta la actualización de KEK (el OEM debe suministrar la KEK firmada por PK) $event 1803Array = @($events | Where-Object {$_. Id -eq 1803}) $event 1803Count = $event 1803Array.Count $missingKEK = $event 1803Count -gt 0 if ($missingKEK) { Write-Host "Evento 1803 (FALTA KEK): el OEM debe suministrar la KEK firmada de PK" -ForegroundColor Yellow } } else { Write-Host "Update complete (Evento 1808 o Status=Updated): omitir el análisis de errores" -ForegroundColor Green } } } captura { Write-Warning "Error al recuperar registros de eventos. Puede requerir privilegios de administrador: $_" $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. de evento más reciente: error" Write-Host "Bucket ID: Error" Write-Host "Confianza: Error" Write-Host "Recuento de eventos 1801: 0" Write-Host "Recuento de eventos 1808: 0" }
# WMI/CIM Queries (5 values)
# 26. OSVersion # Versión PS: 3.0+ (use Get-WmiObject para 2.0) | Administración: No | Requisitos del sistema: Ninguno prueba { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop if ($null -eq $osInfo -o [string]::IsNullOrEmpty($osInfo.Version)) { Write-Warning "No se pudo recuperar la versión del SO" $osVersion = "Desconocido" } else { $osVersion = $osInfo.Version } Write-Host "Versión del SO: $osVersion" } captura { # CIM puede presentar errores en algunos entornos: usar fallback $osVersion = [System.Environment]::OSVersion.Version.ToString() if ([string]::IsNullOrEmpty($osVersion)) { $osVersion = "Unknown" } Write-Host "Versión del SO: $osVersion" }
# 27. LastBootTime # Versión PS: 3.0+ (use Get-WmiObject para 2.0) | Administración: No | Requisitos del sistema: Ninguno prueba { $osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop if ($null -eq $osInfo -o $null -eq $osInfo.LastBootUpTime) { Write-Warning "No se pudo recuperar el último tiempo de arranque" $lastBootTime = $null Write-Host "Hora del último arranque: no disponible" } else { $lastBootTime = $osInfo.LastBootUpTime Write-Host "Hora del último arranque: $lastBootTime" } } captura { # CIM puede presentar errores en algunos entornos: usar fallback prueba { $lastBootTime = (Get-Process -Id 0 -ErrorAction SilentlyContinue). StartTime } captura { $lastBootTime = $null } if ($lastBootTime) { Write-Host "Last Boot Time: $lastBootTime" } else { Write-Host "Last Boot Time: Not Available" } }
# 28. BaseBoardManufacturer # Versión PS: 3.0+ (use Get-WmiObject para 2.0) | Administración: No | Requisitos del sistema: Ninguno prueba { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop if ($null -eq $baseBoard -or [string]::IsNullOrEmpty($baseBoard.Manufacturer)) { Write-Warning "No se pudo recuperar el fabricante de la base" $baseBoardManufacturer = "Desconocido" } else { $baseBoardManufacturer = $baseBoard.Manufacturer } Write-Host "Fabricante de placa base: $baseBoardManufacturer" } captura { # Cim puede fallar: la información de la placa base es complementaria $baseBoardManufacturer = "Desconocido" Write-Host "Fabricante de placa base: $baseBoardManufacturer" }
# 29. BaseBoardProduct # Versión PS: 3.0+ (use Get-WmiObject para 2.0) | Administración: No | Requisitos del sistema: Ninguno prueba { $baseBoard = Get-CimInstance Win32_BaseBoard -ErrorAction Stop if ($null -eq $baseBoard -o [string]::IsNullOrEmpty($baseBoard.Product)) { Write-Warning "No se pudo recuperar el producto de la base" $baseBoardProduct = "Desconocido" } else { $baseBoardProduct = $baseBoard.Product } Write-Host "Producto de placa base: $baseBoardProduct" } captura { # Cim puede fallar: la información de la placa base es complementaria $baseBoardProduct = "Desconocido" Write-Host "Producto de placa base: $baseBoardProduct" }
# 30. SecureBootTaskEnabled # Versión PS: Todo | Administración: No | Requisitos del sistema: existe una tarea programada # Comprueba si la tarea programada de actualización de arranque seguro está habilitada $secureBootTaskEnabled = $null $secureBootTaskStatus = "Desconocido" prueba { $taskOutput = schtasks.exe /Query /TN "\Microsoft\Windows\PI\Secure-Boot-Update" /FO CSV 2>&1 if ($LASTEXITCODE -eq 0) { $taskData = $taskOutput | ConvertirFrom-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 "Tarea de actualización secureBoot: $secureBootTaskStatus (habilitado: $secureBootTaskEnabled)" -ForegroundColor Yellow } else { Write-Host "Tarea de actualización secureBoot: $secureBootTaskStatus (Habilitado: $secureBootTaskEnabled)" -ForegroundColor green } } captura { $secureBootTaskStatus = "Error" $secureBootTaskEnabled = $false Write-Host "Tarea de actualización secureBoot: comprobación de errores - $_" -ForegroundColor Red }
# 31. WinCS Key Status (F33E0C8E002 - Secure Boot Certificate Update) # Versión PS: Todo | Administración: Sí (para la consulta) | Requisitos del sistema: WinCsFlags.exe $wincsKeyApplied = $null $wincsKeyStatus = "Desconocido" prueba { # Comprobar si hay WinCsFlags.exe en las ubicaciones comunes $wincsFlagsPath = $null $possiblePaths = @( "$env:SystemRoot\System32\WinCsFlags.exe", "$env:SystemRoot\SysWOW64\WinCsFlags.exe" ) foreach ($p en $possiblePaths) { if ($p Ruta de prueba) { $wincsFlagsPath = $p; break } } if ($wincsFlagsPath) { # Clave específica de consulta: requiere derechos de administrador $queryOutput = & $wincsFlagsPath /query --key F33E0C8E002 2>&1 $queryOutputStr = $queryOutput -join "'n" if ($LASTEXITCODE -eq 0) { # Comprueba si se aplica la clave (busca "Configuración activa" o un indicador similar) if ($queryOutputStr -match "Active Configuration.*:.*enabled" -or $queryOutputStr -match "Configuration.*applied") { $wincsKeyApplied = $true $wincsKeyStatus = "Aplicado" Write-Host "F33E0C8E002 clave de WinCS: applied" -ForegroundColor green } elseif ($queryOutputStr -match "no se encuentra|Sin configuración") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "F33E0C8E002 de teclas WinCS: no aplicado" -ForegroundColor Yellow } else { Existe la tecla # - comprobar el estado de la salida $wincsKeyApplied = $true $wincsKeyStatus = "Aplicado" Write-Host "F33E0C8E002 de teclas WinCS: applied" -ForegroundColor green } } else { # Comprobar si hay mensajes de error específicos if ($queryOutputStr -match "Acceso denegado|administrador") { $wincsKeyStatus = "Acceso denegado" Write-Host "WinCS Key F33E0C8E002: Acceso denegado (ejecutar como administrador)" -ForegroundColor DarkGray } elseif ($queryOutputStr -match "no se encuentra|Sin configuración") { $wincsKeyApplied = $false $wincsKeyStatus = "NotApplied" Write-Host "WinCS Key F33E0C8E002: Not Applied" -ForegroundColor Yellow } else { $wincsKeyStatus = "QueryFailed" Write-Host "WinCS Key F33E0C8E002: Error en la consulta" -ForegroundColor Red } } } else { $wincsKeyStatus = "WinCsFlagsNotFound" Write-Host "F33E0C8E002 clave de WinCS: no se WinCsFlags.exe encuentra" -ForegroundColor Gray } } captura { $wincsKeyStatus = "Error" Write-Host "WinCS Key F33E0C8E002: Comprobación de errores - $_" -ForegroundColor Red }
# ============================================================================= # Detección de corrección: salida de estado & código de salida # =============================================================================
# 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 } else { $null } AvailableUpdatesPolicy = if ($null -ne $availableUpdatesPolicy) { $availableUpdatesPolicyHex } else { $null } Nombre de host = $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 = $confidence SkipReasonKnownIssue = $skipReasonKnownIssue # KI_<número> de SkipReason en el evento BucketId Event1801Count = $event 1801Count Event1808Count = $event 1808Count # Eventos de error con detalles capturados Event1795Count = $event 1795Count # Error devuelto por el firmware Event1795ErrorCode = $event 1795ErrorCode # Código de error del firmware Event1796Count = $event 1796Count # Código de error registrado Event1796ErrorCode = $event 1796ErrorCode # Código de error capturado Event1800Count = $event 1800Count # Es necesario reiniciar (NO es un error) RebootPending = $rebootPending # True if Event 1800 present Event1802Count = $event 1802Contar # Problema de firmware conocido KnownIssueId = $knownIssueId # KI_<número> de SkipReason Event1803Count = $event 1803Count # Falta la actualización de KEK MissingKEK = $missingKEK # OEM necesita suministrar la KEK firmada por PK OSVersion = $osVersion LastBootTime = if ($lastBootTime -is [datetime]) { $lastBootTime.ToString("o") } else { "$lastBootTime" } BaseBoardManufacturer = $baseBoardManufacturer BaseBoardProduct = $baseBoardProduct SecureBootTaskEnabled = $secureBootTaskEnabled SecureBootTaskStatus = $secureBootTaskStatus WinCSKeyApplied = $wincsKeyApplied # True si se aplica F33E0C8E002 clave WinCSKeyStatus = $wincsKeyStatus # Applied, NotApplied, WinCsFlagsNotFound, etc. }
# Output the status - For data aggregation $jsonOutput = $status | ConvertTo-Json -Compress
# If OutputPath provided, save to file; otherwise output to stdout if (-not [string]::IsNullOrEmpty($OutputPath)) { # Validar OutputPath: omita si tiene el aspecto de una solicitud de ayuda o si tiene caracteres no válidos if ($OutputPath -match '^[/\-]' -or $OutputPath -match '[<>:"|? *]') { Write-Host "Salida no válida especificada, salida a stdout" -ForegroundColor Yellow Write-Output $jsonOutput if ($secureBootEnabled -and $uefica 2023Status -eq "Updated") { exit 0 } else { exit 1 } } # Asegúrate de que la carpeta de salida existe if (-not (Test-Path $OutputPath)) { prueba { New-Item directorio -ItemType -Path $OutputPath -Force | Out-Null } captura { Write-Warning "No se pudo crear la carpeta de salida: $OutputPath - $_" } } # Guardar en HOSTNAME_latest.json $outputFile = Join-Path $OutputPath "$($hostname)_latest.json" prueba { $jsonOutput | Out-File -FilePath $outputFile -Encoding UTF8 -Force Write-Host "JSON guardado en: $outputFile" -ForegroundColor Green } captura { Write-Warning "No se puede escribir en el archivo: $outputFile - $_" # Vuelve al estado anterior Write-Output $jsonOutput } } else { # Comportamiento original: salida a stdout Write-Output $jsonOutput }
# Exit code: "Updated" is the success value per the playbook if ($secureBootEnabled -and $uefica 2023Status -eq "Updated") { exit 0 # Without issue } else { salida 1 # Con problema }