/// <summary> /// Creates a new Office 365 Group (i.e. Unified Group) with its backing Modern SharePoint Site /// </summary> /// <param name="displayName">The Display Name for the Office 365 Group</param> /// <param name="description">The Description for the Office 365 Group</param> /// <param name="mailNickname">The Mail Nickname for the Office 365 Group</param> /// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</param> /// <param name="owners">A list of UPNs for group owners, if any</param> /// <param name="members">A list of UPNs for group members, if any</param> /// <param name="groupLogo">The binary stream of the logo for the Office 365 Group</param> /// <param name="isPrivate">Defines whether the group will be private or public, optional with default false (i.e. public)</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> /// <returns>The just created Office 365 Group</returns> public static UnifiedGroupEntity CreateUnifiedGroup(string displayName, string description, string mailNickname, string accessToken, string[] owners = null, string[] members = null, Stream groupLogo = null, bool isPrivate = false, int retryCount = 10, int delay = 500) { UnifiedGroupEntity result = null; if (String.IsNullOrEmpty(displayName)) { throw new ArgumentNullException("displayName"); } if (String.IsNullOrEmpty(description)) { throw new ArgumentNullException("description"); } if (String.IsNullOrEmpty(mailNickname)) { throw new ArgumentNullException("mailNickname"); } if (String.IsNullOrEmpty(accessToken)) { throw new ArgumentNullException("accessToken"); } // Use a synchronous model to invoke the asynchronous process result = Task.Run(async () => { var group = new UnifiedGroupEntity(); var graphClient = CreateGraphClient(accessToken, retryCount, delay); // Prepare the group resource object var newGroup = new Microsoft.Graph.Group { DisplayName = displayName, Description = description, MailNickname = mailNickname, MailEnabled = true, SecurityEnabled = false, GroupTypes = new List<string> { "Unified" }, }; Microsoft.Graph.Group addedGroup = null; String modernSiteUrl = null; // Add the group to the collection of groups (if it does not exist if (addedGroup == null) { addedGroup = await graphClient.Groups.Request().AddAsync(newGroup); if (addedGroup != null) { group.DisplayName = addedGroup.DisplayName; group.Description = addedGroup.Description; group.GroupId = addedGroup.Id; group.Mail = addedGroup.Mail; group.MailNickname = addedGroup.MailNickname; int imageRetryCount = retryCount; if (groupLogo != null) { using (var memGroupLogo = new MemoryStream()) { groupLogo.CopyTo(memGroupLogo); while (imageRetryCount > 0) { bool groupLogoUpdated = false; memGroupLogo.Position = 0; using (var tempGroupLogo = new MemoryStream()) { memGroupLogo.CopyTo(tempGroupLogo); tempGroupLogo.Position = 0; try { groupLogoUpdated = UpdateUnifiedGroup(addedGroup.Id, accessToken, groupLogo: tempGroupLogo); } catch { // Skip any exception and simply retry } } // In case of failure retry up to 10 times, with 500ms delay in between if (!groupLogoUpdated) { // Pop up the delay for the group image Thread.Sleep(TimeSpan.FromMilliseconds(delay * (retryCount - imageRetryCount))); imageRetryCount--; } else { break; } } } } int driveRetryCount = retryCount; while (driveRetryCount > 0 && String.IsNullOrEmpty(modernSiteUrl)) { try { modernSiteUrl = GetUnifiedGroupSiteUrl(addedGroup.Id, accessToken); } catch { // Skip any exception and simply retry } // In case of failure retry up to 10 times, with 500ms delay in between if (String.IsNullOrEmpty(modernSiteUrl)) { Thread.Sleep(TimeSpan.FromMilliseconds(delay * (retryCount - driveRetryCount))); driveRetryCount--; } } group.SiteUrl = modernSiteUrl; } } #region Handle group's owners if (owners != null && owners.Length > 0) { // For each and every owner foreach (var o in owners) { // Search for the user object var ownerQuery = await graphClient.Users .Request() .Filter($"userPrincipalName eq '{o}'") .GetAsync(); var owner = ownerQuery.FirstOrDefault(); if (owner != null) { try { // And if any, add it to the collection of group's owners await graphClient.Groups[addedGroup.Id].Owners.References.Request().AddAsync(owner); } catch (ServiceException ex) { if (ex.Error.Code == "Request_BadRequest" && ex.Error.Message.Contains("added object references already exist")) { // Skip any already existing owner } else { throw ex; } } } } } #endregion #region Handle group's members if (members != null && members.Length > 0) { // For each and every owner foreach (var m in members) { // Search for the user object var memberQuery = await graphClient.Users .Request() .Filter($"userPrincipalName eq '{m}'") .GetAsync(); var member = memberQuery.FirstOrDefault(); if (member != null) { try { // And if any, add it to the collection of group's owners await graphClient.Groups[addedGroup.Id].Members.References.Request().AddAsync(member); } catch (ServiceException ex) { if (ex.Error.Code == "Request_BadRequest" && ex.Error.Message.Contains("added object references already exist")) { // Skip any already existing member } else { throw ex; } } } } } #endregion return (group); }).GetAwaiter().GetResult(); return (result); }
/// <summary> /// Get an Office 365 Group (i.e. Unified Group) by Id /// </summary> /// <param name="groupId">The ID of the Office 365 Group</param> /// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</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> public static UnifiedGroupEntity GetUnifiedGroup(String groupId, String accessToken, int retryCount = 10, int delay = 500) { if (String.IsNullOrEmpty(groupId)) { throw new ArgumentNullException("groupId"); } if (String.IsNullOrEmpty(accessToken)) { throw new ArgumentNullException("accessToken"); } // Use a synchronous model to invoke the asynchronous process var result = Task.Run(async () => { UnifiedGroupEntity group = null; var graphClient = CreateGraphClient(accessToken, retryCount, delay); var g = await graphClient.Groups[groupId].Request().GetAsync(); group = new UnifiedGroupEntity { GroupId = g.Id, DisplayName = g.DisplayName, Description = g.Description, Mail = g.Mail, MailNickname = g.MailNickname, SiteUrl = GetUnifiedGroupSiteUrl(groupId, accessToken), }; return (group); }).GetAwaiter().GetResult(); return (result); }
/// <summary> /// Returns all the Office 365 Groups in the current Tenant based on a startIndex. IncludeSite adds additional properties about the Modern SharePoint Site backing the group /// </summary> /// <param name="accessToken">The OAuth 2.0 Access Token to use for invoking the Microsoft Graph</param> /// <param name="displayName">The DisplayName of the Office 365 Group</param> /// <param name="mailNickname">The MailNickname of the Office 365 Group</param> /// <param name="startIndex">Not relevant anymore</param> /// <param name="endIndex">Not relevant anymore</param> /// <param name="includeSite">Defines whether to return details about the Modern SharePoint Site backing the group. Default is true.</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> /// <returns>An IList of SiteEntity objects</returns> public static List<UnifiedGroupEntity> ListUnifiedGroups(string accessToken, String displayName = null, string mailNickname = null, int startIndex = 0, int endIndex = 999, bool includeSite = true, int retryCount = 10, int delay = 500) { if (String.IsNullOrEmpty(accessToken)) { throw new ArgumentNullException("accessToken"); } List<UnifiedGroupEntity> result = null; // Use a synchronous model to invoke the asynchronous process result = Task.Run(async () => { List<UnifiedGroupEntity> groups = new List<UnifiedGroupEntity>(); var graphClient = CreateGraphClient(accessToken, retryCount, delay); // Apply the DisplayName filter, if any var displayNameFilter = !String.IsNullOrEmpty(displayName) ? $" and startswith(DisplayName,'{displayName}')" : String.Empty; var mailNicknameFilter = !String.IsNullOrEmpty(mailNickname) ? $" and startswith(MailNickname,'{mailNickname}')" : String.Empty; var pagedGroups = await graphClient.Groups .Request() .Filter($"groupTypes/any(grp: grp eq 'Unified'){displayNameFilter}{mailNicknameFilter}") .Top(endIndex) .GetAsync(); Int32 pageCount = 0; Int32 currentIndex = 0; while (true) { pageCount++; foreach (var g in pagedGroups) { currentIndex++; if (currentIndex >= startIndex) { var group = new UnifiedGroupEntity { GroupId = g.Id, DisplayName = g.DisplayName, Description = g.Description, Mail = g.Mail, MailNickname = g.MailNickname, }; if (includeSite) { group.SiteUrl = GetUnifiedGroupSiteUrl(g.Id, accessToken); } groups.Add(group); } } if (pagedGroups.NextPageRequest != null && groups.Count < endIndex) { pagedGroups = await pagedGroups.NextPageRequest.GetAsync(); } else { break; } } return (groups); }).GetAwaiter().GetResult(); return (result); }
public UnifiedGroupPipeBind(UnifiedGroupEntity group) { _group = group; }