public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("ProvisionTeam function invoked."); try { // Get request body string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); var request = JsonConvert.DeserializeObject <TeamProvisionRequest>(requestBody); if (!String.IsNullOrEmpty(request.TeamTemplateUri)) { // Get the URL of the root site collection var rootSiteUrl = request.RequestSiteUrl.Substring(0, request.RequestSiteUrl.IndexOf("/", 10)); // Get the provisioning template based on the provided URI var templateUri = new Uri(new Uri(request.RequestSiteUrl), request.TeamTemplateUri).AbsoluteUri; var tenantTemplate = _templatesProvider.GetTenantTemplate(templateUri); if (tenantTemplate.Teams != null && tenantTemplate.Teams.Teams != null && tenantTemplate.Teams.Teams.Count > 0) { // Get the first team template var team = tenantTemplate.Teams.Teams[0]; // Configure Team properties team.DisplayName = request.TeamTitle; team.MailNickname = request.TeamAlias.ToLower(); // Configure Team security team.Security = new OfficeDevPnP.Core.Framework.Provisioning.Model.Teams.TeamSecurity(); foreach (var owner in request.TeamOwners) { team.Security.Owners.Add(new OfficeDevPnP.Core.Framework.Provisioning.Model.Teams.TeamSecurityUser { UserPrincipalName = owner.UPN }); } foreach (var member in request.TeamMembers) { team.Security.Members.Add(new OfficeDevPnP.Core.Framework.Provisioning.Model.Teams.TeamSecurityUser { UserPrincipalName = member.UPN }); } // Provision the template onto the target tenant SPOUtilities.ApplyTenantTemplate(rootSiteUrl, tenantTemplate, log); } } else { throw new ApplicationException("Invalid input request! Missing Team Template URI!"); } } catch (Exception ex) { return(new ExceptionResult(ex, true)); } return(new OkObjectResult("All good!")); }
/// <summary> /// Applies a Provisioning Template Hierarchy to a target tenant /// </summary> /// <param name="targetSiteUrl">The URL of the target Site Collection</param> /// <param name="tenantTemplate">The Provisioning Template Hierarchy to apply</param> /// <param name="log">The TraceWriter to log activities</param> public static void ApplyTenantTemplate(String targetSiteUrl, ProvisioningHierarchy tenantTemplate, ILogger log) { ProvisioningTemplateApplyingInformation ptai = new ProvisioningTemplateApplyingInformation(); // We exclude Term Groups because they are not supported in AppOnly ptai.HandlersToProcess = Handlers.All; ptai.HandlersToProcess ^= Handlers.TermGroups; ptai.MessagesDelegate += delegate(string message, ProvisioningMessageType messageType) { log.LogDebug($"{messageType} - {message}"); }; ptai.ProgressDelegate += delegate(string message, int step, int total) { log.LogInformation($"{step:00}/{total:00} - {message}"); }; var tenantUrl = SPOUtilities.GetTenantAdministrationUrl(targetSiteUrl); using (var tenantContext = SPOContextProvider.BuildAppOnlyClientContext(tenantUrl)) { using (var pnpTenantContext = PnPClientContext.ConvertFrom(tenantContext)) { var tenant = new Microsoft.Online.SharePoint.TenantAdministration.Tenant(pnpTenantContext); // Prepare a dictionary to hold the access tokens var accessTokens = new Dictionary <String, String>(); // Get the Microsoft Graph Access Token var clientApplication = ConfidentialClientApplicationBuilder .Create(Environment.GetEnvironmentVariable("ClientId")) .WithTenantId(Environment.GetEnvironmentVariable("Tenant")) .WithClientSecret(Environment.GetEnvironmentVariable("ClientSecret")).Build(); try { string[] graphScopes = new string[] { "https://graph.microsoft.com/.default" }; var authenticationResult = clientApplication.AcquireTokenForClient(graphScopes).ExecuteAsync().GetAwaiter().GetResult(); var graphAccessToken = authenticationResult.AccessToken; accessTokens.Add(new Uri("https://graph.microsoft.com/").Authority, graphAccessToken); } catch (Exception ex) { log.LogError(ex.Message); throw; } // Configure the OAuth Access Tokens for the PnPClientContext, too pnpTenantContext.PropertyBag["AccessTokens"] = accessTokens; ptai.AccessTokens = accessTokens; // Define a PnPProvisioningContext scope to share the security context across calls using (var pnpProvisioningContext = new PnPProvisioningContext(async(r, s) => { if (accessTokens.Any(i => i.Key.Equals(r, StringComparison.InvariantCultureIgnoreCase) || r.ToLower().Contains(i.Key))) { // In this scenario we just use the dictionary of access tokens // in fact the overall operation for sure will take less than 1 hour var item = accessTokens.FirstOrDefault(i => i.Key.Equals(r, StringComparison.InvariantCultureIgnoreCase) || r.ToLower().Contains(i.Key)); return(await Task.FromResult(item.Value)); } else { return(null); } })) { log.LogInformation($"Hierarchy Provisioning Started: {DateTime.Now:hh.mm.ss}"); tenant.ApplyProvisionHierarchy(tenantTemplate, null, ptai); log.LogInformation($"Hierarchy Provisioning Completed: {DateTime.Now:hh.mm.ss}"); } } } }