Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to Sync-PnPSharePointUserProfilesFromAzureActiveDirectory and Get-PnPAzureADUser #1559

Merged
merged 12 commits into from
Feb 8, 2022
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 @@ -30,6 +32,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