diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSetUserPhoto.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSetUserPhoto.ps1 new file mode 100644 index 000000000000..f4636684fb1c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecSetUserPhoto.ps1 @@ -0,0 +1,91 @@ +function Invoke-ExecSetUserPhoto { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Identity.User.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $tenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + $userId = $Request.Query.userId ?? $Request.Body.userId + $action = $Request.Query.action ?? $Request.Body.action + $photoData = $Request.Body.photoData + + $Results = [System.Collections.Generic.List[object]]::new() + + try { + if ([string]::IsNullOrWhiteSpace($userId)) { + throw 'User ID is required' + } + + if ($action -eq 'remove') { + # Remove the user's profile picture + try { + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$userId/photo/`$value" -tenantid $tenantFilter -type DELETE -NoAuthCheck $true + $Results.Add('Successfully removed user profile picture.') + Write-LogMessage -API $APIName -tenant $tenantFilter -headers $Headers -message "Removed profile picture for user $userId" -Sev Info + } catch { + # Check if the error is because there's no photo + if ($_.Exception.Message -like '*does not exist*' -or $_.Exception.Message -like '*ResourceNotFound*') { + $Results.Add('User does not have a profile picture to remove.') + Write-LogMessage -API $APIName -tenant $tenantFilter -headers $Headers -message "No profile picture found for user $userId" -Sev Info + } else { + throw $_ + } + } + } elseif ($action -eq 'set') { + # Set the user's profile picture + if ([string]::IsNullOrWhiteSpace($photoData)) { + throw 'Photo data is required when setting a profile picture' + } + + # Convert base64 string to byte array + # The photoData should be in format: data:image/jpeg;base64,/9j/4AAQSkZJRg... + # We need to strip the data URL prefix if present + $base64Data = $photoData + if ($photoData -match '^data:image/[^;]+;base64,(.+)$') { + $base64Data = $Matches[1] + } + + try { + $photoBytes = [Convert]::FromBase64String($base64Data) + } catch { + throw "Invalid base64 photo data: $($_.Exception.Message)" + } + + # Validate image size (Microsoft Graph has a 4MB limit) + $maxSizeBytes = 4 * 1024 * 1024 # 4MB + if ($photoBytes.Length -gt $maxSizeBytes) { + throw "Photo size exceeds 4MB limit. Current size: $([math]::Round($photoBytes.Length / 1MB, 2))MB" + } + + # Upload the photo using Graph API + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/users/$userId/photo/`$value" -tenantid $tenantFilter -type PATCH -body $photoBytes -ContentType 'image/jpeg' -NoAuthCheck $true + + $Results.Add('Successfully set user profile picture.') + Write-LogMessage -API $APIName -tenant $tenantFilter -headers $Headers -message "Set profile picture for user $userId" -Sev Info + } else { + throw "Invalid action. Must be 'set' or 'remove'" + } + + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ + 'Results' = @($Results) + } + }) + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -tenant $tenantFilter -headers $Headers -message "Failed to $action user profile picture. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ + 'Results' = @("Failed to $action user profile picture: $($ErrorMessage.NormalizedError)") + } + }) + } +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 index b38676d9be0d..07018acad177 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 @@ -1,4 +1,4 @@ -Function Invoke-ExecGDAPRoleTemplate { +function Invoke-ExecGDAPRoleTemplate { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -44,19 +44,33 @@ Function Invoke-ExecGDAPRoleTemplate { } } 'Edit' { - $RowKey = $Request.Body.TemplateId - $Template = $Templates | Where-Object -Property RowKey -EQ $RowKey + # Use OriginalTemplateId if provided (for rename), otherwise use TemplateId + $OriginalRowKey = $Request.Body.OriginalTemplateId ?? $Request.Body.TemplateId + $NewRowKey = $Request.Body.TemplateId + $Template = $Templates | Where-Object -Property RowKey -EQ $OriginalRowKey if ($Template) { $RoleMappings = $Request.Body.RoleMappings - Add-CIPPGDAPRoleTemplate -TemplateId $RowKey -RoleMappings $RoleMappings -Overwrite - Write-LogMessage -headers $Headers -API $APIName -message "Updated role mappings for GDAP template '$RowKey'" -Sev 'Info' - $Body = @{ - Results = "Updated role mappings for template $RowKey" + + # If the template ID is being changed, delete the old one and create a new one + if ($OriginalRowKey -ne $NewRowKey) { + Remove-AzDataTableEntity -Force @Table -Entity $Template + Add-CIPPGDAPRoleTemplate -TemplateId $NewRowKey -RoleMappings $RoleMappings -Overwrite + Write-LogMessage -headers $Headers -API $APIName -message "Renamed GDAP template from '$OriginalRowKey' to '$NewRowKey' and updated role mappings" -Sev 'Info' + $Body = @{ + Results = "Renamed template from $OriginalRowKey to $NewRowKey and updated role mappings" + } + } else { + # Just update the existing template + Add-CIPPGDAPRoleTemplate -TemplateId $NewRowKey -RoleMappings $RoleMappings -Overwrite + Write-LogMessage -headers $Headers -API $APIName -message "Updated role mappings for GDAP template '$NewRowKey'" -Sev 'Info' + $Body = @{ + Results = "Updated role mappings for template $NewRowKey" + } } } else { - Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$RowKey' not found for editing" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$OriginalRowKey' not found for editing" -Sev 'Warning' $Body = @{ - Results = "Template $RowKey not found" + Results = "Template $OriginalRowKey not found" } } }