Skip to content

Instantly share code, notes, and snippets.

@SMSAgentSoftware
Last active December 24, 2025 02:25
Show Gist options
  • Select an option

  • Save SMSAgentSoftware/95f31d9d6c4fd3b406b1ce254a85388c to your computer and use it in GitHub Desktop.

Select an option

Save SMSAgentSoftware/95f31d9d6c4fd3b406b1ce254a85388c to your computer and use it in GitHub Desktop.
PowerShell script to check whether the SecureBoot databases contain updated certificates
#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
@ngjrjeff
Copy link

ngjrjeff commented Nov 4, 2025

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

image

@ElectricFighter
Copy link

ElectricFighter commented Dec 18, 2025

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
image

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?

@SMSAgentSoftware
Copy link
Author

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
image

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment