Detect-SecureBootCA2023.ps1
|
<#PSScriptInfo .VERSION 2.0 .GUID 7f4c2c9b-1d3e-4b8a-9f7c-92c4e7d1a6b2 .AUTHOR Mert Efe Kanlikilic .COMPANYNAME mertefekanlikilic.com .COPYRIGHT (c) 2026 Mert Efe Kanlikilic .TAGS SecureBoot UEFI Intune Compliance Detection PCA2023 .LICENSEURI https://github.com/mertefekanlikilic .PROJECTURI https://github.com/mertefekanlikilic .DESCRIPTION Secure Boot CA 2023 certificate update detection script for Intune compliance. #> <# .SYNOPSIS Secure Boot CA 2023 certificate update detection script. .NOTES Author : Mert Efe Kanlikilic -- mertefekanlikilic.com Version : 2.0 Platform: Windows 11 | Secure Boot enabled devices Run as : SYSTEM, 64-bit PowerShell Date : May 2026 Registry paths: HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing UEFICA2023Status : NotStarted | InProgress | Updated WindowsUEFICA2023Capable : 0 = insufficient, 1 = in progress, 2 = complete HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot AvailableUpdates : 0x5944 = opted in RemediationTimestamp : First remediation date (written by remediation script) UEFI DB thumbprint: Microsoft Windows Production PCA 2023 Thumbprint: 45 66 52 45 2A 1B 5A 25 67 48 7F 81 B1 3F 1F E2 #> $LOG_PATH = "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\SecureBoot-Detection.log" $EVENTLOG_SOURCE = "SecureBootCA2023" $EVENTLOG_LOG = "Application" $SERVICING_KEY = "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\Servicing" $SECUREBOOT_KEY = "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot" $FAILED_DAYS = 7 $PCA2023_THUMBPRINT = "45 66 52 45 2A 1B 5A 25 67 48 7F 81 B1 3F 1F E2" function Write-Log { param([string]$Message, [ValidateSet("INFO","WARN","ERROR")]$Level = "INFO") $ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss" try { Add-Content -Path $LOG_PATH -Value "[$ts][$Level] $Message" -Encoding UTF8 } catch { } } function Write-EventEntry { param([string]$Message, [int]$EventId, [string]$EntryType = "Information") try { if (-not [System.Diagnostics.EventLog]::SourceExists($EVENTLOG_SOURCE)) { New-EventLog -LogName $EVENTLOG_LOG -Source $EVENTLOG_SOURCE -ErrorAction Stop } Write-EventLog -LogName $EVENTLOG_LOG -Source $EVENTLOG_SOURCE ` -EventId $EventId -EntryType $EntryType -Message $Message } catch { Write-Log "Event log write failed: $($_.Exception.Message)" -Level WARN } } function Write-ComplianceResult { param([string]$State, [string]$Message, [int]$ExitCode) $output = "${State}: ${Message}" $eventMap = @{ "Compliant" = @{ Id = 1000; Type = "Information" } "PendingRemediation" = @{ Id = 1001; Type = "Warning" } "PendingRestart" = @{ Id = 1002; Type = "Warning" } "Failed" = @{ Id = 1003; Type = "Error" } "ManualReview" = @{ Id = 1004; Type = "Error" } "NotApplicable" = @{ Id = 1005; Type = "Information" } } Write-Host $output Write-Log $output if ($eventMap.ContainsKey($State)) { Write-EventEntry -Message $output -EventId $eventMap[$State].Id ` -EntryType $eventMap[$State].Type } Stop-Transcript -ErrorAction SilentlyContinue exit $ExitCode } function Get-RegistryState { $result = [PSCustomObject]@{ UEFICA2023Status = "Unknown" WindowsUEFICA2023Capable = -1 AvailableUpdates = -1 RemediationTimestamp = $null Layer1Pass = $false State = "Unknown" Reason = "" } try { $serv = Get-ItemProperty -Path $SERVICING_KEY -ErrorAction Stop $result.UEFICA2023Status = $serv.UEFICA2023Status $result.WindowsUEFICA2023Capable = [int]($serv.WindowsUEFICA2023Capable) } catch { $result.State = "PendingRemediation" $result.Reason = "Servicing key not found -- update has never started" return $result } try { $sb = Get-ItemProperty -Path $SECUREBOOT_KEY -ErrorAction SilentlyContinue if ($sb.AvailableUpdates) { $result.AvailableUpdates = $sb.AvailableUpdates } if ($sb.RemediationTimestamp) { $result.RemediationTimestamp = [datetime]$sb.RemediationTimestamp } } catch { } switch ($result.UEFICA2023Status) { "Updated" { if ($result.WindowsUEFICA2023Capable -eq 2) { $result.Layer1Pass = $true $result.State = "Layer1Pass" $result.Reason = "Registry complete (Status=Updated, Capable=2) -- UEFI DB verification pending" } else { $result.State = "ManualReview" $result.Reason = "Status=Updated but Capable=$($result.WindowsUEFICA2023Capable) -- inconsistent state" } } "InProgress" { if ($result.RemediationTimestamp) { $daysSince = ((Get-Date) - $result.RemediationTimestamp).TotalDays if ($daysSince -ge $FAILED_DAYS) { $result.State = "Failed" $result.Reason = "InProgress for $([math]::Round($daysSince,1)) days -- remediation appears stuck" } else { $result.State = "PendingRestart" $result.Reason = "Update in progress -- restart pending ($([math]::Round($daysSince,1)) days)" } } else { $result.State = "PendingRestart" $result.Reason = "Update in progress (InProgress) -- restart pending" } } "NotStarted" { $result.State = "PendingRemediation" $result.Reason = "Update has not started (NotStarted)" } default { $result.State = "PendingRemediation" $result.Reason = "Unknown status: $($result.UEFICA2023Status)" } } return $result } function Test-UEFIDatabase { try { $dbVar = Get-SecureBootUEFI -Name "db" -ErrorAction Stop if ($null -eq $dbVar -or $null -eq $dbVar.Bytes) { Write-Log "UEFI db variable empty or unreadable" -Level WARN return "Unavailable" } $targetBytes = ($PCA2023_THUMBPRINT -split " ") | ForEach-Object { [Convert]::ToByte($_, 16) } $dbBytes = $dbVar.Bytes $dbLen = $dbBytes.Length $tLen = $targetBytes.Length $found = $false for ($i = 0; $i -le ($dbLen - $tLen); $i++) { $match = $true for ($j = 0; $j -lt $tLen; $j++) { if ($dbBytes[$i + $j] -ne $targetBytes[$j]) { $match = $false; break } } if ($match) { $found = $true; break } } if ($found) { Write-Log "UEFI DB: PCA2023 thumbprint verified" return "Verified" } else { Write-Log "UEFI DB: PCA2023 thumbprint NOT FOUND -- ManualReview required" -Level WARN return "Missing" } } catch { Write-Log "Get-SecureBootUEFI error: $($_.Exception.Message) -- skipping Layer 2" -Level WARN return "Unavailable" } } # --- Main --- try { Start-Transcript -Path $LOG_PATH -Append -Force | Out-Null } catch { } Write-Log "Detection v2.0 starting -- $env:COMPUTERNAME" if (-not [Environment]::Is64BitProcess) { Write-Log "32-bit PowerShell detected" -Level ERROR Write-ComplianceResult -State "Failed" -Message "64-bit PowerShell required -- script ran in 32-bit process" -ExitCode 1 } $sbEnabled = $false try { $sbEnabled = Confirm-SecureBootUEFI -ErrorAction Stop } catch { $sbEnabled = $false } Write-Log "Secure Boot enabled: $sbEnabled" if (-not $sbEnabled) { Write-ComplianceResult -State "NotApplicable" -Message "Secure Boot disabled or BIOS mode -- out of scope" -ExitCode 0 } $regState = Get-RegistryState Write-Log "Layer 1 -- State: $($regState.State) | $($regState.Reason)" Write-Log " UEFICA2023Status : $($regState.UEFICA2023Status)" Write-Log " WindowsUEFICA2023Capable: $($regState.WindowsUEFICA2023Capable)" Write-Log " AvailableUpdates : $($regState.AvailableUpdates)" switch ($regState.State) { "PendingRemediation" { Write-ComplianceResult -State "PendingRemediation" -Message $regState.Reason -ExitCode 1 } "PendingRestart" { Write-ComplianceResult -State "PendingRestart" -Message $regState.Reason -ExitCode 1 } "Failed" { Write-ComplianceResult -State "Failed" -Message $regState.Reason -ExitCode 1 } "ManualReview" { Write-ComplianceResult -State "ManualReview" -Message $regState.Reason -ExitCode 1 } } Write-Log "Layer 2 starting -- UEFI DB thumbprint verification" $uefResult = Test-UEFIDatabase switch ($uefResult) { "Verified" { Write-ComplianceResult -State "Compliant" ` -Message "Layer 1 + Layer 2 passed -- PCA2023 verified in UEFI DB" -ExitCode 0 } "Missing" { Write-ComplianceResult -State "ManualReview" ` -Message "Registry shows Updated but PCA2023 thumbprint absent from UEFI DB -- firmware investigation required" -ExitCode 1 } "Unavailable" { Write-Log "Layer 2 unavailable -- falling back to Layer 1 result" -Level WARN Write-ComplianceResult -State "Compliant" ` -Message "Layer 1 passed -- Layer 2 unavailable (UEFI read not supported), registry-based confirmation only" -ExitCode 0 } } |