Add Windows MDM migration troubleshooting scripts and guide (#39548)

Closes #38916
Related: #34993, #33985, fleetdm/confidential#13228

## Changes

**Article update** (`articles/windows-mdm-setup.md`)
- Adds "Migrating from another MDM solution" subsection under **Manual
enrollment** with overview of common migration issues and links to
remediation scripts

**New scripts** (`docs/solutions/windows/scripts/`)
- `reset-mdm-enrollment-flag.ps1` — Resets MmpcEnrollmentFlag blocking
MDM status after migration
- `remove-stale-mdm-enrollment-records.ps1` — Clears orphaned enrollment
GUIDs, AAD discovery cache, and MS DM Server cache
- `fix-workplace-join-configuration.ps1` — Re-enables
Automatic-Device-Join task and configures Workplace Join policies
- `remove-unreachable-wsus-configuration.ps1` — Removes unreachable WSUS
server config that breaks Windows Update

## Context

Customers migrating Windows hosts from Intune to Fleet have been hitting
recurring enrollment issues, MDM status stuck on "Off," enrollment
errors (`0x80190190`, `0x8018000a`), and Windows Update breakage from
leftover RMM agents. These scripts consolidate the workarounds from
multiple customer engagements into self-serve remediation that can be
deployed via **Controls > Scripts**.

---------

Co-authored-by: Marko Lisica <83164494+marko-lisica@users.noreply.github.com>
This commit is contained in:
Adam Baali
2026-02-11 15:20:26 +01:00
committed by GitHub
co-authored by Marko Lisica
parent b7d9683fc5
commit f2f1f66d11
5 changed files with 134 additions and 0 deletions
+18
View File
@@ -47,6 +47,24 @@ With Windows MDM turned on, enroll a Windows host to Fleet by installing [Fleet'
> Windows [tamper protection](https://learn.microsoft.com/en-us/defender-endpoint/prevent-changes-to-security-settings-with-tamper-protection) is disabled on a host when MDM is turned on.
### Migrating from another MDM solution
When migrating Windows hosts from another MDM, devices may fail to report MDM as "On." You might see enrollment errors (e.g., 400 or 0x8018000a) in [fleetd logs](https://fleetdm.com/guides/enroll-hosts#debugging).
These issues are caused by residual enrollment data, registry conflicts, or third-party management agents from the previous MDM solution. [Run the scripts](https://fleetdm.com/guides/scripts#manually-run-scripts) below on the affected hosts, then **reboot the device** and select **Refetch** on the host details.
- [reset-mdm-enrollment-flag.ps1](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/scripts/reset-mdm-enrollment-flag.ps1): Resets the `MmpcEnrollmentFlag` registry value to fix incorrect MDM status reporting after migration.
- [remove-stale-mdm-enrollment-records.ps1](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/scripts/remove-stale-mdm-enrollment-records.ps1): Removes failed or orphaned MDM enrollment records, AAD discovery cache, and MS DM Server cache left behind by the previous MDM solution.
- [fix-workplace-join-configuration.ps1](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/scripts/fix-workplace-join-configuration.ps1): Re-enables the Automatic-Device-Join scheduled task and fixes Workplace Join policies that may be misconfigured after migration.
- [remove-unreachable-wsus-configuration.ps1](https://github.com/fleetdm/fleet/blob/main/docs/solutions/windows/scripts/remove-unreachable-wsus-configuration.ps1): Removes stale WSUS server configurations that can break Windows Update after migration. Only removes the configuration if the WSUS server is unreachable.
**Conflicting RMM or management agents:** Third-party RMM agents (such as N-able/SolarWinds, ConnectWise, or Kaseya) installed alongside the previous MDM solution can interfere with Fleet's MDM enrollment and may cause Windows Update to stop functioning. Check for and remove any RMM agents that are no longer needed before or after migrating to Fleet.
## Automatic enrollment
> Available in Fleet Premium
@@ -0,0 +1,22 @@
# Please don't delete. This script is referenced in the guide here: https://fleetdm.com/guides/windows-mdm-setup#migrating-from-another-mdm-solution
# Re-enables the Automatic-Device-Join scheduled task and configures Workplace Join policies
# that may be misconfigured after migrating from another MDM solution.
# Reboot the device after running this script.
# 1. Re-enable Automatic-Device-Join scheduled task
$TaskPath = "\Microsoft\Windows\Workplace Join\"
$TaskName = "Automatic-Device-Join"
try {
$task = Get-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -ErrorAction Stop
Enable-ScheduledTask -InputObject $task
Write-Host "Re-enabled Automatic-Device-Join task"
} catch {
Write-Host "Automatic-Device-Join task not found - skipping"
}
# 2. Configure Workplace Join policy
$WJPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WorkplaceJoin"
if (-not (Test-Path $WJPath)) { New-Item -Path $WJPath -Force | Out-Null }
Set-ItemProperty -Path $WJPath -Name "autoWorkplaceJoin" -Value 1 -Type DWord
Set-ItemProperty -Path $WJPath -Name "BlockAADWorkplaceJoin" -Value 0 -Type DWord
Write-Host "Configured Workplace Join policy"
@@ -0,0 +1,41 @@
# Please don't delete. This script is referenced in the guide here: https://fleetdm.com/guides/windows-mdm-setup#migrating-from-another-mdm-solution
# Removes stale MDM enrollment registry entries, AAD discovery cache, and MS DM Server cache
# that can block Fleet MDM enrollment after migrating from another MDM solution.
# Reboot the device after running this script.
# 1. Clear the AAD discovery cache
$AADPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CDJ\AAD"
if (Test-Path $AADPath) {
Remove-Item -Path $AADPath -Recurse -Force
Write-Host "Cleared AAD discovery cache"
} else {
Write-Host "AAD discovery cache not found - skipping"
}
# 2. Remove stale GUID-based enrollment entries (failed, removed, or error states)
$EnrollmentPath = "HKLM:\SOFTWARE\Microsoft\Enrollments"
$cleaned = 0
Get-ChildItem -Path $EnrollmentPath -ErrorAction SilentlyContinue | ForEach-Object {
if ($_.PSChildName -match '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') {
$state = (Get-ItemProperty -Path $_.PSPath -Name "EnrollmentState" -ErrorAction SilentlyContinue).EnrollmentState
# EnrollmentState: 0=Not enrolled, 1=Enrolled, 2=Failed, 3=Removed, 4=Failed (old may still work)
if ($state -in @(2, 3, 4)) {
Remove-Item -Path $_.PSPath -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Removed stale enrollment: $($_.PSChildName) (state: $state)"
$cleaned++
}
}
}
Write-Host "Cleaned $cleaned stale enrollment entries"
# 3. Clear MS DM Server cache
if (Test-Path "HKLM:\SOFTWARE\Microsoft\MSDM\Server") {
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\MSDM\Server\*" -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Cleared MS DM Server cache"
} else {
Write-Host "MS DM Server cache not found - skipping"
}
# 4. Restart Device Registration Service
Restart-Service -Name "DsSvc" -ErrorAction SilentlyContinue
Write-Host "Restarted Device Registration Service"
@@ -0,0 +1,40 @@
# Please don't delete. This script is referenced in the guide here: https://fleetdm.com/guides/windows-mdm-setup#migrating-from-another-mdm-solution
# Detects and removes unreachable WSUS server configurations that can break Windows Update
# after migrating from another MDM solution. Only removes WSUS config if the server cannot
# be reached at all (HTTP error responses like 403 are treated as reachable).
# Reboot the device after running this script.
$WUPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
if (-not (Test-Path $WUPath)) {
Write-Host "Windows Update policy path not found - no action needed"
exit 0
}
$wuServer = (Get-ItemProperty -Path $WUPath -Name "WUServer" -ErrorAction SilentlyContinue).WUServer
if (-not $wuServer) {
Write-Host "No WSUS server configured - no action needed"
exit 0
}
$reachable = $false
try {
$null = Invoke-WebRequest -Uri $wuServer -UseBasicParsing -TimeoutSec 5 -ErrorAction Stop
$reachable = $true
} catch [System.Net.WebException] {
if ($_.Exception.Response) {
# Server responded with an HTTP error (e.g., 403) - it is still reachable
$reachable = $true
}
} catch {
# Connection failed entirely
}
if ($reachable) {
Write-Host "WSUS server $wuServer is reachable - no action taken"
} else {
Write-Host "WSUS server $wuServer is unreachable - removing configuration"
Remove-ItemProperty -Path $WUPath -Name "WUServer" -ErrorAction SilentlyContinue
Remove-ItemProperty -Path $WUPath -Name "WUStatusServer" -ErrorAction SilentlyContinue
Restart-Service wuauserv -Force
Write-Host "Windows Update service restarted"
}
@@ -0,0 +1,13 @@
# Please don't delete. This script is referenced in the guide here: https://fleetdm.com/guides/windows-mdm-setup#migrating-from-another-mdm-solution
# Resets the MmpcEnrollmentFlag registry value that can prevent Fleet from reporting
# MDM status correctly after migrating from another MDM solution (e.g., Intune).
# Reboot the device after running this script.
$enrollmentsPath = "HKLM:\SOFTWARE\Microsoft\Enrollments"
$enrollmentFlag = (Get-ItemProperty -Path $enrollmentsPath -Name "MmpcEnrollmentFlag" -ErrorAction SilentlyContinue).MmpcEnrollmentFlag
if ($null -ne $enrollmentFlag -and 0 -ne $enrollmentFlag) {
Write-Host "Enrollment flag current value $enrollmentFlag - setting to 0"
Set-ItemProperty -Path $enrollmentsPath -Name "MmpcEnrollmentFlag" -Value 0 -Type DWord
} else {
Write-Host "Enrollment flag already 0 or does not exist"
}