Private/Add-IntuneWin32AppAssignment.ps1
|
function Add-IntuneWin32AppAssignment { <# .SYNOPSIS Assigns a Win32 app to a group, all users or all devices, optionally with an assignment filter. .DESCRIPTION Uses the mobileApp assign action (POST /deviceAppManagement/mobileApps/{id}/assign, https://learn.microsoft.com/graph/api/intune-apps-mobileapp-assign). The action replaces all assignments of the app, so the existing assignments are read first (GET /deviceAppManagement/mobileApps/{id}/assignments) and sent again; an existing assignment to the same target is replaced by the new one. Targets (https://learn.microsoft.com/graph/api/resources/intune-shared-deviceandappmanagementassignmenttarget): User-Group, Device-Group #microsoft.graph.groupAssignmentTarget (groupId) All-Users #microsoft.graph.allLicensedUsersAssignmentTarget All-Devices #microsoft.graph.allDevicesAssignmentTarget A group is given by ID or display name (looked up with GET /groups; exactly one group must match). An assignment filter is given by ID or display name (GET /deviceManagement/assignmentFilters) and set with deviceAndAppManagementAssignmentFilterId and deviceAndAppManagementAssignmentFilterType (include or exclude). Assignment filters are only in the Graph beta endpoint, so assignments are read and written with beta: reading them with v1.0 and sending them back would drop existing filters. Requires DeviceManagementApps.ReadWrite.All, and Group.Read.All (or GroupMember.Read.All) to look up a group by name. #> [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param ( [Parameter(Mandatory)] [string]$AppId, [Parameter(Mandatory)] [ValidateSet('User-Group', 'Device-Group', 'All-Users', 'All-Devices')] [string]$AssignmentType, [string]$AssignmentGroup, [ValidateSet('required', 'available', 'uninstall')] [string]$Intent = 'required', [string]$FilterRuleType, [string]$FilterRule ) Test-IntuneAppAssignmentSetting -AssignmentType $AssignmentType -AssignmentGroup $AssignmentGroup -Intent $Intent -FilterRuleType $FilterRuleType -FilterRule $FilterRule $GuidPattern = '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$' switch ($AssignmentType) { { $_ -in 'User-Group', 'Device-Group' } { if ($AssignmentGroup -match $GuidPattern) { $GroupId = $AssignmentGroup } else { $Filter = [System.Uri]::EscapeDataString("displayName eq '$($AssignmentGroup.Replace("'", "''"))'") $Groups = @(Get-GraphCollection -Uri "v1.0/groups?`$filter=$Filter&`$select=id,displayName") if ($Groups.Count -ne 1) { throw "Found $($Groups.Count) groups with the display name '$AssignmentGroup'; exactly one is needed. Use the group ID instead." } $GroupId = [string]$Groups[0].id } $Target = [ordered]@{ '@odata.type' = '#microsoft.graph.groupAssignmentTarget'; groupId = $GroupId } } 'All-Users' { $Target = [ordered]@{ '@odata.type' = '#microsoft.graph.allLicensedUsersAssignmentTarget' } } 'All-Devices' { $Target = [ordered]@{ '@odata.type' = '#microsoft.graph.allDevicesAssignmentTarget' } } } if ($FilterRule) { if ($FilterRule -match $GuidPattern) { $FilterId = $FilterRule } else { $Filters = @(Get-GraphCollection -Uri 'beta/deviceManagement/assignmentFilters?$select=id,displayName' | Where-Object { $_.displayName -eq $FilterRule }) if ($Filters.Count -ne 1) { throw "Found $($Filters.Count) assignment filters with the name '$FilterRule'; exactly one is needed. Use the filter ID instead." } $FilterId = [string]$Filters[0].id } $Target['deviceAndAppManagementAssignmentFilterId'] = $FilterId $Target['deviceAndAppManagementAssignmentFilterType'] = $FilterRuleType.ToLowerInvariant() } $Assignment = [ordered]@{ '@odata.type' = '#microsoft.graph.mobileAppAssignment' intent = $Intent target = $Target settings = [ordered]@{ '@odata.type' = '#microsoft.graph.win32LobAppAssignmentSettings' notifications = 'showAll' deliveryOptimizationPriority = 'notConfigured' } } # Keep the existing assignments, except one to the same target $AppUri = "beta/deviceAppManagement/mobileApps/$AppId" $Assignments = [System.Collections.Generic.List[object]]::new() foreach ($Existing in @(Get-GraphCollection -Uri "$AppUri/assignments")) { $ExistingTarget = $Existing.target $SameTarget = ([string]$ExistingTarget.'@odata.type' -eq $Target['@odata.type']) -and ([string]$ExistingTarget.groupId -eq [string]$Target['groupId']) if ($SameTarget) { Write-Verbose "Replacing the existing $($Existing.intent) assignment to the same target." continue } $Assignments.Add([ordered]@{ '@odata.type' = '#microsoft.graph.mobileAppAssignment' intent = $Existing.intent target = $ExistingTarget settings = $Existing.settings }) } $Assignments.Add($Assignment) $Body = @{ mobileAppAssignments = $Assignments.ToArray() } | ConvertTo-Json -Depth 10 -Compress Write-Verbose "Assigning app $AppId ($Intent, $AssignmentType)." $null = Invoke-MgGraphRequest -Method POST -Uri "$AppUri/assign" -Body $Body -ContentType 'application/json' -ErrorAction Stop $Assignment } |