Recently I needed to get a list of devices in both Azure Active Directory and Intune and I found that using the online portals I could not filter devices by the parameters that I needed. So I turned to Microsoft Graph to get the data instead. You can use the Microsoft Graph Explorer to query via the Graph REST API, however, the query capabilities of the API are still somewhat limited. To find the data I needed, I had to query the Graph REST API using PowerShell, where I can take advantage of the greater filtering capabilities of PowerShell’s Where-Object.
To use the Graph API, you need to authenticate first. A cool guy named Dave Falkus has published a number of PowerShell scripts on GitHub that use the Graph API with Intune, and these contain some code to authenticate with the API. Rather than re-invent the wheel, we can use his functions to get the authentication token that we need.
First, we need the AzureRM or Azure AD module installed as we use the authentication libraries that are included with it.
Next, open one of the scripts that Dave has published on GitHub, for example here, and copy the function Get-AuthToken into your script.
The also copy the Authentication code region into your script, ie the section between the following:
#region Authentication ... #endregion
If you run this code it’ll ask you for an account name to authenticate with from your Azure AD. Once authenticated, we have a token we can use with the Graph REST API saved as a globally-scoped variable $authToken.
Get Devices from Azure AD
To get devices from Azure AD, we can use the following function, which I take no credit for as I have simply modified a function written by Dave.
Function Get-AzureADDevices(){ [cmdletbinding()] $graphApiVersion = "v1.0" $Resource = "devices" $QueryParams = "" try { $uri = "https://graph.microsoft.com/$graphApiVersion/$($Resource)$QueryParams" Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get } catch { $ex = $_.Exception $errorResponse = $ex.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($errorResponse) $reader.BaseStream.Position = 0 $reader.DiscardBufferedData() $responseBody = $reader.ReadToEnd(); Write-Host "Response content:`n$responseBody" -f Red Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" write-host break } }
In the $graphAPIVersion parameter, you can use the current version of the API.
Now we can run the following code, which will use the API to return all devices in your Azure AD and save them to them a hash table which organizes the results by operating system version.
# Return the data $ADDeviceResponse = Get-AzureADDevices $ADDevices = $ADDeviceResponse.Value $NextLink = $ADDeviceResponse.'@odata.nextLink' # Need to loop the requests because only 100 results are returned each time While ($NextLink -ne $null) { $ADDeviceResponse = Invoke-RestMethod -Uri $NextLink -Headers $authToken -Method Get $NextLink = $ADDeviceResponse.'@odata.nextLink' $ADDevices += $ADDeviceResponse.Value } Write-Host "Found $($ADDevices.Count) devices in Azure AD" -ForegroundColor Yellow $ADDevices.operatingSystem | group -NoElement $DeviceTypes = $ADDevices.operatingSystem | group -NoElement | Select -ExpandProperty Name $AzureADDevices = @{} Foreach ($DeviceType in $DeviceTypes) { $AzureADDevices.$DeviceType = $ADDevices | where {$_.operatingSystem -eq "$DeviceType"} | Sort displayName } Write-host "Devices have been saved to a variable. Enter '`$AzureADDevices' to view."
It will tell you how many devices it found, and how many devices there are by operating system version / device type.
We can now use the $AzureADDevices hash table to query the data as we wish.
For example, here I search for an iPhone that belongs to a particular user:
$AzureADDevices.Iphone | where {$_.displayName -match 'nik'}
Here I am looking for the count of Windows devices that are hybrid Azure AD joined, and display the detail in the GridView.
($AzureADDevices.Windows | where {$_.trustType -eq 'ServerAd'}).Count $AzureADDevices.Windows | where {$_.trustType -eq 'ServerAd'} | Out-GridView
And here I’m looking for all MacOS devices that are not compliant with policy.
($AzureADDevices.MacOS | where {$_.isCompliant -ne "True"}) | Out-GridView
Get Devices from Intune
To get devices from Intune, we can take a similar approach. Again no credit for this function as its modified from Dave’s code.
Function Get-IntuneDevices(){ [cmdletbinding()] # Defining Variables $graphApiVersion = "v1.0" $Resource = "deviceManagement/managedDevices" try { $uri = "https://graph.microsoft.com/$graphApiVersion/$Resource" (Invoke-RestMethod -Uri $uri -Headers $authToken -Method Get).Value } catch { $ex = $_.Exception $errorResponse = $ex.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($errorResponse) $reader.BaseStream.Position = 0 $reader.DiscardBufferedData() $responseBody = $reader.ReadToEnd(); Write-Host "Response content:`n$responseBody" -f Red Write-Error "Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)" write-host break } }
Running the following code will return all devices in Intune and save them to a hash table again organised by operating system.
$MDMDevices = Get-IntuneDevices Write-Host "Found $($MDMDevices.Count) devices in Intune" -ForegroundColor Yellow $MDMDevices.operatingSystem | group -NoElement $IntuneDeviceTypes = $MDMDevices.operatingSystem | group -NoElement | Select -ExpandProperty Name $IntuneDevices = @{} Foreach ($IntuneDeviceType in $IntuneDeviceTypes) { $IntuneDevices.$IntuneDeviceType = $MDMDevices | where {$_.operatingSystem -eq "$IntuneDeviceType"} | Sort displayName } Write-host "Devices have been saved to a variable. Enter '`$IntuneDevices' to view."
Now we can query data using the $IntuneDevices variable.
Here I am querying for the count of compliant and non-compliant iOS devices.
$IntuneDevices.iOS | group complianceState -NoElement
Here I am querying for all non-compliant iOS devices, specifying the columns I want to see, sort the results and outputting into table format.
$IntuneDevices.iOS | where {$_.complianceState -eq "noncompliant"} | Select userDisplayName,deviceName,imei,managementState,complianceGracePeriodExpirationDateTime | Sort userDisplayName | ft
All Windows devices sorted by username:
$IntuneDevices.Windows | Select userDisplayName,deviceName | Sort userDisplayName
Windows devices managed by SCCM:
$IntuneDevices.Windows | where {$_.managementAgent -eq "ConfigurationManagerClientMdm"} | Out-GridView
Windows devices enrolled using Windows auto enrollment:
$IntuneDevices.Windows | where {$_.deviceEnrollmentType -eq "windowsAutoEnrollment"} | Out-GridView
Windows devices enrolled by SCCM co-management:
$IntuneDevices.Windows | where {$_.deviceEnrollmentType -eq "windowsCoManagement"} | Out-GridView
You can, of course, expand this into users and other resource types, not just devices. You just need the right URL construct for the data type you want to query.
Hi
Anyway we can target windows 7 or windows 10 devices separately?
I need an extract of all win 7 devices only.
Instead of looping through all pages yourself you can pipe Get-AzureADDevices to the command Get-MSGraphAllPages which is part of the Microsoft.Graph.Intune module
Hi, I am trying to find all Azure AD devices and their MDM. But it can be either “Intune” or “Office 365 Mobile” because of problems we had earlier with configuring Intune.
I tried what you have here and it works great to get devices but with Azure AD devices, the ManagementType is MDM. It does not say which one.
How would we go about getting which MDM it is ?
Thanks