diff --git a/articles/windows-mdm-setup.md b/articles/windows-mdm-setup.md index bbe09e7aec..f88cc0cf40 100644 --- a/articles/windows-mdm-setup.md +++ b/articles/windows-mdm-setup.md @@ -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 diff --git a/docs/solutions/windows/scripts/fix-workplace-join-configuration.ps1 b/docs/solutions/windows/scripts/fix-workplace-join-configuration.ps1 new file mode 100644 index 0000000000..48e79dbafe --- /dev/null +++ b/docs/solutions/windows/scripts/fix-workplace-join-configuration.ps1 @@ -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" diff --git a/docs/solutions/windows/scripts/remove-stale-mdm-enrollment-records.ps1 b/docs/solutions/windows/scripts/remove-stale-mdm-enrollment-records.ps1 new file mode 100644 index 0000000000..e94558093e --- /dev/null +++ b/docs/solutions/windows/scripts/remove-stale-mdm-enrollment-records.ps1 @@ -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" diff --git a/docs/solutions/windows/scripts/remove-unreachable-wsus-configuration.ps1 b/docs/solutions/windows/scripts/remove-unreachable-wsus-configuration.ps1 new file mode 100644 index 0000000000..acfe64f095 --- /dev/null +++ b/docs/solutions/windows/scripts/remove-unreachable-wsus-configuration.ps1 @@ -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" +} diff --git a/docs/solutions/windows/scripts/reset-mdm-enrollment-flag.ps1 b/docs/solutions/windows/scripts/reset-mdm-enrollment-flag.ps1 new file mode 100644 index 0000000000..f789b504bd --- /dev/null +++ b/docs/solutions/windows/scripts/reset-mdm-enrollment-flag.ps1 @@ -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" +}