Skip to content

Commit 68edc5c

Browse files
Merge branch 'dev' of https://github.com/KelvinTegelaar/CIPP-API into dev
2 parents 7403b2f + 0c13c98 commit 68edc5c

4 files changed

Lines changed: 129 additions & 16 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/CIPPCore/Public/Set-CIPPResetPassword.ps1

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,23 @@ function Set-CIPPResetPassword {
1111

1212
try {
1313
$password = New-passwordString
14-
$passwordProfile = @{
15-
'passwordProfile' = @{
16-
'forceChangePasswordNextSignIn' = $forceChangePasswordNextSignIn
17-
'password' = $password
18-
}
19-
} | ConvertTo-Json -Compress
2014

2115
$UserDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)?`$select=onPremisesSyncEnabled" -noPagination $true -tenantid $TenantFilter -verbose
22-
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose
16+
$IsSynced = $UserDetails.onPremisesSyncEnabled -eq $true
17+
18+
if ($IsSynced) {
19+
$ResetBody = @{ 'newPassword' = $password } | ConvertTo-Json -Compress
20+
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)/authentication/methods/28c10230-6103-485e-b985-444c60001490/resetPassword" -tenantid $TenantFilter -type POST -body $ResetBody -verbose
21+
} else {
22+
$passwordProfile = @{
23+
'passwordProfile' = @{
24+
'forceChangePasswordNextSignIn' = $forceChangePasswordNextSignIn
25+
'password' = $password
26+
}
27+
} | ConvertTo-Json -Compress
28+
29+
$null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserID)" -tenantid $TenantFilter -type PATCH -body $passwordProfile -verbose
30+
}
2331

2432
#PWPush
2533
$PasswordLink = $null
@@ -32,15 +40,17 @@ function Set-CIPPResetPassword {
3240
catch {
3341
Write-LogMessage -headers $Headers -API $APIName -message "Failed to create PwPush link, using plain password. Error: $($_.Exception.Message)" -sev 'Warning' -tenant $TenantFilter
3442
}
35-
Write-LogMessage -headers $Headers -API $APIName -message "Successfully reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter
43+
if ($IsSynced) {
44+
Write-LogMessage -headers $Headers -API $APIName -message "Submitted a password writeback reset for $DisplayName, $($UserID). This user is directory synced, so the reset was sent via password writeback and the user must change password at next logon regardless of the requested setting ($forceChangePasswordNextSignIn)." -Sev 'Info' -tenant $TenantFilter
3645

37-
if ($UserDetails.onPremisesSyncEnabled -eq $true) {
3846
return [pscustomobject]@{
39-
resultText = "Successfully reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password. WARNING: This user is AD synced. Please confirm passthrough or writeback is enabled."
47+
resultText = "Password reset accepted for $DisplayName, $($UserID). The new password is $password. This user is directory synced, so the reset was submitted via password writeback and is applied asynchronously - it is not confirmed yet, and will fail if writeback is not enabled or if the on-premises password policy rejects the password. This user must change their password at next logon; that is enforced by this method and cannot be turned off."
4048
copyField = $password
41-
state = 'warning'
49+
state = 'success'
4250
}
4351
} else {
52+
Write-LogMessage -headers $Headers -API $APIName -message "Successfully reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter
53+
4454
return [pscustomobject]@{
4555
resultText = "Successfully reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn. The new password is $password"
4656
copyField = $password

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)