Last active
November 4, 2025 07:26
-
-
Save SMSAgentSoftware/95f31d9d6c4fd3b406b1ce254a85388c to your computer and use it in GitHub Desktop.
PowerShell script to check whether the SecureBoot databases contain updated certificates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Requires -RunAsAdministrator | |
| # Function to read Secure Boot databases (db, KEK, PK, dbx) and parse entries | |
| # Thanks to Chat-GPT 5 | |
| function Read-SecureBootDatabase { | |
| [CmdletBinding()] | |
| param( | |
| [ValidateSet('db','KEK','PK','dbx')] | |
| [string]$DatabaseName = 'db', | |
| # Set to a folder path to export found X.509 certs; or $null to skip exporting | |
| [string]$ExportDir = "C:\Temp\SecureBoot\$DatabaseName" | |
| ) | |
| if ($ExportDir) { | |
| if (-not (Test-Path $ExportDir)) { New-Item -ItemType Directory -Path $ExportDir | Out-Null } | |
| } | |
| # GUIDs per UEFI spec | |
| $GUID_X509 = [guid]'a5c059a1-94e4-4aa7-87b5-ab155c2bf072' # EFI_CERT_X509_GUID | |
| $GUID_SHA256 = [guid]'c1c41626-504c-4092-aca9-41f936934328' # EFI_CERT_SHA256_GUID | |
| $GUID_PKCS7 = [guid]'4aafd29d-68df-49ee-8aa9-347d375665a7' # EFI_CERT_TYPE_PKCS7_GUID | |
| # Helpers (typed copies to avoid Guid ctor issues) | |
| function Get-GuidFromBytes([byte[]]$bytes, [int]$offset) { | |
| $buf = New-Object byte[] 16 | |
| [Buffer]::BlockCopy($bytes, $offset, $buf, 0, 16) | |
| return (New-Object System.Guid (,([byte[]]$buf))) | |
| } | |
| function Read-UInt32LE([byte[]]$bytes, [int]$offset) { | |
| [BitConverter]::ToUInt32($bytes, $offset) | |
| } | |
| function Get-Slice([byte[]]$bytes, [int]$offset, [int]$length) { | |
| $buf = New-Object byte[] $length | |
| [Buffer]::BlockCopy($bytes, $offset, $buf, 0, $length) | |
| return $buf | |
| } | |
| try { | |
| $raw = (Get-SecureBootUEFI $DatabaseName).Bytes | |
| } catch { | |
| Write-Error "Failed to read '$DatabaseName' via Get-SecureBootUEFI: $($_.Exception.Message)" | |
| return | |
| } | |
| if (-not $raw -or $raw.Length -lt 28) { | |
| Write-Warning "'$DatabaseName' is empty or too small to contain any EFI_SIGNATURE_LIST." | |
| return | |
| } | |
| $pos = 0 | |
| $results = New-Object System.Collections.Generic.List[object] | |
| $SIGLIST_HEADER_SIZE = 16 + 4 + 4 + 4 # Type(16) + ListSize(4) + HeaderSize(4) + SigSize(4) | |
| $certCount = 0 | |
| $hashCount = 0 | |
| $listIndex = 0 | |
| while ($pos -le $raw.Length - $SIGLIST_HEADER_SIZE) { | |
| $listIndex++ | |
| $sigType = Get-GuidFromBytes $raw $pos; $pos += 16 | |
| $listSize = Read-UInt32LE $raw $pos; $pos += 4 | |
| $hdrSize = Read-UInt32LE $raw $pos; $pos += 4 | |
| $sigSize = Read-UInt32LE $raw $pos; $pos += 4 | |
| $listStart = $pos - $SIGLIST_HEADER_SIZE | |
| $listEnd = $listStart + $listSize | |
| if ($listSize -lt $SIGLIST_HEADER_SIZE -or $listEnd -gt $raw.Length -or $sigSize -lt 16) { | |
| Write-Warning ("Malformed EFI_SIGNATURE_LIST at offset {0}" -f $listStart) | |
| break | |
| } | |
| # Skip SignatureHeader (commonly 0) | |
| $pos += $hdrSize | |
| # Entries: 16-byte Owner GUID + SignatureData | |
| while ($pos -le $listEnd - $sigSize) { | |
| $owner = Get-GuidFromBytes $raw $pos; $pos += 16 | |
| $dataLen = $sigSize - 16 | |
| $sigData = Get-Slice $raw $pos $dataLen; $pos += $dataLen | |
| if ($sigType -eq $GUID_X509) { | |
| try { | |
| $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 (,[byte[]]$sigData) | |
| $certCount++ | |
| $results.Add([pscustomobject]@{ | |
| Variable = $DatabaseName | |
| ListIndex = $listIndex | |
| EntryType = 'X509' | |
| Index = $certCount | |
| Subject = $cert.Subject | |
| Issuer = $cert.Issuer | |
| NotBefore = $cert.NotBefore | |
| NotAfter = $cert.NotAfter | |
| Serial = $cert.SerialNumber | |
| Thumbprint = $cert.Thumbprint | |
| OwnerGuid = $owner | |
| }) | |
| if ($ExportDir) { | |
| $outPath = Join-Path $ExportDir ("$DatabaseName-cert-{0:D3}.cer" -f $certCount) | |
| [IO.File]::WriteAllBytes($outPath, $cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)) | |
| } | |
| } catch { | |
| $results.Add([pscustomobject]@{ | |
| Variable = $DatabaseName | |
| ListIndex = $listIndex | |
| EntryType = 'X509 (unparseable)' | |
| Error = $_.Exception.Message | |
| OwnerGuid = $owner | |
| RawLen = $sigData.Length | |
| }) | |
| } | |
| } | |
| elseif ($sigType -eq $GUID_SHA256) { | |
| $hashCount++ | |
| $hex = -join ($sigData | ForEach-Object { $_.ToString('X2') }) | |
| $results.Add([pscustomobject]@{ | |
| Variable = $DatabaseName | |
| ListIndex = $listIndex | |
| EntryType = 'SHA256' | |
| Index = $hashCount | |
| Hash = $hex | |
| OwnerGuid = $owner | |
| }) | |
| } | |
| elseif ($sigType -eq $GUID_PKCS7) { | |
| $results.Add([pscustomobject]@{ | |
| Variable = $DatabaseName | |
| ListIndex = $listIndex | |
| EntryType = 'PKCS7' | |
| DataLen = $sigData.Length | |
| OwnerGuid = $owner | |
| Note = 'PKCS#7 container (not parsed here)' | |
| }) | |
| } | |
| else { | |
| $results.Add([pscustomobject]@{ | |
| Variable = $DatabaseName | |
| ListIndex = $listIndex | |
| EntryType = "Other ($sigType)" | |
| DataLen = $sigData.Length | |
| OwnerGuid = $owner | |
| }) | |
| } | |
| } | |
| # Move to the start of the next list (handles padding) | |
| $pos = $listEnd | |
| } | |
| if ($results.Count -eq 0) { | |
| Write-Warning "No entries found in '$DatabaseName' (or entries are of unsupported types)." | |
| } else { | |
| return $results | |
| } | |
| } | |
| # Confirm Secure Boot is enabled | |
| if (-not ((Confirm-SecureBootUEFI) -eq $true)) { | |
| Write-Warning "Secure Boot is not enabled on this system." | |
| exit | |
| } | |
| # Parse the db and KEK databases | |
| $db = Read-SecureBootDatabase -DatabaseName db -ExportDir $null | |
| $kek = Read-SecureBootDatabase -DatabaseName KEK -ExportDir $null | |
| # Define the new certificate names | |
| $DBWindowsUEFICertSubject = "CN=Windows UEFI CA 2023, O=Microsoft Corporation, C=US" | |
| $KEKCertSubject = "CN=Microsoft Corporation KEK 2K CA 2023, O=Microsoft Corporation, C=US" | |
| $DBCorporationUEFICertSubject = "CN=Microsoft Corporation UEFI CA 2023, O=Microsoft Corporation, C=US" | |
| $DBOptionROMUEFICertSubject = "CN=Microsoft Option ROM UEFI CA 2023, O=Microsoft Corporation, C=US" | |
| # Check if the new certificates are present in the respective databases | |
| $DBWindowsUEFICertUpdated = $db.Subject.Contains($DBWindowsUEFICertSubject) | |
| $KEKCertUpdated = $kek.Subject.Contains($KEKCertSubject) | |
| $DBCorporationUEFICertUpdated = $db.Subject.Contains($DBCorporationUEFICertSubject) | |
| $DBOptionROMUEFICertUpdated = $db.Subject.Contains($DBOptionROMUEFICertSubject) | |
| # Output the results | |
| $CertStatus = [PSCustomObject]@{ | |
| KEKCertUpdated = $KEKCertUpdated | |
| DBWindowsUEFICertUpdated = $DBWindowsUEFICertUpdated | |
| DBCorporationUEFICertUpdated = $DBCorporationUEFICertUpdated | |
| DBOptionROMUEFICertUpdated = $DBOptionROMUEFICertUpdated | |
| } | |
| $CertStatus |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks for this script to check.
anyone knows how to make DBCorporationUEFICertUpdated = true??
so far i did the below and it changed the 3 certs to true except DBCorporationUEFICertUpdated
https://support.microsoft.com/en-us/topic/registry-key-updates-for-secure-boot-windows-devices-with-it-managed-updates-a7be69c9-4634-42e1-9ca1-df06f43f360d