Fecha de publicación original: 17 de noviembre de 2025
KB ID: 5072718
|
Cambiar fecha |
Cambiar descripción |
|
24 de febrero de 2026 |
|
|
22 de febrero de 2026 |
|
|
13 de febrero de 2026 |
|
Script de recopilación de datos de inventario de arranque seguro de ejemplo
Copie y pegue este script de ejemplo y modifíquelo según sea necesario para su entorno: el script de recopilación de datos de inventario de arranque seguro de ejemplo.
<# . SINOOPSIS Detecta el estado de actualización del certificado de arranque seguro para la supervisión de toda la flota.
. DESCRIPCIÓN 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 con correcciones de Intune, recopilación basada en GPO y otras herramientas de administración.No es necesario ningún script de corrección: solo se trata de supervisión.
Exit 0 = "Without issue" (certificados actualizados) 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).
. EJEMPLO # Salida a stdout (detección de Intune/SCCM) .\Detect-SecureBootCertUpdateStatus.ps1
. EJEMPLO # Guardar en recurso compartido de red (implementación de GPO) .\Detect-SecureBootCertUpdateStatus.ps1 -OutputPath "\\servidor\SecureBootLogs$"
. NOTAS Rutas de registro por https://aka.ms/securebootplaybook: HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing
EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN NINGÚN TIPO DE GARANTÍA, EXPRESA O 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 )
# Dirección URL de descarga: https://aka.ms/getsecureboot -> "Ejemplos de implementación y supervisión" # Nota: este script se ejecuta en puntos de conexión para recopilar datos de estado de arranque seguro.
# 1. Nombre de host # 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" }
# Registro: clave principal de arranque seguro (3 valores)
# 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" }
n.º 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" }
n.º 5b. AvailableUpdatesPolicy (valor persistente controlado por GPO) # 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" }
# Registro: clave de mantenimiento (3 valores)
# 6. Estado de UEFICA2023 # 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. UEFICA2023ErrorEvento # 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" }
Registro n.º: Atributos del dispositivo (7 valores: 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" }
# Registros de eventos: registro del sistema (10 valores: 16-25)
# 16-25. Consultas de registro de eventos # 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: extraído del evento 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 - Extraído del evento 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" }
N.º 18b. SkipReason: extraer KI_<número> de SkipReason en el mismo evento que 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" }
# Consultas WMI/CIM (5 valores)
# 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. Estado de clave de WinCS (F33E0C8E002: actualización de certificado de arranque seguro) # 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 # =============================================================================
# Crear objeto de estado a partir de todos los datos de inventario recopilados $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. }
# Enviar el estado: para agregación de datos $jsonOutput = $status | ConvertTo-Json -Compress
# Si Se ha proporcionado OutputPath, guardar en archivo; de lo contrario, salida a 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 }
# Código de salida: "Actualizado" es el valor correcto según el libro de reproducción if ($secureBootEnabled -and $uefica 2023Status -eq "Updated") { exit 0 # Without issue } else { salida 1 # Con problema }