<# .SYNOPSIS Checks whether a Windows device is ready for Intune automatic enrollment, triggers it if it isn't enrolled yet, and tells you what happened. .DESCRIPTION Reads the join state from dsregcmd, looks for an existing MDM enrollment in the registry, and if the device is Entra joined (or hybrid joined) but not enrolled, runs the same built-in command the "Enable automatic MDM enrollment" Group Policy uses. Then it waits for the result and pulls the matching events from the MDM diagnostics log. Supports -WhatIf. Run it elevated, on the device itself. .PARAMETER UseDeviceCredential Enroll with the device's credential instead of the signed-in user's. Needed when nobody is signed in (for example, co-management scenarios). .PARAMETER WaitSeconds How long to wait for the enrollment to show up before giving up. Default: 120. .EXAMPLE .\Start-IntuneEnrollment.ps1 -WhatIf .EXAMPLE .\Start-IntuneEnrollment.ps1 -UseDeviceCredential -WaitSeconds 300 #> #Requires -RunAsAdministrator [CmdletBinding(SupportsShouldProcess)] param( [switch]$UseDeviceCredential, [ValidateRange(0, 1800)] [int]$WaitSeconds = 120 ) function Get-JoinState { $state = @{} foreach ($line in (& dsregcmd.exe /status)) { if ($line -match '^\s*(\w+)\s*:\s*(.+?)\s*$') { $state[$matches[1]] = $matches[2] } } $state } function Get-MdmEnrollment { # An Intune enrollment lives under this key with ProviderID "MS DM Server". Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\Enrollments' -ErrorAction SilentlyContinue | Get-ItemProperty -ErrorAction SilentlyContinue | Where-Object { $_.ProviderID -eq 'MS DM Server' } | Select-Object -First 1 } $join = Get-JoinState $existing = Get-MdmEnrollment $status = [pscustomobject]@{ ComputerName = $env:COMPUTERNAME EntraJoined = $join['AzureAdJoined'] -eq 'YES' DomainJoined = $join['DomainJoined'] -eq 'YES' Tenant = $join['TenantName'] EnrolledBefore = [bool]$existing EnrolledAfter = [bool]$existing EnrolledUpn = $existing.UPN Result = $null RecentEvents = $null } if ($existing) { $status.Result = 'Already enrolled' return $status } if (-not $status.EntraJoined) { $status.Result = if ($status.DomainJoined) { 'Not ready: domain joined but not hybrid joined yet (check Entra Connect device sync)' } else { 'Not ready: device is not Entra joined' } return $status } $argument = if ($UseDeviceCredential) { '/AutoEnrollMDMUsingAADDeviceCredential' } else { '/AutoEnrollMDM' } if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "deviceenroller.exe /c $argument")) { $status.Result = 'WhatIf' return $status } $started = Get-Date & "$env:windir\System32\deviceenroller.exe" /c $argument Write-Verbose "Enrollment requested with $argument. Waiting up to $WaitSeconds seconds." $deadline = $started.AddSeconds($WaitSeconds) do { Start-Sleep -Seconds 10 $existing = Get-MdmEnrollment } until ($existing -or (Get-Date) -ge $deadline) # Event 75 = auto-enrollment succeeded, 76 = failed (the message carries the error code). $status.RecentEvents = @(Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin'; Id = 75, 76; StartTime = $started } -ErrorAction SilentlyContinue | ForEach-Object { '{0:HH:mm:ss} [{1}] {2}' -f $_.TimeCreated, $_.Id, $_.Message }) $status.EnrolledAfter = [bool]$existing $status.EnrolledUpn = $existing.UPN $status.Result = if ($existing) { 'Enrolled' } elseif ($status.RecentEvents -match '\[76\]') { 'Failed: see RecentEvents' } else { 'No result yet: check the device in Intune in a few minutes' } $status