fix(assignments): use bulk /assign endpoint for removals on all types

Settings Catalog and other bulk-assign types do not support DELETE on
individual assignments. Removal now reloads existing assignments,
filters out selected targets, sanitizes remaining payloads, and
re-POSTs to <API>/<id>/assign. This mirrors the add flow and works
universally across all supported object types.
This commit is contained in:
2026-04-14 18:50:02 +02:00
parent 814c1d116c
commit 07c25e897a

View File

@@ -648,6 +648,29 @@ elseif($action -eq "Remove assignments")
exit 0 exit 0
} }
# Helper: compute TargetDesc for an assignment
function Get-AssignmentTargetDesc
{
param($Ass)
$tt = $Ass.target."@odata.type"
switch($tt)
{
"#microsoft.graph.groupAssignmentTarget"
{
$grp = $groups | Where-Object { $_.id -eq $Ass.target.groupId } | Select-Object -First 1
return "Include: $(if($grp){$grp.displayName}else{$Ass.target.groupId})"
}
"#microsoft.graph.exclusionGroupAssignmentTarget"
{
$grp = $groups | Where-Object { $_.id -eq $Ass.target.groupId } | Select-Object -First 1
return "Exclude: $(if($grp){$grp.displayName}else{$Ass.target.groupId})"
}
"#microsoft.graph.allLicensedUsersAssignmentTarget" { return "All Users" }
"#microsoft.graph.allDevicesAssignmentTarget" { return "All Devices" }
default { return "Unknown" }
}
}
# Execute # Execute
$success = 0 $success = 0
$failed = 0 $failed = 0
@@ -657,15 +680,42 @@ elseif($action -eq "Remove assignments")
if($objAssignments.Count -eq 0) { continue } if($objAssignments.Count -eq 0) { continue }
Write-Host "`nProcessing: $($obj."$($objectType.NameProp)")" -ForegroundColor Cyan Write-Host "`nProcessing: $($obj."$($objectType.NameProp)")" -ForegroundColor Cyan
foreach($ass in $objAssignments) try
{ {
try $existing = Invoke-GraphRequest "$($objectType.API)/$($obj.id)/assignments"
$remaining = @()
foreach($ea in $existing.value)
{
$desc = Get-AssignmentTargetDesc -Ass $ea
if($desc -in $selectedTargetDisplays)
{
continue
}
# Sanitize for re-post
$clean = $ea | ConvertTo-Json -Depth 50 | ConvertFrom-Json
if($clean.PSObject.Properties["id"]) { $clean.PSObject.Properties.Remove("id") }
if($clean.PSObject.Properties["source"]) { $clean.PSObject.Properties.Remove("source") }
if(-not $clean."@odata.type")
{
$clean | Add-Member -NotePropertyName "@odata.type" -NotePropertyValue $objectType.AssignmentODataType -Force
}
$remaining += $clean
}
$assignPayload = @{
$objectType.AssignmentsType = $remaining
} | ConvertTo-Json -Depth 50 -Compress
$null = Invoke-GraphRequest "$($objectType.API)/$($obj.id)/assign" -HttpMethod POST -Content $assignPayload
foreach($ass in $objAssignments)
{ {
$null = Invoke-GraphRequest "$($objectType.API)/$($obj.id)/assignments/$($ass.AssignmentId)" -HttpMethod DELETE
Write-Host " OK: Removed $($ass.TargetDesc)" -ForegroundColor Green Write-Host " OK: Removed $($ass.TargetDesc)" -ForegroundColor Green
$success++ $success++
} }
catch }
catch
{
foreach($ass in $objAssignments)
{ {
Write-Host " ERROR: Failed to remove $($ass.TargetDesc). $($_.Exception.Message)" -ForegroundColor Red Write-Host " ERROR: Failed to remove $($ass.TargetDesc). $($_.Exception.Message)" -ForegroundColor Red
$failed++ $failed++