Skip to content

Commit

Permalink
Updates to Sync-PnPSharePointUserProfilesFromAzureActiveDirectory a…
Browse files Browse the repository at this point in the history
…nd `Get-PnPAzureADUser` (#1559)

* Fixes for user profile sync

* Fixes for user profile syncing

* Fixes for user profile sync

* Fixes for user profile syncing

* Updating changelog

* Adding PR reference

* Making changelog entry shorter

* Update CHANGELOG.md

* Update CHANGELOG.md
  • Loading branch information
KoenZomers authored Feb 8, 2022
1 parent 250cfde commit 5c6b198
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 28 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Added `Add\Remove\Set-PnPAdaptiveScopeProperty` cmdlets to add/update/remove a property bag value while dealing with the noscript toggling in one cmdlet [#1556](https://github.com/pnp/powershell/pull/1556)
- Added support to add multiple owners and members in `New-PnPTeamsTeam` cmdlet [#1241](https://github.com/pnp/powershell/pull/1241)
- Added the ability to set the title of a new modern page in SharePoint Online using `Add-PnPPage` to be different from its filename by using `-Title`
- Added optional `-UseBeta` parameter to `Get-PnPAzureADUser` to force it to use the Microsoft Graph beta endpoint. This can be necessary when i.e. using `-Select "PreferredDataLocation"` to query for users with a specific multi geo location as this property is only available through the beta endpoint. [#1559](https://github.com/pnp/powershell/pull/1559)
- Added `-Content` option to `Add-PnPFile` which allows creating a new file on SharePoint Online and directly providing its textual content, i.e. to upload a log file of the execution [#1559](https://github.com/pnp/powershell/pull/1559)
- Added `Get-PnPTeamsPrimaryChannel` to get the primary Teams channel, general, of a Team [#1572](https://github.com/pnp/powershell/pull/1572)
- Added `Publish\Unpublish-PnPContentType` to allow for content types to be published or unpublished on hub sites [#1597](https://github.com/pnp/powershell/pull/1597)
- Added `Get-PnPContentTypePublishingStatus` to get te current publication state of a content type in the content type hub site [#1597](https://github.com/pnp/powershell/pull/1597)
Expand All @@ -31,6 +33,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- Improved `Add-PnPTeamsUser` cmdlet. The cmdlet executes faster and we can now add users in batches of 200. [#1548](https://github.com/pnp/powershell/pull/1548)
- The `Move\Remove\Rename-PnPFolder` cmdlets now support pipebinds.
- Changed `Add-PnPDataRowsToSiteTemplate`, it will return a warning if user(s) are not found during list item extraction. Earlier it used to throw error and stop extraction of list items.
- Changed the return type of `Sync-PnPSharePointUserProfilesFromAzureActiveDirectory` to return our own entity instead of the one returned by CSOM [#1559](https://github.com/pnp/powershell/pull/1559)
- Changed running `Sync-PnPSharePointUserProfilesFromAzureActiveDirectory` with `-WhatIf` to also provide a return entity providing the path to where the JSON file has been uploaded to [#1559](https://github.com/pnp/powershell/pull/1559)
- Disabling telemetry collection now requires either setting the environment variable or creating the telemetry file ([documentation](https://pnp.github.io/powershell/articles/configuration.html)) [#1504](https://github.com/pnp/powershell/pull/1504)
- Changed `Get-PnPAzureADUser` to now return all the users in Azure Active Directory by default, instead of only the first 999, unless you specified `-EndIndex:$null` [#1565](https://github.com/pnp/powershell/pull/1565)
- Changed `Get-PnPTenantDeletedSite -Identity` no longer returning an unknown exception when no site collection with the provided Url exists in the tenant recycle bin but instead returning no output to align with other cmdlets [#1596](https://github.com/pnp/powershell/pull/1596)
Expand Down
13 changes: 9 additions & 4 deletions src/Commands/AzureAD/GetAzureADUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public class GetAzureADUser : PnPGraphCmdlet
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_DELTA)]
public int? EndIndex = null;

[Parameter(Mandatory = false, ParameterSetName = ParameterSet_BYID)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_LIST)]
[Parameter(Mandatory = false, ParameterSetName = ParameterSet_DELTA)]
public SwitchParameter UseBeta;

protected override void ExecuteCmdlet()
{
if (PnPConnection.Current.ClientId == PnPConnection.PnPManagementShellClientId)
Expand All @@ -56,22 +61,22 @@ protected override void ExecuteCmdlet()
PnP.PowerShell.Commands.Model.AzureAD.User user;
if (Guid.TryParse(Identity, out Guid identityGuid))
{
user = PnP.PowerShell.Commands.Utilities.AzureAdUtility.GetUser(AccessToken, identityGuid);
user = PnP.PowerShell.Commands.Utilities.AzureAdUtility.GetUser(AccessToken, identityGuid, useBetaEndPoint: UseBeta.IsPresent);
}
else
{
user = PnP.PowerShell.Commands.Utilities.AzureAdUtility.GetUser(AccessToken, WebUtility.UrlEncode(Identity), Select);
user = PnP.PowerShell.Commands.Utilities.AzureAdUtility.GetUser(AccessToken, WebUtility.UrlEncode(Identity), Select, useBetaEndPoint: UseBeta.IsPresent);
}
WriteObject(user);
}
else if (ParameterSpecified(nameof(Delta)))
{
var userDelta = PnP.PowerShell.Commands.Utilities.AzureAdUtility.ListUserDelta(AccessToken, DeltaToken, Filter, OrderBy, Select, StartIndex, EndIndex);
var userDelta = PnP.PowerShell.Commands.Utilities.AzureAdUtility.ListUserDelta(AccessToken, DeltaToken, Filter, OrderBy, Select, StartIndex, EndIndex, useBetaEndPoint: UseBeta.IsPresent);
WriteObject(userDelta);
}
else
{
var users = PnP.PowerShell.Commands.Utilities.AzureAdUtility.ListUsers(AccessToken, Filter, OrderBy, Select, StartIndex, EndIndex);
var users = PnP.PowerShell.Commands.Utilities.AzureAdUtility.ListUsers(AccessToken, Filter, OrderBy, Select, StartIndex, EndIndex, useBetaEndPoint: UseBeta.IsPresent);
WriteObject(users, true);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace PnP.PowerShell.Commands.Enums
{
/// <summary>
/// Types of errors that can occur while performing a SharePoint Online User Profile Import
/// </summary>
public enum SharePointUserProfileImportProfilePropertiesJobError
{
NoError = 0,
InternalError = 1,
DataFileNotExist = 20,
DataFileNotInTenant = 21,
DataFileTooBig = 22,
InvalidDataFile = 23,
ImportCompleteWithError = 30
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
namespace PnP.PowerShell.Commands.Enums
{
/// <summary>
/// The states a SharePoint Online User Profile import job can be in
/// </summary>
public enum SharePointUserProfileImportProfilePropertiesJobState
{
/// <summary>
/// State is unknown
/// </summary>
Unknown = 0,

/// <summary>
/// The file has been submitted to SharePoint Online for processing
/// </summary>
Submitted = 1,

/// <summary>
/// The file is currently being processed to validate if it can be used
/// </summary>
Processing = 2,

/// <summary>
/// The file is queued and being executed
/// </summary>
Queued = 3,

/// <summary>
/// The import process has completed successfully
/// </summary>
Succeeded = 4,

/// <summary>
/// The import process has failed to complete
/// </summary>
Error = 5,

/// <summary>
/// The import process will not start
/// </summary>
WontStart = 99
}
}
33 changes: 27 additions & 6 deletions src/Commands/Files/AddFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class AddFile : PnPWebCmdlet
{
private const string ParameterSet_ASFILE = "Upload file";
private const string ParameterSet_ASSTREAM = "Upload file from stream";
private const string ParameterSet_ASTEXT = "Upload file from text";

[Parameter(Mandatory = true, ParameterSetName = ParameterSet_ASFILE)]
[ValidateNotNullOrEmpty]
Expand All @@ -23,6 +24,7 @@ public class AddFile : PnPWebCmdlet
public FolderPipeBind Folder;

[Parameter(Mandatory = true, ParameterSetName = ParameterSet_ASSTREAM)]
[Parameter(Mandatory = true, ParameterSetName = ParameterSet_ASTEXT)]
[ValidateNotNullOrEmpty]
public string FileName = string.Empty;

Expand All @@ -34,6 +36,9 @@ public class AddFile : PnPWebCmdlet
[ValidateNotNullOrEmpty]
public Stream Stream;

[Parameter(Mandatory = true, ParameterSetName = ParameterSet_ASTEXT)]
public string Content;

[Parameter(Mandatory = false)]
public SwitchParameter Checkout;

Expand Down Expand Up @@ -112,14 +117,30 @@ protected override void ExecuteCmdlet()
{ // Swallow exception, file does not exist
}
}

Microsoft.SharePoint.Client.File file;
if (ParameterSetName == ParameterSet_ASFILE)
{
file = folder.UploadFile(FileName, Path, true);
}
else
switch (ParameterSetName)
{
file = folder.UploadFile(FileName, Stream, true);
case ParameterSet_ASFILE:
file = folder.UploadFile(FileName, Path, true);
break;

case ParameterSet_ASTEXT:
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream))
{
writer.Write(Content);
writer.Flush();
stream.Position = 0;
file = folder.UploadFile(FileName, stream, true);
}
}
break;

default:
file = folder.UploadFile(FileName, Stream, true);
break;
}

bool updateRequired = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using Microsoft.Online.SharePoint.TenantManagement;
using PnP.PowerShell.Commands.Enums;

namespace PnP.PowerShell.Commands.Model.SharePoint.SharePointUserProfileSync
{
/// <summary>
/// Contains the status of a SharePoint Online User Profile Import job
/// </summary>
public class SharePointUserProfileSyncStatus
{
#region Properties

/// <summary>
/// Details on the type of error that occurred, if any
/// </summary>
public SharePointUserProfileImportProfilePropertiesJobError Error { get; set; }

/// <summary>
/// The error message, if an error occurred
/// </summary>
public string ErrorMessage { get; set; }

/// <summary>
/// Unique identifier of the import job
/// </summary>
public Guid? JobId { get; set; }

/// <summary>
///
/// </summary>
public string LogFolderUri { get; set; }

/// <summary>
///
/// </summary>
public string SourceUri { get; set; }

/// <summary>
/// State the user profile import process is in
/// </summary>
public SharePointUserProfileImportProfilePropertiesJobState State { get; set; }

#endregion

#region Methods

/// <summary>
/// Takes an instance of ImportProfilePropertiesJobInfo from CSOM and maps it to a local SharePointUserProfileSyncStatus entity
/// </summary>
/// <param name="importProfilePropertiesJobInfo">Instance to map from</param>
public static SharePointUserProfileSyncStatus ParseFromImportProfilePropertiesJobInfo(ImportProfilePropertiesJobInfo importProfilePropertiesJobInfo)
{
var result = new SharePointUserProfileSyncStatus
{
Error = Enum.TryParse(importProfilePropertiesJobInfo.Error.ToString(), out SharePointUserProfileImportProfilePropertiesJobError sharePointUserProfileImportProfilePropertiesJobError) ? sharePointUserProfileImportProfilePropertiesJobError : SharePointUserProfileImportProfilePropertiesJobError.NoError,
ErrorMessage = importProfilePropertiesJobInfo.ErrorMessage,
JobId = importProfilePropertiesJobInfo.JobId,
LogFolderUri = importProfilePropertiesJobInfo.LogFolderUri,
SourceUri = importProfilePropertiesJobInfo.SourceUri,
State = Enum.TryParse(importProfilePropertiesJobInfo.State.ToString(), out SharePointUserProfileImportProfilePropertiesJobState sharePointUserProfileImportProfilePropertiesJobState) ? sharePointUserProfileImportProfilePropertiesJobState : SharePointUserProfileImportProfilePropertiesJobState.Unknown
};
return result;
}

#endregion
}
}
28 changes: 13 additions & 15 deletions src/Commands/Utilities/AzureAdUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ internal static class AzureAdUtility
/// <param name="selectProperties">Optional additional properties to fetch for the users</param>
/// <param name="startIndex">Optional start index indicating starting from which result to start returning users</param>
/// <param name="endIndex">Optional end index indicating up to which result to return users. By default all users will be returned.</param>
/// <param name="useBetaEndPoint">Indicates if the v1.0 (false) or beta (true) endpoint should be used at Microsoft Graph to query for the data</param>
/// <returns>UserDelta instance</returns>
public static UserDelta ListUserDelta(string accessToken, string deltaToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int? endIndex = null)
public static UserDelta ListUserDelta(string accessToken, string deltaToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int? endIndex = null, bool useBetaEndPoint = false)
{
var userDelta = PnP.Framework.Graph.UsersUtility.ListUserDelta(accessToken, deltaToken, filter, orderby, selectProperties, startIndex, endIndex);
var userDelta = PnP.Framework.Graph.UsersUtility.ListUserDelta(accessToken, deltaToken, filter, orderby, selectProperties, startIndex, endIndex, useBetaEndPoint: useBetaEndPoint);

var result = new UserDelta
{
Expand All @@ -45,28 +46,26 @@ public static UserDelta ListUserDelta(string accessToken, string deltaToken, str
/// <param name="selectProperties">Allows providing the names of properties to return regarding the users. If not provided, the standard properties will be returned.</param>
/// <param name="startIndex">First item in the results returned by Microsoft Graph to return</param>
/// <param name="endIndex">Last item in the results returned by Microsoft Graph to return. Provide NULL to return all results that exist.</param>
/// <param name="retryCount">Number of times to retry the request in case of throttling</param>
/// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry.</param>
/// <param name="useBetaEndPoint">Indicates if the v1.0 (false) or beta (true) endpoint should be used at Microsoft Graph to query for the data</param>
/// <returns>List with User objects</returns>
public static List<User> ListUsers(string accessToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999)
public static List<User> ListUsers(string accessToken, string filter, string orderby, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999, bool useBetaEndPoint = false)
{
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, filter, orderby, selectProperties, startIndex, endIndex).Select(User.CreateFrom).ToList();
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, filter, orderby, selectProperties, startIndex, endIndex, useBetaEndPoint: useBetaEndPoint).Select(User.CreateFrom).ToList();
}

/// <summary>
/// Returns the user with the provided userId from Azure Active Directory
/// Returns the user with the provided <paramref name="userId"/> from Azure Active Directory
/// </summary>
/// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</param>
/// <param name="userId">The unique identifier of the user in Azure Active Directory to return</param>
/// <param name="selectProperties">Allows providing the names of properties to return regarding the users. If not provided, the standard properties will be returned.</param>
/// <param name="startIndex">First item in the results returned by Microsoft Graph to return</param>
/// <param name="endIndex">Last item in the results returned by Microsoft Graph to return. Provide NULL to return all results that exist.</param>
/// <param name="retryCount">Number of times to retry the request in case of throttling</param>
/// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry.</param>
/// <param name="useBetaEndPoint">Indicates if the v1.0 (false) or beta (true) endpoint should be used at Microsoft Graph to query for the data</param>
/// <returns>List with User objects</returns>
public static User GetUser(string accessToken, Guid userId, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999)
public static User GetUser(string accessToken, Guid userId, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999, bool useBetaEndPoint = false)
{
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, $"id eq '{userId}'", null, selectProperties, startIndex, endIndex).Select(User.CreateFrom).FirstOrDefault();
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, $"id eq '{userId}'", null, selectProperties, startIndex, endIndex, useBetaEndPoint: useBetaEndPoint).Select(User.CreateFrom).FirstOrDefault();
}

/// <summary>
Expand All @@ -77,12 +76,11 @@ public static User GetUser(string accessToken, Guid userId, string[] selectPrope
/// <param name="selectProperties">Allows providing the names of properties to return regarding the users. If not provided, the standard properties will be returned.</param>
/// <param name="startIndex">First item in the results returned by Microsoft Graph to return</param>
/// <param name="endIndex">Last item in the results returned by Microsoft Graph to return. Provide NULL to return all results that exist.</param>
/// <param name="retryCount">Number of times to retry the request in case of throttling</param>
/// <param name="delay">Milliseconds to wait before retrying the request. The delay will be increased (doubled) every retry.</param>
/// <param name="useBetaEndPoint">Indicates if the v1.0 (false) or beta (true) endpoint should be used at Microsoft Graph to query for the data</param>
/// <returns>User object</returns>
public static User GetUser(string accessToken, string userPrincipalName, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999)
public static User GetUser(string accessToken, string userPrincipalName, string[] selectProperties = null, int startIndex = 0, int? endIndex = 999, bool useBetaEndPoint = false)
{
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, $"userPrincipalName eq '{userPrincipalName}'", null, selectProperties, startIndex, endIndex).Select(User.CreateFrom).FirstOrDefault();
return PnP.Framework.Graph.UsersUtility.ListUsers(accessToken, $"userPrincipalName eq '{userPrincipalName}'", null, selectProperties, startIndex, endIndex, useBetaEndPoint: useBetaEndPoint).Select(User.CreateFrom).FirstOrDefault();
}

#endregion
Expand Down
Loading

0 comments on commit 5c6b198

Please sign in to comment.