Autopilot Enrollment Broken by WDAC and Constrained Language Mode: The 0x800705b4 Fix
You've deployed Autopilot. You've locked down your devices with Windows Defender Application Control (WDAC) and PowerShell Constrained Language Mode (CLM). Then enrollment fails silently with error 0x800705b4 on every new device, and you spend six weeks reverse-engineering code integrity logs to discover that IME (Intel Management Engine) isn't considered a "Microsoft Product."
This is a real production incident that has hit multiple enterprise environments since April 2025. This guide walks you through the root cause, three proven fixes, and the diagnostic commands you'll need at 3 AM when devices are stuck in an enrollment loop.
What's Actually Happening: The Enrollment Collision
Autopilot enrollment orchestrates a complex dance of unsigned and dynamically-loaded PowerShell scripts, Windows service executables, and Intune Management Extension binaries. When WDAC policy is enforced and CLM is active, both layers of protection reject these scripts as untrusted code.
Why Error 0x800705b4 Matters
The hexadecimal value 0x800705B4 decodes to "Access Denied" — specifically, a code integrity violation. In the context of Autopilot:
- 0x80070000 = Windows system error range
- 5B4 (decimal 1460) = Script Enforcement Policy violation
When WDAC sees an unsigned script or a binary not in its whitelist, it logs this error and blocks execution. When PowerShell CLM is active, it further restricts capabilities—no COM objects, no Win32 API calls, no dynamic script loading. Together, they create an impossible situation for Autopilot.
C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\ServiceEnrollment.log and the Windows Code Integrity operational event log instead.
Root Cause Deep Dive: Three Separate Policy Layers
This isn't a single policy problem—it's three systems acting independently:
| Policy Layer | What It Controls | Impact on Autopilot | Detection |
|---|---|---|---|
| WDAC (Kernel) | Which binaries, DLLs, and scripts can execute | Blocks enrollment scripts, svchost.exe variants, IME binaries | Event ID 3002 in Code Integrity/Operational |
| PowerShell CLM | What PowerShell language features are available | Blocks dynamic code loading, Win32 calls, COM interop | $ExecutionContext.SessionState.LanguageMode = ConstrainedLanguage |
| ESP (Enrollment Status Page) | When provisioning is "complete" | Times out waiting for blocked scripts to finish | Devices stuck at 99% for 60+ minutes |
The most insidious part: IME (Intel Management Engine) is not whitelisted under "Microsoft Products" in most stock WDAC policies. This discovered during real incident forensics—teams created WDAC policies that whitelist "Microsoft Corporation" binaries, but IME is published by Intel, not Microsoft. Since IME is required for certain Autopilot and enrollment tasks, the device deadlocks.
Solution 1: Defer WDAC/CLM Until Post-Enrollment (Recommended)
The cleanest production fix is to delay policy enforcement until the device completes Autopilot ESP. This requires three components:
-
Create an Intune assignment filter excluding Autopilot devices
Use dynamic Azure AD device properties to exclude devices during their enrollment window:
// Assignment Filter: Exclude devices in Autopilot enrollment (device.enrollmentProfileName -ne "Windows Autopilot") or (device.deviceEnrollmentType -ne "windowsCoManagementEnrollment") -
Configure Autopilot ESP to not require WDAC policies
In Intune, navigate to Devices → Windows → Windows enrollment → Autopilot deployment profiles → [Your Profile]. Under Enrollment Status Page, set the following:
- Show app and profile configuration progress: Yes
- Block device use until required apps are installed: No
- Allow users to reset device if installation error occurs: Yes
This allows devices to exit ESP even if WDAC policies haven't fully applied yet.
-
Deploy WDAC/CLM policies to post-enrollment groups
Create a dynamic Azure AD group:
// Dynamic Group: Post-Autopilot Devices (24+ hours old) (device.createdDateTime -lt now-24h) and (device.deviceEnrollmentType -eq "windowsCoManagementEnrollment")Assign your WDAC and CLM policies to only this group. Devices will not receive restrictive policies until at least 24 hours post-enrollment.
-
Monitor enrollment delays and adjust timing
Use Graph API to query assignment success rates:
GET https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/{policyId}/assignments // Returns list of target groups and actual device count applied
Solution 2: Whitelist Enrollment Binaries in WDAC Policy
If you cannot defer policy application, you must whitelist the exact binaries and scripts that Autopilot requires. This is forensically intensive but necessary for immediate hardening.
-
Collect code integrity logs during a test enrollment
On a test device with WDAC in Audit Mode (not enforced), trigger enrollment and collect violations:
// Enable Audit Mode first (non-blocking) Set-CIPolicy -FilePath "C:\WDAC\audit-policy.bin" -Audit // Then collect events after a failed enrollment attempt Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" ` -FilterXPath "*[EventData[Data[@Name='FileName']]]" | Select-Object TimeCreated, @{Name="File";Expression={$_.Properties[4].Value}} | Export-Csv -Path "C:\Logs\wdac-blocks.csv" -NoTypeInformation
-
Identify required Intune Management Extension binaries
These are the critical paths that MUST be whitelisted:
// Standard Intune MEE installation paths C:\Program Files\Microsoft Intune Management Extension\*.exe C:\Program Files\Microsoft Intune Management Extension\*.dll // Service executables required for enrollment C:\Windows\System32\svchost.exe C:\Windows\System32\lsass.exe C:\Windows\System32\winlogon.exe // PowerShell itself (if you want any scripts to run) C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
-
Create a WDAC policy XML with Allow rules for these binaries
This example allows Microsoft-signed Intune binaries and whitelists by file hash for unsigned scripts:
<?xml version="1.0" encoding="utf-8"?> <SiPolicy xmlns="urn:schemas-microsoft-com:sipolicy" xmlns:mssecext="http://schemas.microsoft.com/MSSecurity/sipolicy/2019/06/07" xmlns:p="http://schemas.microsoft.com/wdac/manifest/1.0" xmlns:asp="http://schemas.microsoft.com/AspNet/SiteMap"> <Rules> <!-- Allow Intune Management Extension by publisher --> <FilePublisher Action="Allow" UserMode="True" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation" PublisherName="Microsoft" ProductName="Microsoft Intune Management Extension" BinaryName="*.exe" MinimumFileVersion="0.0.0.0"/> <!-- Allow svchost.exe for enrollment services --> <FilePublisher Action="Allow" UserMode="True" Publisher="CN=Microsoft Windows, O=Microsoft Corporation" PublisherName="Microsoft" BinaryName="svchost.exe" MinimumFileVersion="0.0.0.0"/> <!-- Whitelist unsigned script by hash (from audit log) --> <Hash Type="SHA256" Action="Allow" UserMode="True" Hash="ABCD1234..." /> </Rules> </SiPolicy> -
Convert XML to binary policy and deploy via Intune
Validate syntax, convert to binary, and deploy:
// Test the XML policy Test-CIPolicy -XmlFilePath "C:\WDAC\autopilot-whitelist.xml" // Convert to binary format ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\autopilot-whitelist.xml" ` -BinaryFilePath "C:\WDAC\autopilot-whitelist.bin" // Deploy via Intune (Device Configuration > Windows Defender Application Control) https://intune.microsoft.com → Devices → Configuration profiles → Create profile → Platform: Windows 10 and later → Profile type: Device restrictions → Windows Defender Application Control → Upload binary
Solution 3: Bypass CLM During Enrollment Only
PowerShell Constrained Language Mode can be configured to activate only after enrollment completes. Use a Group Policy or Intune policy that targets post-enrollment devices.
-
Create a Group Policy Object (GPO) or Intune Administrative Template policy
In Computer Configuration > Policies > Administrative Templates > PowerShell:
- Turn on PowerShell Script Block Logging: Disabled (during enrollment)
- Set the default source for Update-Help: Not configured
- Module Logging: Disabled (during enrollment)
Assign this permissive policy to a group that includes devices within 48 hours of enrollment.
-
Deploy CLM enforcement to post-enrollment devices only
In Intune, use an Intune script (not a template) to conditionally enable CLM:
// PowerShell script: Deploy CLM after enrollment (via Intune Remediation) $enrollmentTime = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion" ` -Name InstallDate -ErrorAction SilentlyContinue if ($enrollmentTime) { $enrollDate = [datetime]::FromFileTime($enrollmentTime.InstallDate) $age = (Get-Date) - $enrollDate if ($age.TotalHours -ge 48) { // Device is older than 48 hours; safe to enable CLM New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Session Manager\Environment" ` -Name "__PSLockdownPolicy" -Value 96 -PropertyType DWord -Force exit 0 } else { // Device is in enrollment window; skip CLM exit 1 } }
-
Monitor PowerShell session language mode
Verify CLM activation post-enrollment:
powershell.exe -NoProfile -Command "$ExecutionContext.SessionState.LanguageMode"
Expected output before 48 hours:
FullLanguage
Expected output after 48 hours:ConstrainedLanguage
Diagnostic Toolkit: Finding Your Specific Problem
If 0x800705b4 is happening on your devices, run these commands to identify which layer is blocking:
### 1. Check if WDAC is enabled and in what mode Get-CimInstance -ClassName Win32_DeviceGuard -Namespace "root\Microsoft\Windows\DeviceGuard" | Select-Object CodeIntegrityPolicyEnforcementStatus, AvailableSecurityProperties, UsermodeCodeIntegrityPolicyEnforcementStatus ### Output interpretation: ### CodeIntegrityPolicyEnforcementStatus: ### 0 = Off ### 1 = Audit Mode (non-blocking) ### 2 = Enforced (BLOCKING) ### 2. Check PowerShell language mode $ExecutionContext.SessionState.LanguageMode ### Output: FullLanguage (no restrictions) or ConstrainedLanguage (blocked) ### 3. Review WDAC code integrity violations in real-time Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" ` -FilterXPath "*[System[EventID=3002]]" -MaxEvents 20 | ForEach-Object { @{ Time = $_.TimeCreated File = $_.Properties[4].Value Hash = $_.Properties[5].Value UserMode = $_.Properties[9].Value } } | Format-Table -AutoSize ### 4. Check Autopilot/Intune enrollment logs Get-Content "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\ServiceEnrollment.log" -Tail 100 | Select-String -Pattern "error|failed|denied" -Context 2 ### 5. Verify device enrollment status in Graph API GET https://graph.microsoft.com/beta/deviceManagement/managedDevices ?$filter=deviceName eq 'DEVICENAME'&$select=id,deviceName,enrollmentType,enrollmentProfileName,lastSyncDateTime
Complete PowerShell Remediation Script
This script can be deployed as an Intune Remediation script (Devices → Scripts → Add) to automatically detect and report the enrollment blocking issue:
### File: Detect-AutopilotWDACCLMBlocking.ps1 ### Purpose: Intune Detection script for 0x800705b4 diagnosis ### Deployment: Intune > Devices > Scripts > Platform scripts > Add $results = @{} $isCompliant = $true ### 1. Check WDAC Status try { $wdac = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace "root\Microsoft\Windows\DeviceGuard" -ErrorAction Stop $wdacStatus = $wdac.CodeIntegrityPolicyEnforcementStatus $results['WDAC_Enforced'] = if ($wdacStatus -eq 2) { "Yes (Blocking)" } else { "No (Audit/Off)" } if ($wdacStatus -eq 2) { $isCompliant = $false } } catch { $results['WDAC_Status'] = "Error: $_" } ### 2. Check PowerShell Language Mode try { $langMode = $ExecutionContext.SessionState.LanguageMode $results['PowerShell_LanguageMode'] = $langMode if ($langMode -eq "ConstrainedLanguage") { $isCompliant = $false } } catch { $results['PowerShell_Mode_Error'] = "$_" } ### 3. Check Enrollment Status try { $enrollment = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\*" ` -ErrorAction SilentlyContinue $results['Enrollment_Status'] = if ($enrollment) { "Enrolled" } else { "Not Enrolled" } } catch { } ### 4. Query recent Code Integrity events (WDAC blocks) try { $wdacEvents = @(Get-WinEvent -LogName "Microsoft-Windows-CodeIntegrity/Operational" ` -FilterXPath "*[System[EventID=3002]]" -MaxEvents 5 -ErrorAction SilentlyContinue) if ($wdacEvents.Count -gt 0) { $results['Recent_WDAC_Blocks'] = $wdacEvents.Count $results['Last_Block_File'] = $wdacEvents[0].Properties[4].Value $isCompliant = $false } } catch { } ### 5. Check Intune Service Extension logs try { $enrollLog = Get-Content "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\ServiceEnrollment.log" ` -ErrorAction SilentlyContinue -Tail 50 if ($enrollLog -match "0x800705b4|Script Enforcement|Access Denied") { $results['Enrollment_Log_Error'] = "0x800705b4 detected in enrollment logs" $isCompliant = $false } } catch { } ### 6. Output Results Write-Host "Autopilot Enrollment Blocking Diagnostic" Write-Host "==========================================" $results.GetEnumerator() | ForEach-Object { Write-Host "$($_.Name): $($_.Value)" } ### Exit codes for Intune Remediation: ### 0 = Compliant (device OK) ### 1 = Non-Compliant (issue detected, trigger remediation) if ($isCompliant) { Write-Host "Status: COMPLIANT" exit 0 } else { Write-Host "Status: NON-COMPLIANT - Enrollment blocking detected" exit 1 }
Graph API: Query Device Enrollment Status at Scale
To check which devices have successfully enrolled vs. failed, use this Graph API query:
### Endpoint: Query all devices with enrollment details GET https://graph.microsoft.com/v1.0/deviceManagement/managedDevices ?$filter=enrollmentType eq 'windowsCoManagement' &$select=id,deviceName,enrollmentType,enrollmentProfileName,lastSyncDateTime,complianceState,lostModeBitLockerKey ### Response example (trimmed): { "value": [ { "id": "device-123", "deviceName": "DEVICE-001", "enrollmentType": "windowsCoManagement", "lastSyncDateTime": "2025-05-14T09:30:00.000Z", "complianceState": "compliant" } ] } ### Query devices with Autopilot profile assigned: GET https://graph.microsoft.com/beta/deviceManagement/deviceEnrollmentConfigurations /{autopilotProfileId}/assignments ### Find devices still in enrollment (ESP active): GET https://graph.microsoft.com/beta/deviceManagement/managedDevices ?$filter=enrollmentProfileName eq 'Windows Autopilot' &$select=id,deviceName,createdDateTime ### PowerShell to run this query: $headers = @{ Authorization = "Bearer $accessToken" "Content-Type" = "application/json" } $uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?" + "\$filter=enrollmentType eq 'windowsCoManagement'&" + "\$select=id,deviceName,enrollmentProfileName,lastSyncDateTime" $devices = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get $devices.value | Where-Object { $_.enrollmentProfileName -like "*Autopilot*" } | Format-Table deviceName, enrollmentProfileName, lastSyncDateTime -AutoSize
Comprehensive Comparison: All Three Solutions
| Solution | Implementation Effort | Risk Level | Time to Resolution | Best For |
|---|---|---|---|---|
| 1. Defer WDAC/CLM (Recommended) | Low (filters + group membership) | ✓ Low | 1–2 hours | Large-scale deployments; devices with standard enrollment |
| 2. Whitelist Binaries in WDAC | High (audit logs, policy creation) | ✗ High (fragile on patches) | 6–24 hours | High-security environments; cannot defer policies |
| 3. Bypass CLM Post-Enrollment | Medium (dynamic targeting) | ✗ Medium (timing-dependent) | 2–4 hours | CLM is the primary blocker (WDAC is open) |
Preventing This in New Deployments
If you're building an Autopilot deployment from scratch, follow these best practices to avoid this incident entirely:
- Separate Policies by Lifecycle Phase: Create one policy set for enrollment (permissive) and another for post-enrollment (restrictive). Use Azure AD dynamic groups to target each phase automatically.
- Test WDAC in Audit Mode First: Deploy all WDAC policies in Audit Mode (non-enforced) for 2–4 weeks before switching to Enforced mode. This collects real violations without breaking devices.
- Whitelist Before Enforcing: Use audit logs to identify all required binaries, then include them in your policy before enforcement.
- Exclude Intune MEE and System Services Early: Explicitly whitelist
C:\Program Files\Microsoft Intune Management Extension\and critical svchost variants before enforcement. - Delay CLM to Day 2: Keep PowerShell in Full Language mode during enrollment. Deploy CLM restriction 24+ hours post-enrollment via assignment filters.
- Monitor Continuously: Set up alerts on Code Integrity events (Event ID 3002) in your SIEM or Intune-connected monitoring tool. Don't wait for user complaints.
Troubleshooting Checklist
- ✓ Confirmed WDAC status:
Get-CimInstance Win32_DeviceGuard - ✓ Confirmed PowerShell language mode:
$ExecutionContext.SessionState.LanguageMode - ✓ Reviewed Code Integrity logs: Event ID 3002 in Operational log
- ✓ Reviewed Intune enrollment logs:
ServiceEnrollment.log - ✓ Identified specific blocked binaries or scripts from audit logs
- ✓ Verified ESP timeout settings (should be 60+ minutes during remediation)
- ✓ Tested assignment filters in a pilot group before full rollout
- ✓ Documented all whitelisted hash values (if using Solution 2)
- ✓ Created rollback plan if Solution 1 causes unintended delays
Key Takeaways
Error 0x800705b4 during Autopilot enrollment means your WDAC and/or PowerShell CLM policies are blocking enrollment scripts. This is an architectural conflict that requires one of three mitigations:
- Defer both policies to 24+ hours post-enrollment via dynamic Azure AD groups (fastest, lowest risk)
- Whitelist required Intune and system binaries in your WDAC policy (feasible if you can't defer)
- Bypass CLM until enrollment completes (if CLM alone is the issue)
Use the diagnostic commands provided to identify which layer is blocking on your devices. Deploy the remediation script as an Intune platform script to detect the issue at scale. And most importantly: always test restrictive policies in Audit Mode before enforcement, and always use assignment filters to exclude devices during their enrollment window.