Skip to content

Commit 532fff7

Browse files
committed
fix: use deviceAppManagement endpoints for MAM policies
App protection policy lists expose the singular @odata.type as the URLName, but Graph delete/assign need the plural collection segment under deviceAppManagement. RemovePolicy sent these to deviceManagement with the singular name, so deletes failed with "Resource not found for the segment". Assign shared the same gap. Mirrors the normalization already in Invoke-EditIntunePolicy. Fixes KelvinTegelaar/CIPP#6384
1 parent 1072570 commit 532fff7

3 files changed

Lines changed: 108 additions & 5 deletions

File tree

Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ function Set-CIPPAssignedPolicy {
1919
$AssignmentDirection
2020
)
2121

22+
# App protection policy lists expose the singular @odata.type as the URLName, but Graph
23+
# needs the plural collection segment. Normalize the known types here.
24+
$Type = switch ($Type) {
25+
'androidManagedAppProtection' { 'androidManagedAppProtections' }
26+
'iosManagedAppProtection' { 'iosManagedAppProtections' }
27+
'windowsManagedAppProtection' { 'windowsManagedAppProtections' }
28+
'mdmWindowsInformationProtectionPolicy' { 'mdmWindowsInformationProtectionPolicies' }
29+
'windowsInformationProtectionPolicy' { 'windowsInformationProtectionPolicies' }
30+
'targetedManagedAppConfiguration' { 'targetedManagedAppConfigurations' }
31+
default { $Type }
32+
}
33+
2234
Write-Host "Assigning policy $PolicyId ($PlatformType/$Type) to $GroupName"
2335

2436
try {

Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-RemovePolicy.ps1

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,23 @@ function Invoke-RemovePolicy {
1616
$TenantFilter = $Request.Query.tenantFilter ?? $Request.body.tenantFilter
1717
$PolicyId = $Request.Query.ID ?? $Request.body.ID
1818
$UrlName = $Request.Query.URLName ?? $Request.body.URLName
19-
$BaseEndpoint = switch ($UrlName) {
20-
'managedAppPolicies' { 'deviceAppManagement' }
21-
'mobileAppConfigurations' { 'deviceAppManagement' }
22-
default { 'deviceManagement' }
19+
# App protection policy lists expose the singular @odata.type as the URLName, but a Graph
20+
# DELETE needs the plural collection segment under deviceAppManagement. Normalize here.
21+
$GraphPath = switch ($UrlName) {
22+
'androidManagedAppProtection' { 'deviceAppManagement/androidManagedAppProtections' }
23+
'iosManagedAppProtection' { 'deviceAppManagement/iosManagedAppProtections' }
24+
'windowsManagedAppProtection' { 'deviceAppManagement/windowsManagedAppProtections' }
25+
'mdmWindowsInformationProtectionPolicy' { 'deviceAppManagement/mdmWindowsInformationProtectionPolicies' }
26+
'windowsInformationProtectionPolicy' { 'deviceAppManagement/windowsInformationProtectionPolicies' }
27+
'targetedManagedAppConfiguration' { 'deviceAppManagement/targetedManagedAppConfigurations' }
28+
'managedAppPolicies' { 'deviceAppManagement/managedAppPolicies' }
29+
'mobileAppConfigurations' { 'deviceAppManagement/mobileAppConfigurations' }
30+
default { "deviceManagement/$UrlName" }
2331
}
2432
if (!$PolicyId) { exit }
2533

2634
try {
27-
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/$($BaseEndpoint)/$($UrlName)('$($PolicyId)')" -type DELETE -tenant $TenantFilter
35+
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/$($GraphPath)('$($PolicyId)')" -type DELETE -tenant $TenantFilter
2836

2937
$Results = "Successfully deleted the $UrlName policy with ID: $($PolicyId)"
3038
Write-LogMessage -headers $Headers -API $APINAME -message $Results -Sev Info -tenant $TenantFilter
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Pester tests for Invoke-RemovePolicy Graph URL construction (issue #6384).
2+
3+
BeforeAll {
4+
$RepoRoot = Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $PSCommandPath))
5+
$FunctionPath = Get-ChildItem -Path (Join-Path $RepoRoot 'Modules') -Recurse -Filter 'Invoke-RemovePolicy.ps1' -File |
6+
Select-Object -First 1 -ExpandProperty FullName
7+
8+
([PSObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')).GetMethod('Add').Invoke(
9+
$null, @('HttpStatusCode', [System.Net.HttpStatusCode]))
10+
11+
class HttpResponseContext {
12+
[int]$StatusCode
13+
[object]$Body
14+
}
15+
16+
function New-GraphPostRequest { param($uri, $type, $tenant) }
17+
function Write-LogMessage { param($headers, $API, $message, $Sev, $tenant, $LogData) }
18+
function Get-CippException { param($Exception) }
19+
20+
. $FunctionPath
21+
}
22+
23+
Describe 'Invoke-RemovePolicy Graph URL' {
24+
BeforeEach {
25+
$script:deleteUri = $null
26+
Mock -CommandName New-GraphPostRequest -MockWith {
27+
$script:deleteUri = $uri
28+
}
29+
Mock -CommandName Write-LogMessage -MockWith {}
30+
}
31+
32+
It 'maps singular app protection URLNames to the plural deviceAppManagement segment' {
33+
$request = [pscustomobject]@{
34+
Params = @{ CIPPEndpoint = 'RemovePolicy' }
35+
Headers = @{}
36+
Query = [pscustomobject]@{
37+
tenantFilter = 'contoso.onmicrosoft.com'
38+
ID = 'T_policy-1'
39+
URLName = 'androidManagedAppProtection'
40+
}
41+
Body = [pscustomobject]@{}
42+
}
43+
44+
$response = Invoke-RemovePolicy -Request $request -TriggerMetadata $null
45+
46+
$response.StatusCode | Should -Be ([System.Net.HttpStatusCode]::OK)
47+
$script:deleteUri | Should -Be "https://graph.microsoft.com/beta/deviceAppManagement/androidManagedAppProtections('T_policy-1')"
48+
}
49+
50+
It 'keeps mobileAppConfigurations under deviceAppManagement' {
51+
$request = [pscustomobject]@{
52+
Params = @{ CIPPEndpoint = 'RemovePolicy' }
53+
Headers = @{}
54+
Query = [pscustomobject]@{
55+
tenantFilter = 'contoso.onmicrosoft.com'
56+
ID = 'config-1'
57+
URLName = 'mobileAppConfigurations'
58+
}
59+
Body = [pscustomobject]@{}
60+
}
61+
62+
$null = Invoke-RemovePolicy -Request $request -TriggerMetadata $null
63+
64+
$script:deleteUri | Should -Be "https://graph.microsoft.com/beta/deviceAppManagement/mobileAppConfigurations('config-1')"
65+
}
66+
67+
It 'defaults other URLNames to deviceManagement' {
68+
$request = [pscustomobject]@{
69+
Params = @{ CIPPEndpoint = 'RemovePolicy' }
70+
Headers = @{}
71+
Query = [pscustomobject]@{
72+
tenantFilter = 'contoso.onmicrosoft.com'
73+
ID = 'policy-2'
74+
URLName = 'deviceConfigurations'
75+
}
76+
Body = [pscustomobject]@{}
77+
}
78+
79+
$null = Invoke-RemovePolicy -Request $request -TriggerMetadata $null
80+
81+
$script:deleteUri | Should -Be "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations('policy-2')"
82+
}
83+
}

0 commit comments

Comments
 (0)