01 The root cause — two problems collide
The symptom is brutal: after a reboot following Windows Update, the PC shows "Boot Device Not Found" or drops straight into the UEFI shell. No hardware failure, no disk death — the UEFI boot loader was corrupted silently during the update process.
This isn't a single bug. It's the collision of two independent issues that together take down the entire boot chain.
The diagram shows why this is insidious: neither issue alone is fatal. An EFI partition with 50 MB free and a BIOS update history would survive indefinitely. Secure Boot CA 2023 would also apply cleanly on a machine with a fresh 260 MB EFI partition. It's only the combination that causes the crash.
02 What the remediation script does
The script runs as SYSTEM in 64-bit PowerShell via Intune Proactive Remediation. Here's the execution flow in four steps:
Uses Add-PartitionAccessPath (native PowerShell cmdlet, no timing issues) to assign a temporary drive letter to the hidden EFI FAT32 partition. Falls back to diskpart /s tmpfile if the cmdlet fails — writing a temp file instead of piping avoids the classic pipeline encoding issues.
diskpart.exe via PowerShell is unreliable — the process may not receive the newlines correctly in all contexts. Writing a temp .txt script and using diskpart /s is the production-safe approach.Uses [System.IO.DriveInfo] instead of Get-PSDrive — the former reads directly from the OS and doesn't require a cache refresh. Falls back to WMI Win32_LogicalDisk if DriveInfo.IsReady returns false.
Targets per-brand paths. These are firmware staging copies — not the active firmware itself, which lives on a separate protected partition:
| Brand | Paths cleaned | Typical size freed |
|---|---|---|
| HP | EFI\HP\DEVFW · EFI\HP\BIOS\Previous | 40–70 MB |
| Dell | EFI\Dell\UpdateCapsule · EFI\Dell\BIOS | 20–50 MB |
| Lenovo | EFI\Lenovo\UpdateCapsule | 15–40 MB |
The finally{} block always runs — even on exception. It unmounts the EFI partition, then runs two post-cleanup checks:
- Secure Boot state via
Confirm-SecureBootUEFI— confirms the firmware is still reporting boot as secure - BCD integrity via
bcdedit /enum '{bootmgr}'— confirms the Windows Boot Manager entry is present and valid
A single Write-Output line is emitted at the very end — this is what Intune captures in the Post-remediation detection output column.
03 The scripts
Detection script
Exit 0 = OK, exit 1 = remediation required. The single Write-Output line is what appears in the Pre-remediation detection output column in Intune.
# Run as : SYSTEM (64-bit) · exit 0 = OK · exit 1 = Remediate
$ErrorActionPreference = 'SilentlyContinue'
function Write-Log($Msg, $Level = 'INFO') {
# Write-Host ONLY — never Write-Output — Intune ignores Write-Host
$c = switch ($Level) { 'WARN'{'Yellow'} 'ERROR'{'Red'} 'OK'{'Green'} default{'Cyan'} }
Write-Host "[$(Get-Date -f 'HH:mm:ss')][$Level] $Msg" -ForegroundColor $c
}
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Start-Process powershell "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
exit 0
}
$TempLetter = 'Q'; $Mounted = $false
$Brand = 'Unknown'; $Model = 'Unknown'; $RiskLevel = 'UNKNOWN'
$EFIFreeMB = 0; $EFITotalMB = 0; $VendorSizeMB = 0; $VendorFiles = 0
try {
$cs = Get-WmiObject Win32_ComputerSystem
$Brand = switch -Wildcard ($cs.Manufacturer.Trim()) {
'*HP*'{'HP'} '*Hewlett*'{'HP'} '*Dell*'{'Dell'} '*Lenovo*'{'Lenovo'} default{'Other'}
}
$Model = $cs.Model.Trim()
Write-Log "Brand=$Brand | Model=$Model"
$efiPart = Get-Partition |
Where-Object { $_.GptType -eq '{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}' } |
Select-Object -First 1
if (-not $efiPart) {
Write-Output "RISK=SKIP;REASON=NO_EFI_PARTITION;BRAND=$Brand;MODEL=$Model"
exit 0
}
$DiskNumber = $efiPart.DiskNumber; $PartNumber = $efiPart.PartitionNumber
if (Test-Path "${TempLetter}:\") { $TempLetter = 'P' }
if (Test-Path "${TempLetter}:\") { $TempLetter = 'X' }
try {
Add-PartitionAccessPath -DiskNumber $DiskNumber -PartitionNumber $PartNumber `
-AccessPath "${TempLetter}:\" -ErrorAction Stop
Start-Sleep -Milliseconds 800; $Mounted = $true
} catch {
$dpFile = Join-Path $env:TEMP "efi_$(Get-Random).txt"
@"
select disk $DiskNumber
select partition $PartNumber
assign letter=$TempLetter
exit
"@ | Set-Content $dpFile -Encoding ASCII -Force
Start-Process diskpart.exe -ArgumentList "/s `"$dpFile`"" -Wait -WindowStyle Hidden
Remove-Item $dpFile -Force -EA SilentlyContinue
$w=0; while(-not(Test-Path "${TempLetter}:\") -and $w-lt 10){Start-Sleep 1;$w++}
if(Test-Path "${TempLetter}:\"){$Mounted=$true}else{throw 'EFI mount failed'}
}
$d = [System.IO.DriveInfo]"${TempLetter}:"
if($d.IsReady){ $EFIFreeMB=[math]::Round($d.AvailableFreeSpace/1MB,1); $EFITotalMB=[math]::Round($d.TotalSize/1MB,1) }
$vendorPaths = switch($Brand){
'HP' { @("${TempLetter}:\EFI\HP\DEVFW", "${TempLetter}:\EFI\HP\BIOS\Current") }
'Dell' { @("${TempLetter}:\EFI\Dell", "${TempLetter}:\EFI\DELL") }
'Lenovo' { @("${TempLetter}:\EFI\Lenovo") }
default { @() }
}
foreach($p in $vendorPaths){
if(Test-Path $p){
$i=Get-ChildItem $p -Recurse -File -EA SilentlyContinue
$VendorFiles+=$i.Count
$VendorSizeMB+=[math]::Round(($i|Measure-Object Length -Sum).Sum/1MB,1)
}
}
$RiskLevel = if($EFIFreeMB-lt 20){'CRITICAL'}
elseif($EFIFreeMB-lt 35-or($VendorSizeMB-gt 30-and $EFIFreeMB-lt 55)){'HIGH'}
elseif($VendorFiles-gt 0-and $EFIFreeMB-lt 80){'MEDIUM'}
else{'LOW'}
# ── SINGLE Write-Output line → Intune Pre-remediation detection output ──
Write-Output "RISK=$RiskLevel | FREE=${EFIFreeMB}MB/${EFITotalMB}MB | VENDOR=${VendorSizeMB}MB(${VendorFiles}f) | $Brand $Model"
if($RiskLevel -in 'CRITICAL','HIGH'){ exit 1 } else { exit 0 }
} catch {
Write-Output "RISK=ERROR | $($_.Exception.Message) | $Brand $Model"; exit 0
} finally {
if($Mounted){
Remove-PartitionAccessPath -DiskNumber $DiskNumber -PartitionNumber $PartNumber `
-AccessPath "${TempLetter}:\" -EA SilentlyContinue
}
}
Remediation script (v4 — production tested)
Verified on HP EliteBook 840 G11 (256 MB EFI). Freed 54.4 MB across 6 staging files in under 3 seconds.
# Run as : SYSTEM (64-bit) · Intune Proactive Remediation
# Log : C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\EFI-Remediation.log
$ErrorActionPreference = 'SilentlyContinue'
$LogFile = 'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\EFI-Remediation.log'
$TempLetter = 'Q'; $Mounted = $false; $Cleaned = 0; $FreedMB = 0
$Brand = 'Unknown'; $Model = 'Unknown'; $SecureBoot = 'Unknown'
function Write-Log($Msg, $Level = 'INFO') {
# Write-Host + file log only — NEVER Write-Output here
$line = "[$(Get-Date -f 'HH:mm:ss')][$Level] $Msg"
Add-Content -Path $LogFile -Value $line -Force
$c = switch($Level){'WARN'{'Yellow'}'ERROR'{'Red'}'FIX'{'Green'}'OK'{'Green'}default{'Cyan'}}
Write-Host $line -ForegroundColor $c
}
Write-Log '=== EFI Remediation START === v4'
try {
# 1. Brand & model ─────────────────────────────────────────────
$cs = Get-WmiObject Win32_ComputerSystem
$Brand = switch -Wildcard ($cs.Manufacturer.Trim()){
'*HP*'{'HP'}'*Hewlett*'{'HP'}'*Dell*'{'Dell'}'*Lenovo*'{'Lenovo'}default{'Other'}
}
$Model = $cs.Model.Trim()
Write-Log "Brand=$Brand | Model=$Model"
# 2. EFI partition ─────────────────────────────────────────────
$efiPart = Get-Partition |
Where-Object { $_.GptType -eq '{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}' } |
Select-Object -First 1
if(-not $efiPart){ Write-Output "STATUS=SKIP|REASON=NO_EFI|$Brand $Model"; exit 0 }
$DiskNumber = $efiPart.DiskNumber; $PartNumber = $efiPart.PartitionNumber
Write-Log "EFI partition : Disk $DiskNumber / Partition $PartNumber"
# 3. Mount EFI ─────────────────────────────────────────────────
if(Test-Path "${TempLetter}:\"){$TempLetter='P'}
if(Test-Path "${TempLetter}:\"){$TempLetter='X'}
try {
Add-PartitionAccessPath -DiskNumber $DiskNumber -PartitionNumber $PartNumber `
-AccessPath "${TempLetter}:\" -ErrorAction Stop
Start-Sleep -Milliseconds 800; $Mounted=$true
Write-Log "EFI mounted via Add-PartitionAccessPath at ${TempLetter}:"
} catch {
Write-Log "Add-PartitionAccessPath failed — diskpart fallback" 'WARN'
$dpFile = Join-Path $env:TEMP "efi_rem_$(Get-Random).txt"
@"
select disk $DiskNumber
select partition $PartNumber
assign letter=$TempLetter
exit
"@ | Set-Content $dpFile -Encoding ASCII -Force
Start-Process diskpart.exe -ArgumentList "/s `"$dpFile`"" -Wait -WindowStyle Hidden
Remove-Item $dpFile -Force -EA SilentlyContinue
$w=0; while(-not(Test-Path "${TempLetter}:\")-and $w-lt 10){Start-Sleep 1;$w++}
if(Test-Path "${TempLetter}:\"){$Mounted=$true}else{throw "EFI mount impossible after ${w}s"}
}
# 4. Free space BEFORE ─────────────────────────────────────────
$di = [System.IO.DriveInfo]"${TempLetter}:"
$FreeBefore = [math]::Round($di.AvailableFreeSpace/1MB,1)
$TotalMB = [math]::Round($di.TotalSize/1MB,1)
Write-Log "EFI before : Free=${FreeBefore}MB / Total=${TotalMB}MB"
# 5. Delete vendor staging files ───────────────────────────────
$targetPaths = switch($Brand){
'HP' { @("${TempLetter}:\EFI\HP\DEVFW", "${TempLetter}:\EFI\HP\BIOS\Previous") }
'Dell' { @("${TempLetter}:\EFI\Dell\UpdateCapsule", "${TempLetter}:\EFI\Dell\BIOS") }
'Lenovo' { @("${TempLetter}:\EFI\Lenovo\UpdateCapsule") }
default { @() }
}
foreach($path in $targetPaths){
if(Test-Path $path){
Get-ChildItem $path -Recurse -File -EA SilentlyContinue | ForEach-Object {
$sz = [math]::Round($_.Length/1MB,2)
try{
Remove-Item $_.FullName -Force -ErrorAction Stop
$FreedMB+=$sz; $Cleaned++
Write-Log "Deleted : $($_.Name) (${sz}MB)" 'FIX'
} catch { Write-Log "Cannot delete $($_.Name) : $($_.Exception.Message)" 'WARN' }
}
} else { Write-Log "Path not found (skipped) : $path" }
}
$FreedMB = [math]::Round($FreedMB,1)
Write-Log "Cleanup done : $Cleaned file(s) deleted, ${FreedMB}MB freed"
# 6. Free space AFTER ──────────────────────────────────────────
$di = [System.IO.DriveInfo]"${TempLetter}:"
$FreeAfter = [math]::Round($di.AvailableFreeSpace/1MB,1)
Write-Log "EFI after : Free=${FreeAfter}MB / Total=${TotalMB}MB"
if($FreeAfter-lt 30){
Write-Log "WARNING : ${FreeAfter}MB free — EFI resize recommended (target 260MB)" 'WARN'
}
} catch {
Write-Log "FATAL : $($_.Exception.Message)" 'ERROR'
Write-Output "STATUS=ERROR | $($_.Exception.Message) | $Brand $Model"; exit 1
} finally {
# 7. Unmount EFI (always runs) ─────────────────────────────────
if($Mounted){
try{
Remove-PartitionAccessPath -DiskNumber $DiskNumber -PartitionNumber $PartNumber `
-AccessPath "${TempLetter}:\" -EA SilentlyContinue
Write-Log 'EFI unmounted (Remove-PartitionAccessPath)'
} catch {
$dpFile = Join-Path $env:TEMP "efi_umount_$(Get-Random).txt"
@"
select disk $DiskNumber
select partition $PartNumber
remove letter=$TempLetter
exit
"@ | Set-Content $dpFile -Encoding ASCII -Force
Start-Process diskpart.exe -ArgumentList "/s `"$dpFile`"" -Wait -WindowStyle Hidden
Remove-Item $dpFile -Force -EA SilentlyContinue
Write-Log 'EFI unmounted (diskpart fallback)'
}
}
# 8. SecureBoot state (post-cleanup, outside EFI partition) ───
$SecureBoot = (Confirm-SecureBootUEFI -ErrorAction SilentlyContinue)
Write-Log "SecureBoot state : $SecureBoot"
# 9. BCD integrity check ───────────────────────────────────────
$bcd = & bcdedit /enum '{bootmgr}' 2>&1
if($bcd -match 'Windows Boot Manager'){
Write-Log 'BCD integrity : OK (Windows Boot Manager entry present)' 'OK'
} else {
Write-Log 'BCD integrity : WARNING — Boot Manager entry not found' 'WARN'
}
# 10. SINGLE Write-Output line → Intune Post-remediation output
if($Cleaned-gt 0){
Write-Output "STATUS=FIXED | FREED=${FreedMB}MB | FILES=$Cleaned | FREE_NOW=${FreeAfter}MB/${TotalMB}MB | SB=$SecureBoot | $Brand $Model"
} else {
Write-Output "STATUS=CLEAN | NOTHING_TO_DELETE | FREE=${FreeAfter}MB/${TotalMB}MB | SB=$SecureBoot | $Brand $Model"
}
Write-Log '=== EFI Remediation END ==='
}
04 Intune configuration
| Setting | Value | Why |
|---|---|---|
| Run as logged-on credentials | ✕ No | Add-PartitionAccessPath requires SYSTEM. User context → Access Denied. |
| Enforce script signature check | ✕ No | Script is unsigned. Only enable if you have an internal PKI and sign your scripts. |
| Run in 64-bit PowerShell | ✓ Yes | The Storage module (Get-Partition, Add-PartitionAccessPath) only exists in 64-bit. This is the most critical setting. |
| Schedule | Daily · 09:00 | Keeps the EFI partition clean after every BIOS update cycle. |
Storage module doesn't exist. Every cmdlet call will fail silently and you'll see RISK=ERROR in the detection output with no useful message.05 Real-world output
Here's what the script produced running locally on an HP EliteBook 840 G11 (256 MB EFI partition):
6 staging files present
54.4 MB occupied by DEVFW
Secure Boot: True
BCD: Windows Boot Manager OK