Table of Contents
Know What Operating System Used by Entra ID Registered Devices
After reading an article about populating extension attributes for registered devices, a reader asked me how easy it would be to create a report about the operating systems used for registered devices. Microsoft puts a lot of effort into encouraging customers to upgrade to Windows 11 and it’s a good idea to know what’s the device inventory. Of course, products like Intune have the ability to report this kind of information, but it’s more fun (and often more flexible) when you can extract the information yourself.
As it turns out, reporting the operating systems used by registered devices is very easy because the Microsoft Graph reports this information in the set of properties retrieved by the Get-MgDevice cmdlet from the Microsoft Graph PowerShell SDK.
PowerShell Script to Report Entra ID Registered Devices
The script described below creates a report of all registered devices and sorts the output by the last sign in date. Microsoft calls this property ApproximateLastSignInDateTime. As the name indicates, the property stores the approximate date for the last sign in. Entra ID doesn’t update the property every time someone uses the device to connect. I don’t have a good rule for when property updates occur. It’s enough (and approximate) that the date is somewhat accurate for the purpose of identifying if a device is in use, which is why the script sorts devices by that date.
Any Windows device that hasn’t been used to sign into Entra ID in the last six months is likely not active. This isn’t true for mobile phones because they seem to sign in once and never appear again. The report generated for my tenant still has a record for a Windows Phone which last signed in on 2 December 2015. I think I can conclude that it’s safe to remove this device from my inventory.
Figuring Out Device Owners
In the last script I wrote using the Get-MgDevice cmdlet, I figured out the owner of the device by extracting the user identifier from the PhysicalIds property. While this approach works, it’s complicated. A much better approach is to use the Get-MgDeviceRegisteredOwner cmdlet which returns the user identifier for the user account of the registered owner. With this identifier, we can retrieve any account property that makes sense, such as the display name, user principal name, department, city, and country. You could easily add other properties that make sense to your organization. See this article for more information about using the Get-MgUser cmdlet to interact with user accounts.
The Big Caveat About Operating System Information
The problem that exists in using registered devices to report operating system information is that it’s not accurate. The operating system details noted for a device are accurate at the point of registration but degrade over time. If you want to generate accurate reports, you need to use the Microsoft Graph API for Intune.
With that caveat in mind, here’s the code to report the operating system information for Entra ID registered devices:
Connect-MgGraph -Scope User.Read.All, Directory.Read.All Write-Host "Finding registered devices" [array]$Devices = Get-MgDevice -All -PageSize 999 If (!($Devices)) { Write-Host "No registered devices found - exiting" ; break } Write-Host ("Processing details for {0} devices" -f $Devices.count) $Report = [System.Collections.Generic.List[Object]]::new() $i = 0 ForEach ($Device in $Devices) { $i++ Write-Host ("Reporting device {0} ({1}/{2})" -f $Device.DisplayName, $i, $Devices.count) $DeviceOwner = $Null Try { [array]$OwnerIds = Get-MgDeviceRegisteredOwner -DeviceId $Device.Id $DeviceOwner = Get-MgUser -UserId $OwnerIds[0].Id -Property Id, displayName, Department, OfficeLocation, City, Country, UserPrincipalName} } Catch {} $ReportLine = [PSCustomObject][Ordered]@{ Device = $Device.DisplayName Id = $Device.Id LastSignIn = $Device.ApproximateLastSignInDateTime Owner = $DeviceOwner.DisplayName OwnerUPN = $DeviceOwner.UserPrincipalName Department = $DeviceOwner.Department Office = $DeviceOwner.OfficeLocation City = $DeviceOwner.City Country = $DeviceOwner.Country "Operating System" = $Device.OperatingSystem "O/S Version" = $Device.OperatingSystemVersion Registered = $Device.RegistrationDateTime "Account Enabled" = $Device.AccountEnabled DeviceId = $Device.DeviceId TrustType = $Device.TrustType } $Report.Add($ReportLine) } #End Foreach Device # Sort in order of last signed in date $Report = $Report | Sort-Object {$_.LastSignIn -as [datetime]} -Descending $Report | Out-GridView
Figure 1 is an example of the report as viewed through the Out-GridView cmdlet.

You can download the latest version of the script from GitHub.
An Incomplete Help
I’ve no idea whether this script will help anyone. It’s an incomplete answer to a question. However, even an incomplete answer can be useful in the right circumstances. After all, it’s just PowerShell, so use the code as you like.
Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.
Your script was very much of help, thank you Tony.
For my use case, I needed to filter out certain security groups in order to get more specific results. Thought I’d share in case someone else needs has a similar need:
# Define the Object IDs of the security groups you want to filter for
$SecurityGroupIds = @(
“Group_objectID_here”, #Groupname 1
“Group_objectID_here”, #Groupname 2
)
…
# Loop through each device in the array
ForEach ($Device in $Devices) {
$i++
# Display a message indicating the current device being processed
Write-Host (“Reporting device {0} ({1}/{2}” -f $Device.DisplayName, $i, $Devices.count)
# Initialize a variable to store the device owner’s details
$DeviceOwner = $Null
Try {
# Get an array of registered owner IDs for the current device
[array]$OwnerIds = Get-MgDeviceRegisteredOwner -DeviceId $Device.Id
# Get the user details for the first registered owner
$DeviceOwner = Get-MgUser -UserId $OwnerIds[0].Id
# Check if the device owner is a member of any of the specified security groups
$IsMember = $false
$UserGroups = Get-MgUserMemberOf -UserId $DeviceOwner.Id
foreach ($group in $UserGroups) {
if ($SecurityGroupIds -contains $group.Id) {
$IsMember = $true
break
}
}
# If the owner is not a member of any of the security groups, skip processing this device
if (!$IsMember) {
Write-Host (“Device owner is not a member of any of the specified security groups – skipping”)
continue
}
}
Catch {}
…