Automate device groups based on discovered apps with PowerShell and Intune
This will be a shorter post than normal. Just a quickly put together script that I found useful.
I imagine many Intune admins have been asked in the past "We need a count of all devices with Adobe Acrobat installed, can you get us a list of devices?"
If the software is managed by Intune, then sure no problem. We can see in the Intune portal all the devices that have installed said app via company portal.
However, I have not found a streamlined way to create a device group with this information. So, I wrote something up that hopefully makes our lives that much easier.
I will breakdown the script, so we understand how it works, it's fairly simple.
First some requirements:
Required Powershell Modules:
Name Version
---- -------
Microsoft.Graph.Authentication 2.15.0
Microsoft.Graph.Beta.DeviceManagement 2.15.0
Microsoft.Graph.Beta.Groups 2.15.0
Microsoft.Graph.Beta.Identity.DirectoryManagement 2.15.0
Required Microsoft Graph API Permissions:
- DeviceManagementConfiguration.ReadWrite.All
- DeviceManagementManagedDevices.ReadWrite.All
- Directory.ReadWrite.All
- Group.ReadWrite.All
- GroupMember.ReadWrite.All
- Device.ReadWrite.All
We will be using the 'Discovered Apps' blade within Intune as reference.
Now, we'd want to retrieve all detected installations of "Adobe Acrobat (64-bit)"
$DetectedInstalls = Get-MgBetaDeviceManagementDetectedApp -Filter "displayname eq 'Adobe Acrobat (64-bit)'"
Next, we will retrieve the associated device name(s) of the detected installs.
$DetectedInstallHostnames = $DetectedInstalls | ForEach-Object {
$DetectedInstall = $_
Get-MgBetaDeviceManagementDetectedAppManagedDevice -DetectedAppId $DetectedInstall.id -ErrorAction Stop | Select-Object DeviceName
}
Next, we check for an existing group, and create it if needed.
# Define group details
$GroupName = "$($AppDisplayName -replace '[^a-zA-Z0-9]', '')_Installed_Devices" # Remove space and characters for MailNickname
$GroupDescription = "Devices with [$AppDisplayName] installed"
# Check if the group already exists
$Group = Get-MgBetaGroup -Filter "displayName eq '$GroupName'" -ErrorAction Stop | Select-Object -First 1
# Create the group if it doesn't exist
if (-not $Group) {
$GroupParams = @{
DisplayName = $GroupName
Description = $GroupDescription
MailEnabled = $false
MailNickname = $GroupName
SecurityEnabled = $true
GroupTypes = @()
}
$Group = New-MgBetaGroup @GroupParams
Write-Host "Group '$GroupName' created."
}
Next, we gather all existing group members and add or remove devices from the group depending on if they are in the detected installs object.
# Get current members of the group
$CurrentGroupMembers = Get-MgBetaGroupMember -GroupId $Group.Id -ErrorAction Stop | ForEach-Object { Get-MgBetaDevice -DeviceId $_.Id -ErrorAction Stop }
# Loop through detected installations to add devices to the group
$DetectedInstallHostnames | ForEach-Object {
$DetectedInstallHostname = $_
# Check if the device is already a member of the group
$IsInGroup = $CurrentGroupMembers | Where-Object { $_.DisplayName -eq $DetectedInstallHostname.DeviceName }
# Add the device to the group if it's not already a member
if (-not $IsInGroup) {
$deviceObject = Get-MgBetaDevice -Filter "displayname eq '$($DetectedInstallHostname.DeviceName)'" -ErrorAction Stop
New-MgBetaGroupMember -GroupId $group.Id -DirectoryObjectId $deviceObject.id -ErrorAction Stop
Write-Host "Added $($DetectedInstallHostname.DeviceName) to group '$GroupName'."
}
}
# Clean up: Remove devices from the group if they no longer have the app installed
$CurrentGroupMembers | ForEach-Object {
$GroupMember = $_
$IsStillDetected = $DetectedInstallHostnames | Where-Object { $_.DeviceName -eq $GroupMember.DisplayName }
# Remove the device from the group if it's no longer detected
if (-not $IsStillDetected) {
$deviceObject = Get-MgBetaDevice -Filter "displayname eq '$($GroupMember.DisplayName)'" -ErrorAction Stop
Remove-MgBetaGroupMemberByRef -GroupId $group.Id -DirectoryObjectId $deviceObject.id -ErrorAction Stop
Write-Host "Removed $($GroupMember.DisplayName) from group '$GroupName' as '$AppDisplayName' is no longer detected."
}
}
This could be set up to run via an Azure App registration for automated updating, or just ran manually in one off scenarios. Please use as best fits your needs.
For the full script see below: