-
-
Save SMSAgentSoftware/95f31d9d6c4fd3b406b1ce254a85388c to your computer and use it in GitHub Desktop.
| #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 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 |
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
reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Secureboot /v AvailableUpdates /t REG_DWORD /d 0x5944 /f
Start-ScheduledTask -TaskName "\Microsoft\Windows\PI\Secure-Boot-Update"
https://support.microsoft.com/en-us/topic/registry-key-updates-for-secure-boot-windows-devices-with-it-managed-updates-a7be69c9-4634-42e1-9ca1-df06f43f360d
Based off the list of certificates on Microsoft's article, I assume the correct name of the new "Corporation" certificate is "Microsoft UEFI CA 2023" instead of "Microsoft Corporation UEFI CA 2023" as written on line 171 of the script which is responsible for the match.
If you print the db an kek variables of the script directly, you'll see that 3 new DB and 1 KEK entries have been added after the update completes successfully.
Hope this helps, maybe the script could be updated if this is correct?
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 DBCorporationUEFICertUpdatedreg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Secureboot /v AvailableUpdates /t REG_DWORD /d 0x5944 /f
Start-ScheduledTask -TaskName "\Microsoft\Windows\PI\Secure-Boot-Update"
https://support.microsoft.com/en-us/topic/registry-key-updates-for-secure-boot-windows-devices-with-it-managed-updates-a7be69c9-4634-42e1-9ca1-df06f43f360d
Based off the list of certificates on Microsoft's article, I assume the correct name of the new "Corporation" certificate is "Microsoft UEFI CA 2023" instead of "Microsoft Corporation UEFI CA 2023" as written on line 171 of the script which is responsible for the match.
If you print the db an kek variables of the script directly, you'll see that 3 new DB and 1 KEK entries have been added after the update completes successfully.
Hope this helps, maybe the script could be updated if this is correct?
Thank you for pointing this out - I have updated the script.

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