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
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
This does not seem to work the associated payload is never piped out.