Intune: Assignment Filters Summary Report

Assignment filters in Intune allow you to narrow the assignment scope of policies. For example, you can create an assignment filter that includes only devices that are enrolled in Intune, run Windows 10, and have a specific hardware model. You can then assign a configuration profile or an app to All devices with this filter in include mode, and only the devices that match the criteria will receive the assignment. This way, you can ensure that your assignments are relevant and appropriate for your devices and users. Further you can use Associated Assignments tab in each Assignment Filter to review the associated assignments.

Each tenant can create and use up to 200 Assignment Filters and for some organizations, this count might be quickly reached. Having a nice report of all Assignment Filters along with the rule and associated assignments would help IT Admins to manage them efficiently on a periodic basis. Here is a PowerShell script leveraging Graph API to provide the functionality.

The script exports the data in HTML format for review and corresponding CSVs to play with. You can configure $ReportPath variable in Line #15 and you will find three files in the path for every run.

The report will have a summary table of all Assignment Filters in the tenant with filter type, platform, rule and associated assignments count along with other common fields. A second table will list all associated assignments details for each filter with payload id, payload name, payload type and intent.

Note: In all my sample scripts, I use delegated permissions. If you to run the script unattended in any automation tool, modify the script to levarge a client app registration along with a client secret – see Connect To Microsoft Graph PowerShell With a Client Secret (ourcloudnetwork.com) for details on how to do this.

The script requires Microsoft Graph PowerShell modules. You can install these using the commands below. Refer to Install the Microsoft Graph PowerShell SDK documentation for more info.

Install-Module Microsoft.Graph
Install-Module Microsoft.Graph.Beta
<#
DISCLAIMER STARTS 
THIS SAMPLE CODE IS PROVIDED FOR THE PURPOSE OF ILLUSTRATION ONLY AND IS NOT INTENDED TO BE USED IN A PRODUCTION ENVIRONMENT. THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED IS "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE."
DISCLAIMER ENDS
#>


$Head = "<style>"
$Head +="BODY{background-color:#CCCCCC;font-family:Calibri,sans-serif; font-size: small;}"
$Head +="TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse; width: 98%;}"
$Head +="TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:#293956;color:white;padding: 5px; font-weight: bold;text-align:left;}"
$Head +="TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:#F0F0F0; padding: 2px;}"
$Head +="</style>"

$Now = Get-Date -Format "dd-MM-yyyy-HH-mm-ss"
$ReportPath = "C:\Windows\Temp\"

$Stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
#Connect to Microsoft Graph using delegated permissions
Write-Output "Connecting Microsoft Graph..."
Connect-MgGraph -scopes Group.Read.All, DeviceManagementManagedDevices.Read.All, DeviceManagementServiceConfig.Read.All, DeviceManagementApps.Read.All, DeviceManagementApps.Read.All, DeviceManagementConfiguration.Read.All, DeviceManagementConfiguration.Read.All, DeviceManagementApps.Read.All
#Get all Assigment Filters
$AssignmentFilters = Get-MgBetaDeviceManagementAssignmentFilter -All

#Get all Intune Payloads in the tenant
$AllPayloads = @()
$Workloads = `
"https://graph.microsoft.com/beta/deviceManagement/deviceCompliancePolicies",
"https://graph.microsoft.com/beta/deviceManagement/configurationPolicies",
"https://graph.microsoft.com/beta/deviceAppManagement/mobileApps",
"https://graph.microsoft.com/beta/deviceAppManagement/targetedManagedAppConfigurations",
"https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts",
"https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles",
"https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts",
"https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations",
"https://graph.microsoft.com/beta/deviceManagement/groupPolicyConfigurations",
"https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations",
"https://graph.microsoft.com/beta/deviceAppManagement/iosManagedAppProtections",
"https://graph.microsoft.com/beta/deviceAppManagement/androidManagedAppProtections",
"https://graph.microsoft.com/beta/deviceAppManagement/windowsManagedAppProtections",
"https://graph.microsoft.com/beta/deviceAppManagement/mdmWindowsInformationProtectionPolicies"
$c = 1
foreach ($Workload in $Workloads){
		Write-Progress -Activity "Getting all configurations in the tenant.." -Status "Processing $Workload" -PercentComplete $($c*100/$($Workloads.count))
		$uri = $Workload
		$AllPayloads += (Invoke-MgGraphRequest -Method GET -Uri $uri).Value
		$c++
}

#Initialize few variables
$AFResults = @()
$PSObject = @()
$Set = 1

#Loop all Assignment Filters to get payload information. Currently JSON batching supports only 20 requests at a time. So breaking down the total Assignment Filters by set of 20 each and getting the Payload Information and storing the output in $AFResults array.

Write-Output "Getting Payload Information of all Assignment Filters..."

For ($n = 1; $n -le $AssignmentFilters.count; $n++){
	Write-Progress -Activity "Getting Payload Information of all Assignment Filters..." -Status "Processing $n out of $AssignmentFilters.count" -PercentComplete $($n*100/$AssignmentFilters.count)
	$id = $n - 1
	$AssignmentFilterId = $AssignmentFilters[$id].id
	$PSObject += [PSCustomObject]@{
        id      = "$id"
        method  = "GET"
        url     = "deviceManagement/assignmentFilters/$($AssignmentFilterId)/payloads"
    }
	if (($n -eq $($Set*20)) -or ($n -eq $AssignmentFilters.count)){
		$BatchRequestBody = [PSCustomObject]@{requests = $PSObject }
		$JSONRequests = $BatchRequestBody | ConvertTo-Json -Depth 4
		$AFResults += Invoke-MgGraphRequest -Method POST -Uri 'https://graph.microsoft.com/beta/$batch' -Body $JSONRequests -ContentType 'application/json' -ErrorAction Stop
		$PSObject = @()
		$Set ++
	}
}

#Create Assignment Filter Summary Report

Write-Output "Creating Assignment Filter Summary Report..."
$Filters = $AssociatedAssignments = @()
For ($n = 1; $n -le $AssignmentFilters.count; $n++){
	Write-Progress -Activity "Creating Assignment Filters Summary Report..." -Status "Processing $n out of $AssignmentFilters.count" -PercentComplete $($n*100/$AssignmentFilters.count)
	$id = $n - 1
	$Assignments = ($AFResults.responses | where {$_.id -eq $id}).body.value
	$AssignmentsCount = $Assignments.count
	$Filters += [PSCustomObject]@{
		Id = $AssignmentFilters[$id].id
		ManagementType = $AssignmentFilters[$id].AssignmentFilterManagementType
		DisplayName = $AssignmentFilters[$id].DisplayName
		Description = $AssignmentFilters[$id].Description
		CreatedDateTime = $AssignmentFilters[$id].CreatedDateTime
		LastModifiedDateTime = $AssignmentFilters[$id].LastModifiedDateTime
		Platform = $AssignmentFilters[$id].Platform
		RoleScopeTags = [string]$AssignmentFilters[$id].RoleScopeTags -replace " ",","
		Rule = $AssignmentFilters[$id].Rule
		AssociatedAssignmentsCount = $AssignmentsCount
	}
	If ($AssignmentsCount -gt 0) {
		Foreach ($Assignment in $Assignments){
			$PayloadName = (($AllPayloads | where {$_.id -eq $($Assignment.payloadId)})|select -Unique displayname).displayname
			If (!($PayloadName)){
				$PayloadName = (($AllPayloads | where {$_.id -eq $($Assignment.payloadId)})|select -Unique name).name
			}
			$AssociatedAssignments += [PSCustomObject]@{
				Id = $AssignmentFilters[$id].id
				ManagementType = $AssignmentFilters[$id].AssignmentFilterManagementType
				DisplayName = $AssignmentFilters[$id].DisplayName
				GroupId = $Assignment.groupId
				PayloadId = $Assignment.payloadId
				PayloadName = $PayloadName
				PayloadType = $Assignment.payloadType
				IntentType = $Assignment.assignmentFilterType
			}
		}
	}
}
$ReportOutput += "<h2>Assignment Filters Summary</h2>"
$ReportOutput += $Filters | ConvertTo-Html -Fragment
$Filters | ConvertTo-Csv -NoTypeInformation > $ReportPath\AssignmentFilters_Summary_$($Now).csv

$ReportOutput += "<h2>Assignment Filters Associated Assignments Summary</h2>"
$ReportOutput += $AssociatedAssignments | ConvertTo-Html -Fragment
$AssociatedAssignments | ConvertTo-Csv -NoTypeInformation > $ReportPath\AssignmentFilters_AssociatedAssignments_$($Now).csv

ConvertTo-HTML -head $Head -body "$ReportOutput" | Out-File $ReportPath\AssignmentFilters_Summary_Report_$($Now).htm
Invoke-Item $ReportPath\AssignmentFilters_Summary_Report_$($Now).htm

$Stopwatch.Stop()

Write-Output "Time Taken for the script execution with batching:`n"

$Stopwatch.Elapsed

2 thoughts on “Intune: Assignment Filters Summary Report

  1. Hmm, Modules installed fine but get the below when running Get-MgBetaDeviceManagementAssignmentFilter
    Get-MgBetaDeviceManagementAssignmentFilter : One or more errors occurred.
    At line:1 char:1
    + Get-MgBetaDeviceManagementAssignmentFilter
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-MgBetaDevic…mentFilter_List], AggregateException
    + FullyQualifiedErrorId : System.AggregateException,Microsoft.Graph.Beta.PowerShell.Cmdlets.GetMgBetaDeviceManagementAssignmentFilter_List

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.