From 8bc75087c1ab0adf9e37c1fcfce74b3a6b3668ea Mon Sep 17 00:00:00 2001 From: Erwin van Hunen Date: Mon, 16 Dec 2024 19:25:30 +0100 Subject: [PATCH] Added Get-PnPUserProfilePhoto cmdlet --- CHANGELOG.md | 2 +- documentation/Get-PnPUserProfilePhoto.md | 89 +++++++++++++++ .../UserProfiles/GetUserProfilePhoto.cs | 106 ++++++++++++++++++ .../Utilities/Microsoft365GroupsUtility.cs | 1 + 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 documentation/Get-PnPUserProfilePhoto.md create mode 100644 src/Commands/UserProfiles/GetUserProfilePhoto.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 90ac28ce6..36d00586c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,7 +48,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Added `-ListPermissionScopes` parameter on `Get-PnPAccessToken` cmdlet to list the current permission scopes on the current access token. - Added `Get-PnPCopilotAgent` cmdlet that returns the Microsoft Copilot Agents in a site collection. - Added `Get-PnPFileRetentionLabel` cmdlet to fetch the file retention labels. [#4603](https://github.com/pnp/powershell/pull/4603) -- Added `Set/Remove-PnPUserProfilePhoto` cmdlet to upload or remove the profile photo of the specified user. +- Added `Get/Set/Remove-PnPUserProfilePhoto` cmdlet to download, upload or remove the profile photo of the specified user. ### Changed diff --git a/documentation/Get-PnPUserProfilePhoto.md b/documentation/Get-PnPUserProfilePhoto.md new file mode 100644 index 000000000..7fbadc0b3 --- /dev/null +++ b/documentation/Get-PnPUserProfilePhoto.md @@ -0,0 +1,89 @@ +--- +Module Name: PnP.PowerShell +title: Get-PnPUserProfilePhoto +schema: 2.0.0 +applicable: SharePoint Online +external help file: PnP.PowerShell.dll-Help.xml +online version: https://pnp.github.io/powershell/cmdlets/Get-PnPUserProfilePhoto.html +--- + +# Get-PnPUserProfilePhoto + +## SYNOPSIS + +**Required Permissions** + + * Microsoft Graph API: One of ProfilePhoto.ReadWrite.All, User.ReadWrite or User.ReadWrite.All + +Gets the profile picture of a user. + +## SYNTAX + +```powershell +Get-PnPUserProfilePhoto -Identity [-Filename ] [-Connection ] +``` + +## DESCRIPTION +This cmdlet downloads the user profile photo to the specified path and filename. If no filename has been specified it will default to the Display Name of the user with the either the extension .png or .jpeg depending on the format of the file. + +## EXAMPLES + +### EXAMPLE 1 +```powershell +Get-PnPUserProfilePhoto -Identity "john@contoso.onmicrosoft.com" +``` +Downloads the photo for the user specified to the current folder. + +### EXAMPLE 2 +```powershell +Get-PnPUserProfilePhoto -Identity "john@contoso.onmicrosoft.com" -Filename "john.png" +``` +Downloads the photo for the user specified to the current folder and will name the file 'john.png'. + +## PARAMETERS + +### -Connection +Optional connection to be used by the cmdlet. Retrieve the value for this parameter by either specifying -ReturnConnection on Connect-PnPOnline or by executing Get-PnPConnection. + +```yaml +Type: PnPConnection +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Filename +The path to the image file to save. + +```yaml +Type: String +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + +### -Identity +The identity of the user to remove. This can be the UPN, the GUID or an instance of the user. + +```yaml +Type: AzureADUserPipeBind +Parameter Sets: (All) + +Required: True +Position: Named +Default value: None +Accept pipeline input: True (ByValue) +Accept wildcard characters: False +``` + +## RELATED LINKS + +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) diff --git a/src/Commands/UserProfiles/GetUserProfilePhoto.cs b/src/Commands/UserProfiles/GetUserProfilePhoto.cs new file mode 100644 index 000000000..ba9479131 --- /dev/null +++ b/src/Commands/UserProfiles/GetUserProfilePhoto.cs @@ -0,0 +1,106 @@ +using AngleSharp.Io; +using PnP.Framework.Diagnostics; +using PnP.PowerShell.Commands.Attributes; +using PnP.PowerShell.Commands.Base; +using PnP.PowerShell.Commands.Base.PipeBinds; +using PnP.PowerShell.Commands.Utilities; +using System.IO; +using System.Management.Automation; +using System.Net.Http.Headers; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace PnP.PowerShell.Commands.UserProfiles +{ + [Cmdlet(VerbsCommon.Get, "PnPUserProfilePhoto")] + [RequiredApiDelegatedOrApplicationPermissions("graph/ProfilePhoto.ReadWrite.All")] + [RequiredApiDelegatedPermissions("graph/User.ReadWrite")] + [RequiredApiDelegatedOrApplicationPermissions("graph/User.ReadWrite.All")] + public class GetUserProfilePhoto : PnPGraphCmdlet + { + [Parameter(Mandatory = true, ValueFromPipeline = true)] + public AzureADUserPipeBind Identity; + + [Parameter(Mandatory = false)] + public string Filename; + + [Parameter(Mandatory = false)] + public SwitchParameter Force; + + + protected override void ExecuteCmdlet() + { + WriteVerbose($"Looking up user provided through the {nameof(Identity)} parameter"); + Model.AzureAD.User user = Identity.GetUser(AccessToken, Connection.AzureEnvironment); + + if (user == null) + { + Log.Error("Get-PnPUserProfilePhoto", $"User provided through the {nameof(Identity)} parameter could not be found"); + throw new PSArgumentException($"User provided through the {nameof(Identity)} parameter could not be found"); + } + + WriteVerbose($"Setting profile photo for user {user.UserPrincipalName}"); + + if (Filename == null) + { + // retrieve the metadata first to figure out the file type + var photoData = RequestHelper.Get($"users/{user.Id}/photo"); + if (photoData != null) + { + switch (photoData.ContentType) + { + case "image/jpeg": + { + Filename = $"{user.DisplayName}.jpg"; + break; + } + case "image/png": + { + Filename = $"{user.DisplayName}.png"; + break; + } + } + } + else + { + Log.Error("Get-PnPUserProfilePhoto", "Photo not found"); + throw new PSArgumentException("Photo for user not found"); + } + } + + if (!System.IO.Path.IsPathRooted(Filename)) + { + Filename = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Filename); + } + + var getphoto = true; + if (File.Exists(Filename)) + { + if (Force || ShouldContinue($"File {Filename} exists. Overwrite?", Properties.Resources.Confirm)) + { + getphoto = true; + } + else + { + getphoto = false; + } + } + if (getphoto) + { + var response = RequestHelper.GetResponse($"users/{user.Id}/photo/$value"); + if (response.IsSuccessStatusCode) + { + var content = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult(); + System.IO.File.WriteAllBytes(Filename, content); + WriteObject($"File saved as: {Filename}"); + } + } + } + + internal class PhotoMetadata + { + [JsonPropertyName("@odata.mediaContentType")] + public string ContentType { get; set; } + } + } +} diff --git a/src/Commands/Utilities/Microsoft365GroupsUtility.cs b/src/Commands/Utilities/Microsoft365GroupsUtility.cs index 432afbd49..64b7a5a1a 100644 --- a/src/Commands/Utilities/Microsoft365GroupsUtility.cs +++ b/src/Commands/Utilities/Microsoft365GroupsUtility.cs @@ -2,6 +2,7 @@ using PnP.PowerShell.Commands.Utilities.REST; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Http;