From ab653925378a65a1009d0803e70cf01c3a62adb3 Mon Sep 17 00:00:00 2001 From: KoenZomers Date: Thu, 6 Jul 2023 07:04:25 +0200 Subject: [PATCH 1/4] Adding allowing base user profile props to be specifically requested --- .../UserProfiles/GetUserProfileProperty.cs | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/Commands/UserProfiles/GetUserProfileProperty.cs b/src/Commands/UserProfiles/GetUserProfileProperty.cs index bfa8d30a8..dc99ceee8 100644 --- a/src/Commands/UserProfiles/GetUserProfileProperty.cs +++ b/src/Commands/UserProfiles/GetUserProfileProperty.cs @@ -22,6 +22,7 @@ protected override void ExecuteCmdlet() { var peopleManager = new PeopleManager(AdminContext); + // Loop through each of the requested users foreach (var acc in Account) { var currentAccount = acc; @@ -31,28 +32,46 @@ protected override void ExecuteCmdlet() SortedDictionary upsDictionary = new(); + // Check if specific user profile properties have been requested if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0) { + // Specific user profile properties have been requested, return only those properties that have been requested UserProfilePropertiesForUser userProfilePropertiesForUser = new UserProfilePropertiesForUser(AdminContext, currentAccount, Properties); var userRequestedProperties = peopleManager.GetUserProfilePropertiesFor(userProfilePropertiesForUser); AdminContext.Load(userProfilePropertiesForUser); AdminContext.ExecuteQueryRetry(); + // Add all the requested extended user profile properties to the output for (var i = 0; i < userRequestedProperties.Count(); i++) { object propertyValue = userRequestedProperties.ElementAt(i); upsDictionary.Add(Properties[i], propertyValue); } - WriteObject(upsDictionary, true); - + // Check if any of the base user profile properties have been requested and if so, add them to the output as well + if(Properties.Contains("AccountName")) upsDictionary.Add("AccountName", userProfileProperties.AccountName); + if(Properties.Contains("DirectReports")) upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); + if(Properties.Contains("DisplayName")) upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); + if(Properties.Contains("Email")) upsDictionary.Add("Email", userProfileProperties.Email); + if(Properties.Contains("ExtendedManagers")) upsDictionary.Add("ExtendedManagers", userProfileProperties.ExtendedManagers); + if(Properties.Contains("ExtendedReports")) upsDictionary.Add("ExtendedReports", userProfileProperties.ExtendedReports); + if(Properties.Contains("IsFollowed")) upsDictionary.Add("IsFollowed", userProfileProperties.IsFollowed); + if(Properties.Contains("LatestPost")) upsDictionary.Add("LatestPost", userProfileProperties.LatestPost); + if(Properties.Contains("Peers")) upsDictionary.Add("Peers", userProfileProperties.Peers); + if(Properties.Contains("PersonalSiteHostUrl")) upsDictionary.Add("PersonalSiteHostUrl", userProfileProperties.PersonalSiteHostUrl); + if(Properties.Contains("PersonalUrl")) upsDictionary.Add("PersonalUrl", userProfileProperties.PersonalUrl); + if(Properties.Contains("PictureUrl")) upsDictionary.Add("PictureUrl", userProfileProperties.PictureUrl); + if(Properties.Contains("Title")) upsDictionary.Add("Title", userProfileProperties.Title); + if(Properties.Contains("UserUrl")) upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); } else { + // No specific user profile properties have been requested, return all we have var userProfileProperties = peopleManager.GetPropertiesFor(currentAccount); AdminContext.Load(userProfileProperties); AdminContext.ExecuteQueryRetry(); + // Add all of the basic user profile properties to the output upsDictionary.Add("AccountName", userProfileProperties.AccountName); upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); @@ -68,6 +87,7 @@ protected override void ExecuteCmdlet() upsDictionary.Add("Title", userProfileProperties.Title); upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); + // Add all the extended user profile properties to the output if (userProfileProperties.UserProfileProperties != null && userProfileProperties.UserProfileProperties.Count > 0) { for (var i = 0; i < userProfileProperties.UserProfileProperties.Count; i++) @@ -83,10 +103,11 @@ protected override void ExecuteCmdlet() } } } - - WriteObject(upsDictionary, true); } + + // Write the collected properties to the output stream + WriteObject(upsDictionary, true); } } } -} +} \ No newline at end of file From 7c2a49b6feff203e75e8333b573e3d510ecaaeca Mon Sep 17 00:00:00 2001 From: KoenZomers Date: Thu, 6 Jul 2023 08:37:54 +0200 Subject: [PATCH 2/4] Fixes --- CHANGELOG.md | 1 + .../UserProfiles/GetUserProfileProperty.cs | 116 +++++++++++------- 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9496f9181..a60fa0a2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Fixed - Fixed `Add-PnPContentTypeToList` cmdlet to better handle piped lists. [#3244](https://github.com/pnp/powershell/pull/3244) +- Fixed `Get-PnPUserProfileProperty` cmdlet not allowing basic user profile properties to be retrieved using `-Properties` ### Contributors diff --git a/src/Commands/UserProfiles/GetUserProfileProperty.cs b/src/Commands/UserProfiles/GetUserProfileProperty.cs index dc99ceee8..0c509ddcf 100644 --- a/src/Commands/UserProfiles/GetUserProfileProperty.cs +++ b/src/Commands/UserProfiles/GetUserProfileProperty.cs @@ -20,6 +20,9 @@ public class GetUserProfileProperty : PnPAdminCmdlet protected override void ExecuteCmdlet() { + // All the basic profile profile properties that only exist on the PersonProperties object + var basicProperties = new string[] { "AccountName", "DirectReports", "DisplayName", "Email", "ExtendedManagers", "ExtendedReports", "IsFollowed", "LatestPost", "Peers", "PersonalSiteHostUrl", "PersonalUrl", "PictureUrl", "Title", "UserUrl" }; + var peopleManager = new PeopleManager(AdminContext); // Loop through each of the requested users @@ -33,9 +36,9 @@ protected override void ExecuteCmdlet() SortedDictionary upsDictionary = new(); // Check if specific user profile properties have been requested - if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0) + if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0 && Properties.All(p => !basicProperties.Contains(p))) { - // Specific user profile properties have been requested, return only those properties that have been requested + // Specific user profile properties have been requested and none of them are basic user profile properties, return only those properties that have been requested UserProfilePropertiesForUser userProfilePropertiesForUser = new UserProfilePropertiesForUser(AdminContext, currentAccount, Properties); var userRequestedProperties = peopleManager.GetUserProfilePropertiesFor(userProfilePropertiesForUser); AdminContext.Load(userProfilePropertiesForUser); @@ -47,59 +50,86 @@ protected override void ExecuteCmdlet() object propertyValue = userRequestedProperties.ElementAt(i); upsDictionary.Add(Properties[i], propertyValue); } - - // Check if any of the base user profile properties have been requested and if so, add them to the output as well - if(Properties.Contains("AccountName")) upsDictionary.Add("AccountName", userProfileProperties.AccountName); - if(Properties.Contains("DirectReports")) upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); - if(Properties.Contains("DisplayName")) upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); - if(Properties.Contains("Email")) upsDictionary.Add("Email", userProfileProperties.Email); - if(Properties.Contains("ExtendedManagers")) upsDictionary.Add("ExtendedManagers", userProfileProperties.ExtendedManagers); - if(Properties.Contains("ExtendedReports")) upsDictionary.Add("ExtendedReports", userProfileProperties.ExtendedReports); - if(Properties.Contains("IsFollowed")) upsDictionary.Add("IsFollowed", userProfileProperties.IsFollowed); - if(Properties.Contains("LatestPost")) upsDictionary.Add("LatestPost", userProfileProperties.LatestPost); - if(Properties.Contains("Peers")) upsDictionary.Add("Peers", userProfileProperties.Peers); - if(Properties.Contains("PersonalSiteHostUrl")) upsDictionary.Add("PersonalSiteHostUrl", userProfileProperties.PersonalSiteHostUrl); - if(Properties.Contains("PersonalUrl")) upsDictionary.Add("PersonalUrl", userProfileProperties.PersonalUrl); - if(Properties.Contains("PictureUrl")) upsDictionary.Add("PictureUrl", userProfileProperties.PictureUrl); - if(Properties.Contains("Title")) upsDictionary.Add("Title", userProfileProperties.Title); - if(Properties.Contains("UserUrl")) upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); } else { - // No specific user profile properties have been requested, return all we have + // No specific user profile properties have been requested or there were basic user profile properties amongst them var userProfileProperties = peopleManager.GetPropertiesFor(currentAccount); AdminContext.Load(userProfileProperties); AdminContext.ExecuteQueryRetry(); - // Add all of the basic user profile properties to the output - upsDictionary.Add("AccountName", userProfileProperties.AccountName); - upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); - upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); - upsDictionary.Add("Email", userProfileProperties.Email); - upsDictionary.Add("ExtendedManagers", userProfileProperties.ExtendedManagers); - upsDictionary.Add("ExtendedReports", userProfileProperties.ExtendedReports); - upsDictionary.Add("IsFollowed", userProfileProperties.IsFollowed); - upsDictionary.Add("LatestPost", userProfileProperties.LatestPost); - upsDictionary.Add("Peers", userProfileProperties.Peers); - upsDictionary.Add("PersonalSiteHostUrl", userProfileProperties.PersonalSiteHostUrl); - upsDictionary.Add("PersonalUrl", userProfileProperties.PersonalUrl); - upsDictionary.Add("PictureUrl", userProfileProperties.PictureUrl); - upsDictionary.Add("Title", userProfileProperties.Title); - upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); - - // Add all the extended user profile properties to the output - if (userProfileProperties.UserProfileProperties != null && userProfileProperties.UserProfileProperties.Count > 0) + // Check if we only need to output specific properties or all of them + if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0) { - for (var i = 0; i < userProfileProperties.UserProfileProperties.Count; i++) + // Check if any of the base user profile properties have been requested and if so, add them to the output as well + if (Properties.Contains("AccountName")) upsDictionary.Add("AccountName", userProfileProperties.AccountName); + if (Properties.Contains("DirectReports")) upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); + if (Properties.Contains("DisplayName")) upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); + if (Properties.Contains("Email")) upsDictionary.Add("Email", userProfileProperties.Email); + if (Properties.Contains("ExtendedManagers")) upsDictionary.Add("ExtendedManagers", userProfileProperties.ExtendedManagers); + if (Properties.Contains("ExtendedReports")) upsDictionary.Add("ExtendedReports", userProfileProperties.ExtendedReports); + if (Properties.Contains("IsFollowed")) upsDictionary.Add("IsFollowed", userProfileProperties.IsFollowed); + if (Properties.Contains("LatestPost")) upsDictionary.Add("LatestPost", userProfileProperties.LatestPost); + if (Properties.Contains("Peers")) upsDictionary.Add("Peers", userProfileProperties.Peers); + if (Properties.Contains("PersonalSiteHostUrl")) upsDictionary.Add("PersonalSiteHostUrl", userProfileProperties.PersonalSiteHostUrl); + if (Properties.Contains("PersonalUrl")) upsDictionary.Add("PersonalUrl", userProfileProperties.PersonalUrl); + if (Properties.Contains("PictureUrl")) upsDictionary.Add("PictureUrl", userProfileProperties.PictureUrl); + if (Properties.Contains("Title")) upsDictionary.Add("Title", userProfileProperties.Title); + if (Properties.Contains("UserUrl")) upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); + + // Add the extended user profile properties to the output which have been specified in Properties + if (userProfileProperties.UserProfileProperties != null && userProfileProperties.UserProfileProperties.Count > 0) { - var element = userProfileProperties.UserProfileProperties.ElementAt(i); - if (!upsDictionary.ContainsKey(element.Key)) + for (var i = 0; i < userProfileProperties.UserProfileProperties.Count; i++) { - upsDictionary.Add(element.Key, element.Value); + var element = userProfileProperties.UserProfileProperties.ElementAt(i); + + // Check if this property should be included in the output, if not continue with the next property + if(!Properties.Contains(element.Key)) continue; + + if (!upsDictionary.ContainsKey(element.Key)) + { + upsDictionary.Add(element.Key, element.Value); + } + else + { + upsDictionary[element.Key] = element.Value; + } } - else + } + } + else + { + // Add all of the basic user profile properties to the output + upsDictionary.Add("AccountName", userProfileProperties.AccountName); + upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); + upsDictionary.Add("DisplayName", userProfileProperties.DisplayName); + upsDictionary.Add("Email", userProfileProperties.Email); + upsDictionary.Add("ExtendedManagers", userProfileProperties.ExtendedManagers); + upsDictionary.Add("ExtendedReports", userProfileProperties.ExtendedReports); + upsDictionary.Add("IsFollowed", userProfileProperties.IsFollowed); + upsDictionary.Add("LatestPost", userProfileProperties.LatestPost); + upsDictionary.Add("Peers", userProfileProperties.Peers); + upsDictionary.Add("PersonalSiteHostUrl", userProfileProperties.PersonalSiteHostUrl); + upsDictionary.Add("PersonalUrl", userProfileProperties.PersonalUrl); + upsDictionary.Add("PictureUrl", userProfileProperties.PictureUrl); + upsDictionary.Add("Title", userProfileProperties.Title); + upsDictionary.Add("UserUrl", userProfileProperties.UserUrl); + + // Add all the extended user profile properties to the output + if (userProfileProperties.UserProfileProperties != null && userProfileProperties.UserProfileProperties.Count > 0) + { + for (var i = 0; i < userProfileProperties.UserProfileProperties.Count; i++) { - upsDictionary[element.Key] = element.Value; + var element = userProfileProperties.UserProfileProperties.ElementAt(i); + if (!upsDictionary.ContainsKey(element.Key)) + { + upsDictionary.Add(element.Key, element.Value); + } + else + { + upsDictionary[element.Key] = element.Value; + } } } } From 4be388cc045e1f588d12ee87c82bf191d64f3138 Mon Sep 17 00:00:00 2001 From: KoenZomers Date: Thu, 6 Jul 2023 08:39:25 +0200 Subject: [PATCH 3/4] Added PR reference --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a60fa0a2d..5c425a256 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Fixed - Fixed `Add-PnPContentTypeToList` cmdlet to better handle piped lists. [#3244](https://github.com/pnp/powershell/pull/3244) -- Fixed `Get-PnPUserProfileProperty` cmdlet not allowing basic user profile properties to be retrieved using `-Properties` +- Fixed `Get-PnPUserProfileProperty` cmdlet not allowing basic user profile properties to be retrieved using `-Properties` [#3247](https://github.com/pnp/powershell/pull/3247) ### Contributors From a78eb0f9ca35c306d62aefbcab6e49877ea92463 Mon Sep 17 00:00:00 2001 From: KoenZomers Date: Thu, 6 Jul 2023 08:51:37 +0200 Subject: [PATCH 4/4] Added verbose logging --- documentation/Get-PnPUserProfileProperty.md | 18 ++++++++++++++++-- .../UserProfiles/GetUserProfileProperty.cs | 18 ++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/documentation/Get-PnPUserProfileProperty.md b/documentation/Get-PnPUserProfileProperty.md index 11aea4c38..59a58c045 100644 --- a/documentation/Get-PnPUserProfileProperty.md +++ b/documentation/Get-PnPUserProfileProperty.md @@ -20,7 +20,7 @@ You must connect to the tenant admin website (https://\-admin.sharepoin ## SYNTAX ```powershell -Get-PnPUserProfileProperty -Account [-Properties ] [-Connection ] +Get-PnPUserProfileProperty -Account [-Properties ] [-Verbose] [-Connection ] ``` ## DESCRIPTION @@ -93,6 +93,20 @@ Accept pipeline input: False Accept wildcard characters: False ``` +### -Verbose +When provided, additional debug statements will be shown while executing the cmdlet. + +```yaml +Type: SwitchParameter +Parameter Sets: (All) + +Required: False +Position: Named +Default value: None +Accept pipeline input: False +Accept wildcard characters: False +``` + ## RELATED LINKS -[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) +[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) \ No newline at end of file diff --git a/src/Commands/UserProfiles/GetUserProfileProperty.cs b/src/Commands/UserProfiles/GetUserProfileProperty.cs index 0c509ddcf..4c115e58f 100644 --- a/src/Commands/UserProfiles/GetUserProfileProperty.cs +++ b/src/Commands/UserProfiles/GetUserProfileProperty.cs @@ -26,12 +26,14 @@ protected override void ExecuteCmdlet() var peopleManager = new PeopleManager(AdminContext); // Loop through each of the requested users - foreach (var acc in Account) + foreach (var account in Account) { - var currentAccount = acc; - var result = Tenant.EncodeClaim(currentAccount); + WriteVerbose($"Getting user profile properties for {account}"); + var result = Tenant.EncodeClaim(account); AdminContext.ExecuteQueryRetry(); - currentAccount = result.Value; + var currentAccount = result.Value; + + WriteVerbose($"Account {account} encoded to {currentAccount}"); SortedDictionary upsDictionary = new(); @@ -39,6 +41,8 @@ protected override void ExecuteCmdlet() if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0 && Properties.All(p => !basicProperties.Contains(p))) { // Specific user profile properties have been requested and none of them are basic user profile properties, return only those properties that have been requested + WriteVerbose($"Retrieving {Properties.Length} specific non basic user profile {(Properties.Length != 1 ? "properties" : "property")} for account {currentAccount}"); + UserProfilePropertiesForUser userProfilePropertiesForUser = new UserProfilePropertiesForUser(AdminContext, currentAccount, Properties); var userRequestedProperties = peopleManager.GetUserProfilePropertiesFor(userProfilePropertiesForUser); AdminContext.Load(userProfilePropertiesForUser); @@ -54,6 +58,8 @@ protected override void ExecuteCmdlet() else { // No specific user profile properties have been requested or there were basic user profile properties amongst them + WriteVerbose($"Retrieving all user profile properties for {currentAccount}"); + var userProfileProperties = peopleManager.GetPropertiesFor(currentAccount); AdminContext.Load(userProfileProperties); AdminContext.ExecuteQueryRetry(); @@ -61,6 +67,8 @@ protected override void ExecuteCmdlet() // Check if we only need to output specific properties or all of them if (ParameterSpecified(nameof(Properties)) && Properties != null && Properties.Length > 0) { + WriteVerbose($"Adding specific {Properties.Length} user profile {(Properties.Length != 1 ? "properties" : "property")} to the output"); + // Check if any of the base user profile properties have been requested and if so, add them to the output as well if (Properties.Contains("AccountName")) upsDictionary.Add("AccountName", userProfileProperties.AccountName); if (Properties.Contains("DirectReports")) upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); @@ -101,6 +109,8 @@ protected override void ExecuteCmdlet() else { // Add all of the basic user profile properties to the output + WriteVerbose("Adding all user profile properties to the output"); + upsDictionary.Add("AccountName", userProfileProperties.AccountName); upsDictionary.Add("DirectReports", userProfileProperties.DirectReports); upsDictionary.Add("DisplayName", userProfileProperties.DisplayName);