Detect Secure Boot Status and Drift with PowerShell · CloudEngineerHub
Detection & Remediation8 min read4 views
Detecting Secure Boot Status and Drift with PowerShell
A read-only Intune detection script that queries the firmware with Confirm-SecureBootUEFI, cross-checks the registry mirror, and reports drift honestly.
C
CloudEngineerHub Team
Published: September 14, 2026· Last Updated: September 28, 2026·8 min read
Secure Boot is one of those settings that stays correct until it suddenly is not. A firmware update resets it to defaults, a technician repurposes a board for another OS and turns it off, an image lab ships a batch with it disabled, and from then on the device silently misses every security control that sits on top of it: virtualization-based security degrades, BitLocker platform sealing weakens, and any compliance policy that requires Secure Boot starts failing without a clear reason showing up anywhere. By the time someone connects the dots, the fleet has drifted for months.
Visual Walkthrough
The engine behind every “Detect with PowerShell” runbook on this site.
Exit 1 flips the device into the remediation queue for this package.
remediate
3
Remediation executes
Fix script runs silently as SYSTEM with a 5-minute budget.
verify
4
Re-run detection
The same detection script must now exit 0 — proof, not hope.
telemetry
5
Results report
Per-device outcome lands in Reports → Remediations for trend analysis.
6
Repeat on schedule
The loop continues — drift gets caught the day it appears.
Continuous cycle
Proactive Remediations — The Detect → Fix → Verify Loop. 1. Detection script runs: Scheduled (daily/hourly): exit 0 healthy, exit 1 unhealthy — nothing more. — 2. Verdict: unhealthy: Exit 1 flips the device into the remediation queue for this package. — 3. Remediation executes: Fix script runs silently as SYSTEM with a 5-minute budget. — 4. Re-run detection: The same detection script must now exit 0 — proof, not hope. — 5. Results report: Per-device outcome lands in Reports → Remediations for trend analysis. — 6. Repeat on schedule: The loop continues — drift gets caught the day it appears.
C
CloudEngineerHub Team
Author
The CloudEngineerHub editorial team — Microsoft endpoint management and cloud engineers writing hands-on guides on Intune, Azure, Entra ID, Autopilot, Defender and PowerShell. Every article is reviewed against current Microsoft documentation.
Windows can tell you the firmware state from inside the OS, which makes fleet-wide drift detection a small PowerShell script rather than a physical audit. This article builds that script as an Intune detection package. It queries the firmware directly with the built-in Confirm-SecureBootUEFI cmdlet, cross-checks the registry mirror of the same state, and reports four honest outcomes: enabled, disabled, not determinable, or error. It changes nothing, because changing this particular setting from inside the running OS is neither possible nor desirable.
Symptoms
Devices fail Intune compliance with "Secure Boot" flagged, or report BitLocker policy warnings alongside it.
Virtualization-based Security (VBS) or Credential Guard shows as not running on devices that meet every other hardware requirement.
After a firmware or BIOS update campaign, a subset of devices loses Secure Boot without anyone touching the OS.
Windows 11 readiness reports fail on otherwise capable hardware.
A desktop technician reimages a device and it comes back joined and patched, but with Secure Boot off, and nothing in the build checklist catches it.
Possible Causes
Firmware update or CMOS reset
BIOS/UEFI updates and NVRAM resets frequently restore default firmware settings. If Secure Boot was not the default, it is now off, and the OS never informs anyone.
Deliberate disablement for another OS
Dual-boot experiments, Linux lab machines, and legacy boot troubleshooting all start with turning Secure Boot off. Some of those machines come back; the setting often does not.
Legacy BIOS hardware
Devices in legacy/MBR mode have no Secure Boot to enable. Detection must report this as "cannot determine" rather than "disabled", because the remediation is an OS migration to UEFI, not a settings change.
Image or provisioning mistakes
Images captured with firmware settings unsealed, or provisioning workflows that disable Secure Boot to work around driver or boot issues and never re-enable it, propagate the drift at scale.
PK or key management problems
Platforms with custom key exchanges (for example, third-party module signing chains) can end up with Secure Boot in Setup Mode, which reads as disabled until keys are enrolled.
Detection Script
The script below is read-only, runs in 64-bit SYSTEM context, and completes in under a second. It calls the built-in Confirm-SecureBootUEFI cmdlet as the primary source of truth, reads HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State\UEFISecureBootEnabled as a cross-check, and resolves conflicts conservatively.
PowerShell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#Requires -RunAsAdministrator
[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
<#
.SYNOPSIS
Detection script: reports the Secure Boot state of the device.
.NOTES
Intended for Intune Scripts and Remediations, 64-bit SYSTEM context.
Read-only. Exit 0 = Secure Boot enabled, 1 = Secure Boot disabled,
2 = state cannot be determined reliably (not a UEFI platform, or
contradictory signals), 3 = unexpected error. Uses the built-in
Confirm-SecureBootUEFI cmdlet as the primary source and the registry
value UEFISecureBootEnabled as a cross-check.
#>$logDir = 'C:\ProgramData\Company\Logs'$logFile = Join-Path $logDir'SecureBootDetection.log'$secureBootStateKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State'function Write-DetectionLog {
param([Parameter(Mandatory)][string] $Level, [Parameter(Mandatory)][string] $Message)
if (-not (Test-Path $logDir)) { New-Item -Path$logDir -ItemType Directory -Force | Out-Null }
"$([DateTime]::UtcNow.ToString('o')) [$Level] $Message" | Out-File -FilePath$logFile -Append -Encoding utf8
}
try {
Write-DetectionLog 'INFO''Secure Boot detection run started.' # ---- Primary source: the firmware itself ----$cmdletState = $nulltry {
$cmdletState = Confirm-SecureBootUEFI
Write-DetectionLog 'INFO'"Confirm-SecureBootUEFI returned: $cmdletState"
}
catch {
Write-DetectionLog 'WARN'"Confirm-SecureBootUEFI failed: $($_.Exception.Message). Falling back to the registry cross-check."
}
# ---- Cross-check: the registry mirror of the state ----$registryState = $nullif (Test-Path $secureBootStateKey) {
$prop = Get-ItemProperty -Path$secureBootStateKey -Name'UEFISecureBootEnabled' -ErrorAction SilentlyContinue
if ($null -ne$prop) { $registryState = $prop.UEFISecureBootEnabled }
}
Write-DetectionLog 'INFO'"Registry UEFISecureBootEnabled: $registryState"if ($null -ne$cmdletState) {
if ($null -ne$registryState -and$registryState -ne [int]$cmdletState) {
Write-DetectionLog 'WARN'"Firmware query and registry disagree (cmdlet=$cmdletState registry=$registryState). Trusting the firmware query and flagging the drift."
}
if ($cmdletState) {
Write-DetectionLog 'INFO''Secure Boot is enabled.'
exit 0
}
Write-DetectionLog 'ERROR''Secure Boot is disabled in firmware.'
exit 1
}
# ---- The cmdlet threw: not a UEFI platform, or the state is unreadable ----if ($null -eq$registryState) {
Write-DetectionLog 'WARN''No Secure Boot state available: the device is not UEFI, or Secure Boot state is exposed by neither the cmdlet nor the registry.'
exit 2
}
if ($registryState -eq1) {
Write-DetectionLog 'WARN''Registry reports Secure Boot enabled but the firmware query could not confirm it - contradictory signals, state uncertain.'
exit 2
}
Write-DetectionLog 'ERROR''Registry reports Secure Boot disabled and the firmware query could not confirm otherwise.'
exit 1
}
catch {
Write-DetectionLog 'ERROR'"Unexpected failure: $($_.Exception.Message)"
exit 3
}
Detection Logic
Firmware query.Confirm-SecureBootUEFI asks the platform's UEFI Secure Boot variable directly, which is as close to the truth as the running OS can get. It returns $true or $false on UEFI systems. On non-UEFI platforms it throws, which the script catches and treats as a signal, not a failure.
Registry cross-check. On UEFI systems with the Secure Boot driver loaded, HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State carries UEFISecureBootEnabled: 1 enabled, 0 disabled. The key's absence is itself informative, because legacy BIOS machines do not publish it. The script logs the value whether or not the cmdlet succeeded.
Consistent enabled. Cmdlet says true (registry agrees or is absent) exits 0.
Consistent disabled. Cmdlet says false exits 1. This is the actionable drift case: the hardware supports Secure Boot and it is off.
Cmdlet threw, registry absent. Almost certainly not a UEFI platform. Exit 2, because "cannot determine" is the honest answer and the remediation path (MBR2GPT and a firmware mode switch) is entirely different from flipping a toggle.
Contradictory signals. If the cmdlet fails while the registry claims enabled, or the two disagree, the script exits 2 and logs both values. Trusting a single source in a contradictory state is how false-positive cleanup campaigns start.
Remediation Script
There is no remediation script, by design. Secure Boot is a firmware setting, and the running OS cannot and should not flip it; the whole point of the mechanism is that the pre-boot environment controls it. Remediation is a human workflow: an OEM firmware management tool (HP, Dell, and Lenovo all ship their own), a scripted BIOS settings push during provisioning, or a manual firmware settings visit. What this package contributes is the trigger: a reliable, logged, per-device signal that says which devices need that workflow. Wire the exit codes into your compliance reporting and let the firmware tooling handle the fix.
Deploying Through Intune
Deploy as a detection-only package:
In the Microsoft Intune admin center, go to Devices → Scripts and remediations and select + Add under Windows 10/11.
On Basics, name it, for example Detect - Secure Boot state, and note that it is a read-only firmware-state check.
On Detection script, upload detect.ps1. Set Run script in 64-bit PowerShell: Yes and Run this script using signed-on credentials: No; the cmdlet requires elevation, which SYSTEM provides. Leave Enforce script signature check: No unless you sign internal scripts.
On the Remediation script step, choose No remediation script. Firmware settings are out of a script's reach on purpose.
On Schedule, Weekly is enough; firmware state changes rarely and only through deliberate action or firmware events.
On Assignments, target all physical Windows devices. Expect exit code 2 noise from VMs without virtual Secure Boot, so exclude known VM groups with filters if the counts bother your reports.
Review and create.
Post-specific notes:
Intune compliance policies can also require Secure Boot for Windows devices. Use this package to explain non-compliance; use the compliance policy to enforce it in reporting.
Devices upgraded from Windows 10 on legacy firmware may need an MBR2GPT migration before Secure Boot can even exist. Route exit code 2 devices into that workflow, not into firmware-toggle tickets.
Autopilot device preparation and Windows 11 readiness both assume Secure Boot and TPM 2.0. Catch the drift before the enrollment, not during it.
Visual Walkthrough
Why compliance checks fail when the firmware trust chain is off.
Decision TreeSecure Boot & TPM — Hardware Root of Trust5/5
Decision gate
Firmware trust enabled?
UEFI Secure Boot + TPM 2.0 are the foundation for VBS/BitLocker/WHfB.
Enabled & measured
1
Secure Boot on
Bootloaders must be signed — rootkits denied at boot.
Secure Boot is present for this platform but disabled
2
State cannot be determined reliably: not a UEFI platform, or firmware and registry disagree
3
Unexpected script error — inspect the log
Logging
The script writes to C:\ProgramData\Company\Logs\SecureBootDetection.log. Each line has a UTC timestamp, a level (INFO, WARN, ERROR), and a message. A healthy run logs the cmdlet result and the registry value on separate lines, which makes any later disagreement between the two sources visible in the raw log. Files grow by three to five lines per run; monthly rotation is plenty.
Troubleshooting the Script
Exit code 2 on a physical device. Check whether the device boots in legacy mode or has the Secure Boot driver unavailable. The registry key's absence plus a cmdlet error is the script telling you the platform has nothing to report.
Exit code 2 on a virtual machine. Many VM generations do not expose a Secure Boot variable. Exclude VM groups from the assignment or accept the code 2 count as your VM population.
Confirm-SecureBootUEFI errors about elevation. The cmdlet requires an elevated context. Confirm the package runs with signed-on credentials set to No, so it executes as SYSTEM.
Firmware and registry disagree in the log. Rare, but it happens after firmware updates race the OS state. The script trusts the firmware and logs both values; re-run after the next reboot before escalating.
No log file appears. The script never ran. Verify assignment, device check-in time, and that no conflicting policy forces a 32-bit PowerShell session.
How to Validate the Fix
On a known-UEFI device with Secure Boot enabled, run the script manually in an elevated 64-bit PowerShell console. Expect exit code 0 with both the cmdlet and registry values logged as 1/True.
In a lab VM, disable Secure Boot in the firmware, reboot, and re-run. Expect exit code 1 and the "disabled in firmware" log line.
On a legacy BIOS device or a VM without the variable, expect exit code 2 with the "no Secure Boot state available" line.
In the admin center, confirm the Device status view splits into the expected populations after the first scheduled run.
After a technician re-enables Secure Boot on a flagged device, re-run detection and confirm it moves to code 0, then confirm the device passes its compliance evaluation after the next sync.
Production Considerations
Execution context. SYSTEM in 64-bit Windows PowerShell. The check is machine-scoped and touches no user state.
Idempotency. Pure read: the script evaluates firmware and registry state and writes a log line. Run it as often as you like.
Side effects. None. No firmware calls that mutate state, no service restarts, no reboots.
Reporting hygiene. Decide as a team what exit code 2 means in your reporting before broad deployment. Treating "unknown" as "compliant" hides legacy hardware; treating it as "non-compliant" buries VM noise.
Security review and test ring. No credentials appear in the script and nothing is changed, but per your change process, have the PowerShell automation SME and security team review it and validate it in a test ring before broad production rollout.
Why does the script not just enable Secure Boot when it finds it off?
The setting lives in firmware, and the running OS has no supported way to change it; that restriction is a core part of what makes Secure Boot trustworthy. Remediation belongs to your firmware management tooling or a manual firmware visit. The script's job is finding the devices, quickly and reliably.
The cmdlet threw. Is the script broken?
No. Confirm-SecureBootUEFI throws on platforms where the UEFI Secure Boot variable does not exist, which includes legacy BIOS boots and some virtual machines. The script catches that, cross-checks the registry state, and reports exit code 2 when it cannot determine the truth. The log tells you which case you are in.
How does this relate to Windows 11 and Autopilot readiness?
Secure Boot is part of the Windows 11 hardware baseline, and modern Autopilot device preparation assumes it along with TPM 2.0. Detecting disabled Secure Boot before enrollment prevents a class of failures that otherwise surface as strange compliance states or setup failures mid-deployment.
Comments
0No comments yet — be the first to share your thoughts.