Checklist
Graph API / inventory export checklist
Based on the article: Automating Intune device reports with Microsoft Graph PowerShell · 4 min read
The device list in the Intune admin center is fine for a quick look, but a weekly inventory, a stale-device list or a noncompliance report is easier to produce from a script. In this post I'll build that script step by step with the Microsoft Graph PowerShell SDK, then make it run unattended with a certificate.
Before you start
- PowerShell 7 (recommended) or Windows PowerShell 5.1.
- The
Microsoft.Graph.DeviceManagementmodule, or the fullMicrosoft.GraphSDK. - The Graph permission
DeviceManagementManagedDevices.Read.All. It's the least-privileged permission for listing managed devices and exists as both a delegated and an application permission. - For interactive runs, an account with an Intune role that can read devices, such as Read Only Operator.
- An active Intune licence in the tenant, which the Intune Graph API requires.
Checklist
- 1
Install the module and connect
powershellInstall-Module Microsoft.Graph.DeviceManagement -Scope CurrentUser Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All" -NoWelcome Get-MgContext | Select-Object Account, Scopes - 2
Export the inventory
Ask only for the properties you need, and always add
-All; without it you only get the first page of results.powershell$props = 'id','deviceName','userPrincipalName','operatingSystem','osVersion', 'complianceState','lastSyncDateTime','enrolledDateTime', 'managedDeviceOwnerType','serialNumber','model','manufacturer' $devices = Get-MgDeviceManagementManagedDevice -All -Property $props $devices | Select-Object DeviceName, UserPrincipalName, OperatingSystem, OsVersion, ComplianceState, LastSyncDateTime, EnrolledDateTime, ManagedDeviceOwnerType, SerialNumber, Model, Manufacturer | Export-Csv -Path .\IntuneDevices.csv -NoTypeInformation -Encoding UTF8For a quick summary in the console before you open the CSV:
powershell$devices | Group-Object OperatingSystem, ComplianceState -NoElement | Sort-Object Count -Descending - 3
Find stale devices
The inventory is already in memory, so filter it locally instead of calling Graph again:
powershell$cutoff = (Get-Date).AddDays(-30) $devices | Where-Object { $_.LastSyncDateTime -lt $cutoff } | Sort-Object LastSyncDateTime | Select-Object DeviceName, UserPrincipalName, OperatingSystem, LastSyncDateTime | Export-Csv -Path .\StaleDevices.csv -NoTypeInformation -Encoding UTF8 - 4
List noncompliant devices
complianceStatesupportseqandorin a server-side filter. Its values includecompliant,noncompliant,conflict,error,inGracePeriodandconfigManager.powershell$nonCompliant = Get-MgDeviceManagementManagedDevice -All -Property $props ` -Filter "complianceState eq 'noncompliant'" $nonCompliant | Group-Object OperatingSystem | Select-Object Name, Count - 5
Run it unattended with a certificate
Scheduled runs shouldn't depend on someone signing in. Use app-only authentication:
- Register an app in Microsoft Entra ID and upload the public key of a certificate (
.cer,.pemor.crt). - Add the application permission
DeviceManagementManagedDevices.Read.Alland grant admin consent. - Install the certificate, with its private key, in the certificate store of the account that runs the scheduled task.
- Connect with the app's client ID, your tenant ID and the certificate thumbprint:
powershell$connect = @{ ClientId = '00000000-0000-0000-0000-000000000000' # application (client) ID TenantId = '11111111-1111-1111-1111-111111111111' # directory (tenant) ID CertificateThumbprint = 'YOUR-CERTIFICATE-THUMBPRINT' } Connect-MgGraph @connect -NoWelcome (Get-MgContext).AuthType # returns AppOnly - Register an app in Microsoft Entra ID and upload the public key of a certificate (
- 6
Schedule it and keep a history
Save the script, stamp each export with the date so you can compare weeks, and run it from Task Scheduler under the account that holds the certificate. Use full paths, because a scheduled task doesn't start in your script folder:
powershell$stamp = Get-Date -Format 'yyyy-MM-dd' $path = Join-Path $PSScriptRoot "IntuneDevices-$stamp.csv" # use as -Path in step 2 # Task Scheduler action # Program: pwsh.exe # Arguments: -NoProfile -NonInteractive -File C:\Scripts\Get-IntuneDeviceReport.ps1
Verify
Get-MgContextshows the scope you asked for, orAppOnlyfor the scheduled run.$devices.Countis in line with the total under Devices › All devices in the Intune admin center.- The CSV opens with one row per device, populated columns and sensible
LastSyncDateTimevalues.
Tips & gotchas
- Paging:
-Allfollows every page for you.-PageSizeonly changes how many records each request returns. - Throttling: Graph answers bursts with HTTP 429 and a
Retry-Afterheader, and Microsoft's guidance notes the Graph SDKs already include retry handlers that honour it. The best protection is fewer calls: pull the list once and filter locally rather than querying device by device. - Unselected means empty: with
-Property, anything you didn't request comes back blank. A few properties are only populated when you get a single device rather than the list. - Time zones: Graph timestamps are in UTC, so allow for that when you choose cut-offs or share reports with colleagues elsewhere.
- SDK v2:
Select-MgProfileno longer exists. Beta cmdlets live in theMicrosoft.Graph.Betamodule, for exampleGet-MgBetaDeviceManagementManagedDevice.