Public/Get-IntuneAutopilotStatus.ps1
|
function Get-IntuneAutopilotStatus { <# .SYNOPSIS Reports on Windows Autopilot device registration and deployment profile status. .DESCRIPTION Enumerates Autopilot registered devices, checks deployment profile assignments, identifies devices without profiles, devices with failed deployments, and devices with mismatched group tags. Useful for pre-deployment readiness checks. .PARAMETER IncludeDeploymentProfiles Include deployment profile details in the report. Defaults to true. .EXAMPLE Get-IntuneAutopilotStatus #> [CmdletBinding()] param( [Parameter()] [bool]$IncludeDeploymentProfiles = $true ) begin { Test-GraphConnection $results = [System.Collections.Generic.List[PSObject]]::new() } process { # Get Autopilot devices try { $autopilotDevices = Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -All -Property @( 'id', 'serialNumber', 'model', 'manufacturer', 'groupTag', 'purchaseOrderIdentifier', 'enrollmentState', 'lastContactedDateTime', 'deploymentProfileAssignmentStatus', 'deploymentProfileAssignedDateTime' ) -ErrorAction Stop } catch { Write-Warning "Unable to read Autopilot devices. Ensure you have DeviceManagementServiceConfig.Read.All permission." return } # Get deployment profiles for reference $profileMap = @{} if ($IncludeDeploymentProfiles) { try { $deploymentProfiles = Invoke-MgGraphRequest -Method GET ` -Uri 'https://graph.microsoft.com/v1.0/deviceManagement/windowsAutopilotDeploymentProfiles' ` -ErrorAction Stop foreach ($dp in $deploymentProfiles.value) { $profileMap[$dp.id] = $dp.displayName } } catch { Write-Verbose "Unable to retrieve deployment profiles." } } foreach ($device in $autopilotDevices) { $findings = @() # Check enrollment state if ($device.EnrollmentState -and $device.EnrollmentState -ne 'enrolled') { switch ($device.EnrollmentState) { 'notContacted' { $findings += 'NOT YET CONTACTED' } 'requested' { $findings += 'ENROLLMENT REQUESTED' } 'failed' { $findings += 'ENROLLMENT FAILED' } 'enrollmentPending' { $findings += 'ENROLLMENT PENDING' } default { $findings += "STATE: $($device.EnrollmentState)" } } } # Check deployment profile assignment $profileStatus = $device.DeploymentProfileAssignmentStatus if ($profileStatus -and $profileStatus -ne 'assigned') { switch ($profileStatus) { 'notAssigned' { $findings += 'NO DEPLOYMENT PROFILE' } 'pending' { $findings += 'PROFILE ASSIGNMENT PENDING' } 'failed' { $findings += 'PROFILE ASSIGNMENT FAILED' } default { $findings += "PROFILE: $profileStatus" } } } # Check group tag if (-not $device.GroupTag) { $findings += 'NO GROUP TAG' } # Check last contact $daysSinceContact = if ($device.LastContactedDateTime) { [math]::Round(((Get-Date) - $device.LastContactedDateTime).TotalDays) } else { -1 } if ($daysSinceContact -gt 90) { $findings += "STALE ($daysSinceContact days since contact)" } $results.Add([PSCustomObject]@{ SerialNumber = $device.SerialNumber Manufacturer = $device.Manufacturer Model = $device.Model GroupTag = if ($device.GroupTag) { $device.GroupTag } else { '(none)' } PurchaseOrder = if ($device.PurchaseOrderIdentifier) { $device.PurchaseOrderIdentifier } else { '(none)' } EnrollmentState = $device.EnrollmentState ProfileStatus = $profileStatus LastContacted = $device.LastContactedDateTime DaysSinceContact = $daysSinceContact Finding = if ($findings.Count -gt 0) { $findings -join ' | ' } else { 'OK' } }) } } end { $flagged = $results | Where-Object { $_.Finding -ne 'OK' } Write-Host " Autopilot devices scanned: $($results.Count) | Findings: $($flagged.Count)" -ForegroundColor Gray $results | Sort-Object Finding, SerialNumber } } |