Export Windows Autopilot devices with Graph PowerShell: serial, group tag and profile status
Updated 18 October 2026What changed
Checked against the Microsoft Graph v1.0 and beta windowsAutopilotDeviceIdentity resources, the list and updateDeviceProperties API pages, the Graph PowerShell cmdlet references, and Microsoft's Autopilot device attribute and device group documentation.
On this page14 sections
Short answer: Get-MgDeviceManagementWindowsAutopilotDeviceIdentity calls the Graph v1.0 endpoint, and v1.0 does not have deploymentProfileAssignmentStatus or deploymentProfileAssignedDateTime. Select those properties from the v1.0 cmdlet and you get empty columns, not an error. Use the beta cmdlet, Get-MgBetaDeviceManagementWindowsAutopilotDeviceIdentity, when you need profile assignment data.
This tutorial is for Intune admins who need a reliable export of Windows Autopilot registrations: serial numbers, group tags, profile status, display names and the Intune and Entra records they link to. It covers the v1.0 and beta differences, an export script, filters for the devices that will not deploy, bulk updates of group tags and device names, and a raw REST version for support cases.
Scope and prerequisites
The examples assume:
- An Intune-licensed tenant. Microsoft notes that the Graph API for Intune requires an active Intune licence.
- The Microsoft Graph PowerShell SDK, with these modules:
Microsoft.Graph.AuthenticationforConnect-MgGraphandInvoke-MgGraphRequestMicrosoft.Graph.DeviceManagement.Enrollmentfor the v1.0 cmdletsMicrosoft.Graph.Beta.DeviceManagement.Enrollmentfor the beta cmdlet that returns profile statusMicrosoft.Graph.DeviceManagement, only for the managed device lookup in the display name section
- An account or app with
DeviceManagementServiceConfig.Read.Allfor reading. Updating group tags or device names needsDeviceManagementServiceConfig.ReadWrite.All. Do not request the write scope for a read-only export.
Output shown in this article is placeholder shape only. Replace <serial-number>, <group-tag> and similar values with your own.
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.DeviceManagement.Enrollment -Scope CurrentUser
Install-Module Microsoft.Graph.Beta.DeviceManagement.Enrollment -Scope CurrentUser
Install-Module Microsoft.Graph.DeviceManagement -Scope CurrentUserv1.0 versus beta: which properties you actually get
This is the table to keep open. It comes from Microsoft's v1.0 and beta resource definitions.
| Property | API | Notes |
|---|---|---|
serialNumber, manufacturer, model | v1.0 and beta | Hardware identity from the import |
groupTag | v1.0 and beta | Maps to the OrderID attribute used in dynamic group rules |
purchaseOrderIdentifier | v1.0 and beta | Maps to PurchaseOrderId in dynamic group rules |
enrollmentState | v1.0 and beta | v1.0 values: unknown, enrolled, pendingReset, failed, notContacted. Beta adds blocked |
lastContactedDateTime | v1.0 and beta | Last Intune contact for the Autopilot record |
displayName | v1.0 and beta | The Device name field on the Autopilot record. See the display name section below |
userPrincipalName, addressableUserName | v1.0 and beta | Populated when a user is assigned to the device |
managedDeviceId | v1.0 and beta | Links to the Intune managed device once enrolled |
azureActiveDirectoryDeviceId | v1.0 and beta | Marked "to be deprecated". Beta adds azureAdDeviceId |
deploymentProfileAssignmentStatus | Beta only | unknown, assignedInSync, assignedOutOfSync, assignedUnkownSyncState, notAssigned, pending, failed |
deploymentProfileAssignedDateTime | Beta only | When the profile was set |
deploymentProfileAssignmentDetailedStatus | Beta only | For example hardwareRequirementsNotMet |
remediationState, userlessEnrollmentStatus | Beta only | Beta-only operational fields |
assignedUnkownSyncState is spelled that way in the API. If you filter on it, match Microsoft's spelling, not the dictionary one.
Microsoft supports the Intune beta APIs but says they are subject to more frequent change, and recommends v1.0 when possible. A sensible split: use v1.0 for anything that only needs serial, group tag and enrolment state, and use beta only for profile assignment fields.
Step 1: Connect with the least privilege you need
Connect-MgGraph -Scopes "DeviceManagementServiceConfig.Read.All" -NoWelcome
Get-MgContext | Select-Object Account, TenantId, ScopesExpected output shape:
Account TenantId Scopes
------- -------- ------
<admin>@<tenant-domain> <tenant-id> {DeviceManagementServiceConfig.Read.All, openid, profile...}If Scopes does not include the permission, stop. Every later call returns a permissions error, and in a large script that is easy to misread as "no devices found".
Step 2: Export every Autopilot device to CSV
-All follows paging for you. Without it you only get the first page of results, which looks like a complete list in a small test tenant and silently truncates in a real one.
$devices = Get-MgBetaDeviceManagementWindowsAutopilotDeviceIdentity -All
$devices |
Select-Object SerialNumber, Manufacturer, Model, GroupTag,
PurchaseOrderIdentifier, EnrollmentState,
DeploymentProfileAssignmentStatus,
@{ n = 'ProfileAssignedUtc'; e = { $_.DeploymentProfileAssignedDateTime } },
@{ n = 'LastContactedUtc'; e = { $_.LastContactedDateTime } },
DisplayName, UserPrincipalName, ManagedDeviceId, AzureAdDeviceId, Id |
Export-Csv -Path .\autopilot-devices.csv -NoTypeInformation -Encoding utf8
"Exported {0} Autopilot devices" -f $devices.CountExpected output shape:
Exported <count> Autopilot devicesCompare that count with the Windows Autopilot devices total in the Intune admin centre. If they differ, check you used -All and that you are signed in to the right tenant.
If you must stay on v1.0, use Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -All and remove the three DeploymentProfile* columns and AzureAdDeviceId from the Select-Object. Leaving them in just produces empty columns that look like data.
Step 3: Find one device by serial or a group by tag
The filters below run in PowerShell after the export. That is slower than a server-side filter, but it behaves the same in every tenant and is easy to audit.
$serial = '<serial-number>'
$devices | Where-Object SerialNumber -eq $serial |
Format-List SerialNumber, GroupTag, EnrollmentState,
DeploymentProfileAssignmentStatus, DeploymentProfileAssignedDateTime,
DisplayName, ManagedDeviceIdExpected output shape:
SerialNumber : <serial-number>
GroupTag : <group-tag or blank>
EnrollmentState : notContacted
DeploymentProfileAssignmentStatus : assignedInSync
DeploymentProfileAssignedDateTime : <date/time>
DisplayName : <device name or blank>
ManagedDeviceId : <blank until enrolled>For a whole batch by group tag:
$tag = '<group-tag>'
$devices | Where-Object GroupTag -eq $tag |
Group-Object DeploymentProfileAssignmentStatus |
Select-Object Name, CountA blank or misspelt GroupTag is a common reason a device never joins the dynamic group that the profile targets. Compare the tags in this output with the exact [OrderID]: value in the group rule.
Step 4: List the devices that will not deploy
A device is ready for a user-driven deployment when it has a profile assigned and in sync. This report lists everything else, oldest first.
$devices |
Where-Object { $_.DeploymentProfileAssignmentStatus -ne 'assignedInSync' } |
Sort-Object LastContactedDateTime |
Select-Object SerialNumber, GroupTag, DeploymentProfileAssignmentStatus,
DeploymentProfileAssignmentDetailedStatus, EnrollmentState |
Format-Table -AutoSizeRead the status column as a routing decision, not a diagnosis:
| Status | What to check first |
|---|---|
notAssigned | Group tag, the dynamic group rule, and whether the profile is assigned to that group |
pending | Nothing yet. Profile assignment is not instant; re-run the report later before changing anything |
assignedOutOfSync or assignedUnkownSyncState | Whether someone recently changed the profile or the group, then re-check |
failed | DeploymentProfileAssignmentDetailedStatus, for example hardwareRequirementsNotMet |
unknown | Re-export. If it persists, open the device in the Intune admin centre |
If notAssigned devices all share one blank or misspelt group tag, fix the tag (Step 6) rather than editing the dynamic group. For import-side failures, such as rows that never appear at all, use Autopilot device not importing.
Display name versus computer name
People often search for windowsAutopilotDeviceIdentity displayName "computer name" because the two are easy to confuse.
displayNameis the Device name field on the Autopilot device record. You can edit it in Devices > Windows > Windows enrollment > Devices or withupdateDeviceProperties. Microsoft's Autopilot device attribute documentation notes that device names can be set for all devices but are ignored for Microsoft Entra hybrid join, where the name comes from the domain join profile.- The computer name of an enrolled device lives on the Intune managed device record. Use
managedDeviceIdto read it rather than trusting the AutopilotdisplayName.
Connect-MgGraph -Scopes "DeviceManagementServiceConfig.Read.All","DeviceManagementManagedDevices.Read.All" -NoWelcome
$devices | Where-Object ManagedDeviceId | ForEach-Object {
$managed = Get-MgDeviceManagementManagedDevice -ManagedDeviceId $_.ManagedDeviceId
[pscustomobject]@{
SerialNumber = $_.SerialNumber
AutopilotName = $_.DisplayName
IntuneDeviceName = $managed.DeviceName
NamesMatch = $_.DisplayName -eq $managed.DeviceName
}
} | Where-Object { -not $_.NamesMatch } | Format-Table -AutoSizeExpected output shape:
SerialNumber AutopilotName IntuneDeviceName NamesMatch
------------ ------------- ---------------- ----------
<serial-number> <computer-name> FalseA blank AutopilotName is normal when you use a naming template in the deployment profile instead of per-device names. This report makes one call per enrolled device, so run it against a filtered list in large tenants.
Step 5: Raw REST for support cases
Support engineers often ask for the raw JSON. Invoke-MgGraphRequest returns hashtables by default, so Select-Object prints empty columns; ask for PSObject output instead, and follow @odata.nextLink so you do not stop at the first page.
$uri = 'https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeviceIdentities'
$all = while ($uri) {
$page = Invoke-MgGraphRequest -Method GET -Uri $uri -OutputType PSObject
$page.value
$uri = $page.'@odata.nextLink'
}
$all | Where-Object serialNumber -eq '<serial-number>' |
ConvertTo-Json -Depth 3 | Set-Content .\autopilot-device.jsonCheck the JSON before attaching it to a case. It contains the serial number, product key field, user principal name and object IDs.
Step 6: Bulk-update group tags or device names
This step writes to the tenant. Reconnect with the write scope only for this step, and run it with -WhatIf first.
Prepare a CSV with exactly these headers:
SerialNumber,GroupTag
<serial-number-1>,<new-group-tag>
<serial-number-2>,<new-group-tag>Connect-MgGraph -Scopes "DeviceManagementServiceConfig.ReadWrite.All" -NoWelcome
$changes = Import-Csv .\group-tag-changes.csv
$bySerial = @{}
Get-MgDeviceManagementWindowsAutopilotDeviceIdentity -All |
ForEach-Object { $bySerial[$_.SerialNumber] = $_ }
foreach ($row in $changes) {
$device = $bySerial[$row.SerialNumber]
if (-not $device) { Write-Warning "Not registered: $($row.SerialNumber)"; continue }
if ($device.GroupTag -ceq $row.GroupTag) { continue }
Update-MgDeviceManagementWindowsAutopilotDeviceIdentityDeviceProperty `
-WindowsAutopilotDeviceIdentityId $device.Id `
-BodyParameter @{ groupTag = $row.GroupTag } -WhatIf
}When the -WhatIf output lists only the devices you expect, remove -WhatIf and run it again. To set device names instead, use a DisplayName column and @{ displayName = $row.DisplayName }, and remember names are ignored for hybrid join.
The update sends only the property you include. After the change, the dynamic group based on OrderID has to re-evaluate and the profile has to reassign. Re-run Step 4 later instead of assuming the change took effect immediately.
Validation checklist
-
Get-MgContextshows the expected tenant and only the scopes this task needs - The export count matches the Windows Autopilot devices total in the Intune admin centre
- Profile status columns are populated, which proves you used the beta cmdlet
- Devices that are not
assignedInSyncare explained by group tag, group rule or profile assignment - Bulk updates ran with
-WhatIffirst and the change list was reviewed - Exported files containing serials and UPNs are stored and deleted like any other device inventory
Common mistakes
| Mistake | What you see | Fix |
|---|---|---|
| Selecting profile status from the v1.0 cmdlet | Empty DeploymentProfileAssignmentStatus column | Use Get-MgBetaDeviceManagementWindowsAutopilotDeviceIdentity |
Forgetting -All | Counts that stop at a page boundary | Add -All, or follow @odata.nextLink in raw REST |
Raw REST without -OutputType PSObject | Select-Object shows blank columns | Add -OutputType PSObject |
Treating displayName as the live computer name | Names that do not match devices in Intune | Read DeviceName from the managed device via managedDeviceId |
| Fixing tags by editing the dynamic group | Group rule grows exceptions | Correct the groupTag on the device records instead |
| Requesting ReadWrite for a report | Over-privileged automation account | Use Read.All for exports; ReadWrite only for Step 6 |
When not to use this approach
- Unattended production automation on beta. Beta properties can change. If a scheduled job only needs serial, tag and enrolment state, use v1.0 and keep the beta call in an interactive report.
- As proof that a device will deploy.
assignedInSyncmeans a profile is assigned. It does not prove the Enrollment Status Page, apps or join will succeed; see Autopilot Enrollment Status Page stuck. - Windows Autopilot device preparation. Device preparation does not depend on Autopilot registration or deployment profiles in the same way, so profile status is not the right health signal there. See Autopilot v1 vs Device Preparation v2.
Related Resources
- Autopilot device not importing
- Autopilot Enrollment Status Page stuck
- Autopilot v1 vs Device Preparation v2
- Migrating from AzureAD and MSOnline to Microsoft Graph PowerShell
- Microsoft Intune hub
- PowerShell hub
Primary Sources
- windowsAutopilotDeviceIdentity resource type (v1.0)
- windowsAutopilotDeviceIdentity resource type (beta)
- List windowsAutopilotDeviceIdentities
- updateDeviceProperties action
- Get-MgDeviceManagementWindowsAutopilotDeviceIdentity
- Edit Windows Autopilot device attributes
- Create device groups for Windows Autopilot
Microsoft Intune
Product linkManage, secure, and report on all your endpoints from a single cloud-native console.
This is a Microsoft product link, not an advert and not an affiliate placement. AdminSignal has no affiliate arrangement for Intune.
Jack Hadcroft
LinkedInBand 6 Endpoint Specialist and author of AdminSignal
Technical claims are reviewed against current Microsoft documentation. Lab or tenant checks are named only when they were done.
Independent publication. About · Editorial policy