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 }

​​​​​​​

¿Necesita más ayuda?

¿Quiere más opciones?

Explore las ventajas de las suscripciones, examine los cursos de aprendizaje, aprenda a proteger su dispositivo y mucho más.