internal ApplyConfiguration GetConfiguration(string currentFileSystemLocation) { if (objectValue != null) { return(objectValue); } if (!string.IsNullOrEmpty(value)) { // is it a path? try { string path = value; if (!System.IO.Path.IsPathRooted(value)) { path = System.IO.Path.Combine(currentFileSystemLocation, path); } if (System.IO.File.Exists(path)) { return(ApplyConfiguration.FromString(System.IO.File.ReadAllText(path))); } else { return(ApplyConfiguration.FromString(value)); } } catch { return(null); } } return(null); }
public static void ApplyProvisionHierarchy(this Tenant tenant, ProvisioningHierarchy hierarchy, string sequenceId, ProvisioningTemplateApplyingInformation applyingInformation = null) { if (applyingInformation == null) { ApplyTenantTemplate(tenant, hierarchy, sequenceId); } else { ApplyTenantTemplate(tenant, hierarchy, sequenceId, ApplyConfiguration.FromApplyingInformation(applyingInformation)); } }
public override TokenParser ProvisionObjects(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, TokenParser parser, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(this.Name)) { foreach (var sequence in hierarchy.Sequences) { this.reusedTerms = new List <TermGroupHelper.ReusedTerm>(); var context = tenant.Context as ClientContext; TaxonomySession taxSession = TaxonomySession.GetTaxonomySession(context); TermStore termStore = null; try { termStore = taxSession.GetDefaultKeywordsTermStore(); context.Load(termStore, ts => ts.Languages, ts => ts.DefaultLanguage, ts => ts.Groups.Include( tg => tg.Name, tg => tg.Id, tg => tg.TermSets.Include( tset => tset.Name, tset => tset.Id))); context.ExecuteQueryRetry(); } catch (ServerException) { WriteMessage("Failed to retrieve existing terms", ProvisioningMessageType.Error); return(parser); } foreach (var modelTermGroup in sequence.TermStore.TermGroups) { this.reusedTerms.AddRange(TermGroupHelper.ProcessGroup(context, taxSession, termStore, modelTermGroup, null, parser, scope)); } foreach (var reusedTerm in this.reusedTerms) { TermGroupHelper.TryReuseTerm(context, reusedTerm.ModelTerm, reusedTerm.Parent, reusedTerm.TermStore, parser, scope); } } } return(parser); }
public override TokenParser ProvisionObjects(Tenant tenant, ProvisioningHierarchy hierarchy, string sequenceId, TokenParser parser, ApplyConfiguration configuration) { #if !ONPREMISES using (var scope = new PnPMonitoredScope(Name)) { // Prepare a method global variable to store the Access Token String accessToken = null; // - Teams based on JSON templates var users = hierarchy.AzureActiveDirectory?.Users; if (users != null && users.Any()) { foreach (var u in users) { // Get a fresh Access Token for every request accessToken = PnPProvisioningContext.Current.AcquireToken(GraphHelper.MicrosoftGraphBaseURI, "User.ReadWrite.All"); // Creates or updates the User starting from the provisioning template definition var userId = CreateOrUpdateUser(scope, parser, u, accessToken); // If the user got created if (userId != null) { if (u.Licenses != null && u.Licenses.Count > 0) { // Manage the licensing settings ManageUserLicenses(scope, userId, u.Licenses, accessToken); } // So far the User's photo cannot be set if we don't have an already existing mailbox // SetUserPhoto(scope, parser, hierarchy.Connector, u, (String)userId, accessToken); } } } } #endif return(parser); }
public override bool WillProvision(Tenant tenant, ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { #if !ONPREMISES if (!_willProvision.HasValue) { _willProvision = hierarchy.AzureActiveDirectory?.Users?.Any(); } #else if (!_willProvision.HasValue) { _willProvision = false; } #endif return(_willProvision.Value); }
protected override void ExecuteCmdlet() { var sitesProvisioned = new List <ProvisionedSite>(); var configuration = new ApplyConfiguration(); if (ParameterSpecified(nameof(Configuration))) { configuration = Configuration.GetConfiguration(SessionState.Path.CurrentFileSystemLocation.Path); } configuration.SiteProvisionedDelegate = (title, url) => { if (sitesProvisioned.FirstOrDefault(s => s.Url == url) == null) { sitesProvisioned.Add(new ProvisionedSite() { Title = title, Url = url }); } }; if (ParameterSpecified(nameof(Handlers))) { if (!Handlers.Has(Handlers.All)) { foreach (var enumValue in (Handlers[])Enum.GetValues(typeof(Handlers))) { if (Handlers.Has(enumValue)) { if (enumValue == Handlers.TermGroups) { configuration.Handlers.Add(ConfigurationHandler.Taxonomy); } else if (enumValue == Handlers.PageContents) { configuration.Handlers.Add(ConfigurationHandler.Pages); } else if (Enum.TryParse <ConfigurationHandler>(enumValue.ToString(), out ConfigurationHandler configHandler)) { configuration.Handlers.Add(configHandler); } } } } } if (ParameterSpecified(nameof(ExcludeHandlers))) { foreach (var handler in (Handlers[])Enum.GetValues(typeof(Handlers))) { if (!ExcludeHandlers.Has(handler) && handler != Handlers.All) { if (handler == Handlers.TermGroups) { if (configuration.Handlers.Contains(ConfigurationHandler.Taxonomy)) { configuration.Handlers.Remove(ConfigurationHandler.Taxonomy); } else if (Enum.TryParse <ConfigurationHandler>(handler.ToString(), out ConfigurationHandler configHandler)) { if (configuration.Handlers.Contains(configHandler)) { configuration.Handlers.Remove(configHandler); } } } } } } if (ExtensibilityHandlers != null) { configuration.Extensibility.Handlers = ExtensibilityHandlers.ToList(); } configuration.ProgressDelegate = (message, step, total) => { if (message != null) { var percentage = Convert.ToInt32((100 / Convert.ToDouble(total)) * Convert.ToDouble(step)); progressRecord.Activity = $"Applying template to tenant"; progressRecord.StatusDescription = message; progressRecord.PercentComplete = percentage; progressRecord.RecordType = ProgressRecordType.Processing; WriteProgress(progressRecord); } }; var warningsShown = new List <string>(); configuration.MessagesDelegate = (message, type) => { switch (type) { case ProvisioningMessageType.Warning: { if (!warningsShown.Contains(message)) { WriteWarning(message); warningsShown.Add(message); } break; } case ProvisioningMessageType.Progress: { if (message != null) { var activity = message; if (message.IndexOf("|") > -1) { var messageSplitted = message.Split('|'); if (messageSplitted.Length == 4) { var current = double.Parse(messageSplitted[2]); var total = double.Parse(messageSplitted[3]); subProgressRecord.RecordType = ProgressRecordType.Processing; subProgressRecord.Activity = string.IsNullOrEmpty(messageSplitted[0]) ? "-" : messageSplitted[0]; subProgressRecord.StatusDescription = string.IsNullOrEmpty(messageSplitted[1]) ? "-" : messageSplitted[1]; subProgressRecord.PercentComplete = Convert.ToInt32((100 / total) * current); WriteProgress(subProgressRecord); } else { subProgressRecord.Activity = "Processing"; subProgressRecord.RecordType = ProgressRecordType.Processing; subProgressRecord.StatusDescription = activity; subProgressRecord.PercentComplete = 0; WriteProgress(subProgressRecord); } } else { subProgressRecord.Activity = "Processing"; subProgressRecord.RecordType = ProgressRecordType.Processing; subProgressRecord.StatusDescription = activity; subProgressRecord.PercentComplete = 0; WriteProgress(subProgressRecord); } } break; } case ProvisioningMessageType.Completed: { WriteProgress(new ProgressRecord(1, message, " ") { RecordType = ProgressRecordType.Completed }); break; } } }; configuration.PropertyBag.OverwriteSystemValues = OverwriteSystemPropertyBagValues; configuration.Lists.IgnoreDuplicateDataRowErrors = IgnoreDuplicateDataRowErrors; configuration.Navigation.ClearNavigation = ClearNavigation; configuration.ContentTypes.ProvisionContentTypesToSubWebs = ProvisionContentTypesToSubWebs; configuration.Fields.ProvisionFieldsToSubWebs = ProvisionFieldsToSubWebs; ProvisioningHierarchy hierarchyToApply = null; switch (ParameterSetName) { case ParameterSet_PATH: { hierarchyToApply = GetHierarchy(); break; } case ParameterSet_OBJECT: { hierarchyToApply = Template; if (ResourceFolder != null) { var fileSystemConnector = new FileSystemConnector(ResourceFolder, ""); hierarchyToApply.Connector = fileSystemConnector; } else { if (Path != null) { if (!System.IO.Path.IsPathRooted(Path)) { Path = System.IO.Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, Path); } } else { Path = SessionState.Path.CurrentFileSystemLocation.Path; } var fileInfo = new FileInfo(Path); var fileConnector = new FileSystemConnector(fileInfo.DirectoryName, ""); hierarchyToApply.Connector = fileConnector; } break; } } if (Parameters != null) { foreach (var parameter in Parameters.Keys) { if (hierarchyToApply.Parameters.ContainsKey(parameter.ToString())) { hierarchyToApply.Parameters[parameter.ToString()] = Parameters[parameter].ToString(); } else { hierarchyToApply.Parameters.Add(parameter.ToString(), Parameters[parameter].ToString()); } } } #if !ONPREMISES // check if consent is needed and in place var consentRequired = false; if (hierarchyToApply.Teams != null) { consentRequired = true; } if (hierarchyToApply.AzureActiveDirectory != null) { consentRequired = true; } if (consentRequired) { // try to retrieve an access token for the Microsoft Graph: var accessToken = PnPConnection.CurrentConnection.TryGetAccessToken(Enums.TokenAudience.MicrosoftGraph); if (accessToken == null) { if (PnPConnection.CurrentConnection.PSCredential != null) { // Using normal credentials accessToken = TokenHandler.AcquireToken("graph.microsoft.com", null); } if (accessToken == null) { throw new PSInvalidOperationException("Your template contains artifacts that require an access token. Please provide consent to the PnP Management Shell application first by executing: Connect-PnPOnline -Graph -LaunchBrowser"); } } } using (var provisioningContext = new PnPProvisioningContext((resource, scope) => { if (resource.ToLower().StartsWith("https://")) { var uri = new Uri(resource); resource = uri.Authority; } // Get Azure AD Token if (PnPConnection.CurrentConnection != null) { if (resource.Equals("graph.microsoft.com", StringComparison.OrdinalIgnoreCase)) { var graphAccessToken = PnPConnection.CurrentConnection.TryGetAccessToken(Enums.TokenAudience.MicrosoftGraph); if (graphAccessToken != null) { // Authenticated using -Graph or using another way to retrieve the accesstoken with Connect-PnPOnline return(Task.FromResult(graphAccessToken)); } } } if (PnPConnection.CurrentConnection.PSCredential != null) { // Using normal credentials return(Task.FromResult(TokenHandler.AcquireToken(resource, null))); } else { // No token... throw new PSInvalidOperationException("Your template contains artifacts that require an access token. Please provide consent to the PnP Management Shell application first by executing: Connect-PnPOnline -Graph -LaunchBrowser"); } })) { #endif if (!string.IsNullOrEmpty(SequenceId)) { Tenant.ApplyTenantTemplate(hierarchyToApply, SequenceId, configuration); } else { if (hierarchyToApply.Sequences.Count > 0) { foreach (var sequence in hierarchyToApply.Sequences) { Tenant.ApplyTenantTemplate(hierarchyToApply, sequence.ID, configuration); } } else { Tenant.ApplyTenantTemplate(hierarchyToApply, null, configuration); } } #if !ONPREMISES } #endif WriteObject(sitesProvisioned, true); }
public override bool WillProvision(Tenant tenant, ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { if (!_willProvision.HasValue && hierarchy.Tenant != null) { _willProvision = ((hierarchy.Tenant.AppCatalog?.Packages != null && hierarchy.Tenant.AppCatalog?.Packages.Count > 0) || hierarchy.Tenant.ContentDeliveryNetwork != null || (hierarchy.Tenant.SiteDesigns != null && hierarchy.Tenant.SiteDesigns.Count > 0) || (hierarchy.Tenant.SiteScripts != null && hierarchy.Tenant.SiteScripts.Count > 0) || (hierarchy.Tenant.StorageEntities != null && hierarchy.Tenant.StorageEntities.Count > 0) || (hierarchy.Tenant.WebApiPermissions != null && hierarchy.Tenant.WebApiPermissions.Count > 0) || (hierarchy.Tenant.Themes != null && hierarchy.Tenant.Themes.Count > 0) || (hierarchy.Tenant.SPUsersProfiles != null && hierarchy.Tenant.SPUsersProfiles.Count > 0) || (hierarchy.Tenant.Office365GroupLifecyclePolicies != null && hierarchy.Tenant.Office365GroupLifecyclePolicies.Count > 0) || (hierarchy.Tenant.Office365GroupsSettings?.Properties != null && hierarchy.Tenant.Office365GroupsSettings?.Properties.Count > 0) ); } return(_willProvision.Value); }
public override TokenParser ProvisionObjects(Tenant tenant, ProvisioningHierarchy hierarchy, string sequenceId, TokenParser parser, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(this.Name)) { if (hierarchy.Tenant != null) { TenantHelper.ProcessCdns(tenant, hierarchy.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessApps(tenant, hierarchy.Tenant, hierarchy.Connector, parser, scope, configuration, MessagesDelegate); try { parser = TenantHelper.ProcessWebApiPermissions(tenant, hierarchy.Tenant, parser, scope, MessagesDelegate); } catch (ServerUnauthorizedAccessException ex) { scope.LogError(ex.Message); } parser = TenantHelper.ProcessSiteScripts(tenant, hierarchy.Tenant, hierarchy.Connector, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessSiteDesigns(tenant, hierarchy.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessStorageEntities(tenant, hierarchy.Tenant, parser, scope, configuration, MessagesDelegate); parser = TenantHelper.ProcessThemes(tenant, hierarchy.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessUserProfiles(tenant, hierarchy.Tenant, parser, scope, MessagesDelegate); // So far we do not provision CDN settings // It will come in the near future // NOOP on CDN } } return(parser); }
internal static TokenParser ProcessStorageEntities(Tenant tenant, ProvisioningTenant provisioningTenant, TokenParser parser, PnPMonitoredScope scope, ApplyConfiguration configuration, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.StorageEntities != null && provisioningTenant.StorageEntities.Any()) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); using (var context = ((ClientContext)tenant.Context).Clone(rootSiteUrl.Value, configuration.AccessTokens)) { var web = context.Web; Uri appCatalogUri = null; try { appCatalogUri = web.GetAppCatalog(); } catch (System.Net.WebException ex) { if (ex.Response != null) { var httpResponse = ex.Response as System.Net.HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.Unauthorized) { // Ignore any security exception and simply keep // the AppCatalog URI null } else { throw ex; } } else { throw ex; } } if (appCatalogUri != null) { using (var appCatalogContext = context.Clone(appCatalogUri, configuration.AccessTokens)) { foreach (var entity in provisioningTenant.StorageEntities) { var key = parser.ParseString(entity.Key); var value = parser.ParseString(entity.Value); var description = parser.ParseString(entity.Description); var comment = parser.ParseString(entity.Comment); appCatalogContext.Web.SetStorageEntity(key, value, description, comment); } appCatalogContext.Web.Update(); appCatalogContext.ExecuteQueryRetry(); } } else { messagesDelegate?.Invoke($"Tenant app catalog doesn't exist. Provisioning of storage entities will be skipped!", ProvisioningMessageType.Warning); } } } return(parser); }
internal void ApplyTenantTemplate(Tenant tenant, PnP.Framework.Provisioning.Model.ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { ProvisioningProgressDelegate progressDelegate = null; ProvisioningMessagesDelegate messagesDelegate = null; if (configuration == null) { // When no provisioning info was passed then we want to execute all handlers configuration = new ApplyConfiguration(); } else { progressDelegate = configuration.ProgressDelegate; if (configuration.ProgressDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_ProgressDelegate_registered); } messagesDelegate = configuration.MessagesDelegate; if (configuration.MessagesDelegate != null) { scope.LogInfo(CoreResources.SiteToTemplateConversion_MessagesDelegate_registered); } } List <ObjectHierarchyHandlerBase> objectHandlers = new List <ObjectHierarchyHandlerBase> { new ObjectHierarchyTenant(), new ObjectHierarchySequenceTermGroups(), new ObjectHierarchySequenceSites(), new ObjectTeams(), new ObjectAzureActiveDirectory(), }; var count = objectHandlers.Count(o => o.ReportProgress && o.WillProvision(tenant, hierarchy, sequenceId, configuration)) + 1; progressDelegate?.Invoke("Initializing engine", 1, count); // handlers + initializing message) int step = 2; TokenParser sequenceTokenParser = new TokenParser(tenant, hierarchy); CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningStarted); foreach (var handler in objectHandlers) { if (handler.WillProvision(tenant, hierarchy, sequenceId, configuration)) { if (messagesDelegate != null) { handler.MessagesDelegate = messagesDelegate; } if (handler.ReportProgress && progressDelegate != null) { progressDelegate(handler.Name, step, count); step++; } try { sequenceTokenParser = handler.ProvisionObjects(tenant, hierarchy, sequenceId, sequenceTokenParser, configuration); } catch (Exception ex) { CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningExceptionOccurred, handler.Name, ex); throw; } } } CallWebHooks(hierarchy.Templates.FirstOrDefault(), sequenceTokenParser, ProvisioningTemplateWebhookKind.ProvisioningCompleted); } }
public override TokenParser ProvisionObjects(Web web, ProvisioningTemplate template, TokenParser parser, ProvisioningTemplateApplyingInformation applyingInformation) { web.EnsureProperty(w => w.Url); using (var scope = new PnPMonitoredScope(this.Name)) { if (template.Tenant != null) { using (var tenantContext = web.Context.Clone(web.GetTenantAdministrationUrl())) { var tenant = new Tenant(tenantContext); TenantHelper.ProcessCdns(tenant, template.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessApps(tenant, template.Tenant, template.Connector, parser, scope, ApplyConfiguration.FromApplyingInformation(applyingInformation), MessagesDelegate); try { parser = TenantHelper.ProcessWebApiPermissions(tenant, template.Tenant, parser, scope, MessagesDelegate); } catch (ServerUnauthorizedAccessException ex) { scope.LogError(ex.Message); } parser = TenantHelper.ProcessSiteScripts(tenant, template.Tenant, template.Connector, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessSiteDesigns(tenant, template.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessStorageEntities(tenant, template.Tenant, parser, scope, ApplyConfiguration.FromApplyingInformation(applyingInformation), MessagesDelegate); parser = TenantHelper.ProcessThemes(tenant, template.Tenant, parser, scope, MessagesDelegate); parser = TenantHelper.ProcessUserProfiles(tenant, template.Tenant, parser, scope, MessagesDelegate); } } } return(parser); }
public void ProvisionTenantTemplate() { if (TestCommon.AppOnlyTesting()) { Assert.Inconclusive("This test does not yet work with app-only due to group connected site creation"); } string tenantNameParamValue = new Uri(TestCommon.DevSiteUrl).DnsSafeHost.Split('.')[0]; string accountDomainParamValue = TestCommon.O365AccountDomain; if (string.IsNullOrEmpty(accountDomainParamValue)) { accountDomainParamValue = "contoso.com"; } var resourceFolder = string.Format(@"{0}\..\..\..\Resources\Templates", AppDomain.CurrentDomain.BaseDirectory); XMLTemplateProvider provider = new XMLFileSystemTemplateProvider(resourceFolder, ""); var existingTemplate = provider.GetTemplate("ProvisioningSchema-2021-03-FullSample-01.xml"); Guid siteGuid = Guid.NewGuid(); int siteId = siteGuid.GetHashCode(); var template = new ProvisioningTemplate { Id = "TestTemplate" }; template.Lists.Add(new ListInstance() { Title = "Testlist", TemplateType = 100, Url = "lists/testlist" }); template.TermGroups.AddRange(existingTemplate.TermGroups); ProvisioningHierarchy hierarchy = new ProvisioningHierarchy(); hierarchy.Templates.Add(template); hierarchy.Parameters.Add("CompanyName", "Contoso"); if (!string.IsNullOrEmpty(tenantNameParamValue)) { hierarchy.Parameters.Add("O365TenantName", tenantNameParamValue); } if (!string.IsNullOrEmpty(accountDomainParamValue)) { hierarchy.Parameters.Add("O365AccountDomain", accountDomainParamValue); } var sequence = new ProvisioningSequence { ID = Guid.NewGuid().ToString(), TermStore = new ProvisioningTermStore() }; var termGroup = new TermGroup() { Name = "Contoso TermGroup" }; var termSet = new TermSet() { Name = "Projects", Id = Guid.NewGuid(), IsAvailableForTagging = true, Language = 1033 }; var term = new Term() { Name = "Contoso Term" }; termSet.Terms.Add(term); // termGroup.TermSets.Add(termSet); var existingTermSet = existingTemplate.TermGroups[0].TermSets[0]; termGroup.TermSets.Add(existingTermSet); // sequence.TermStore.TermGroups.Add(termGroup); var teamSite1 = new TeamSiteCollection() { Alias = $"prov-1-{siteId}", Description = "prov-1", DisplayName = "prov-1", IsHubSite = false, IsPublic = false, Title = "prov-1", }; teamSite1.Templates.Add("TestTemplate"); var subsite = new TeamNoGroupSubSite() { Description = "Test Sub", Url = "testsub1", Language = 1033, TimeZoneId = 4, Title = "Test Sub", UseSamePermissionsAsParentSite = true }; subsite.Templates.Add("TestTemplate"); teamSite1.Sites.Add(subsite); sequence.SiteCollections.Add(teamSite1); var teamSite2 = new TeamSiteCollection() { Alias = $"prov-2-{siteId}", Description = "prov-2", DisplayName = "prov-2", IsHubSite = false, IsPublic = false, Title = "prov-2" }; teamSite2.Templates.Add("TestTemplate"); sequence.SiteCollections.Add(teamSite2); hierarchy.Sequences.Add(sequence); using (var tenantContext = TestCommon.CreateTenantClientContext()) { var applyConfiguration = new ApplyConfiguration { ProgressDelegate = (message, step, total) => { if (message != null) { } } }; var tenant = new Tenant(tenantContext); tenant.ApplyTenantTemplate(hierarchy, sequence.ID, applyConfiguration); } }
public abstract TokenParser ProvisionObjects(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, TokenParser parser, ApplyConfiguration configuration);
public abstract bool WillProvision(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration);
public ApplyConfigurationPipeBind(ApplyConfiguration configuration) { objectValue = configuration; }
public override TokenParser ProvisionObjects(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, TokenParser tokenParser, ApplyConfiguration configuration) { using (var scope = new PnPMonitoredScope(CoreResources.Provisioning_ObjectHandlers_Provisioning)) { bool nowait = false; if (configuration != null) { nowait = configuration.Tenant.DoNotWaitForSitesToBeFullyCreated; } var sequence = hierarchy.Sequences.FirstOrDefault(s => s.ID == sequenceId); if (sequence != null) { var siteUrls = new Dictionary <Guid, string>(); TokenParser siteTokenParser = null; var tenantThemes = tenant.GetAllTenantThemes(); tenant.Context.Load(tenantThemes); tenant.Context.ExecuteQueryRetry(); foreach (var sitecollection in sequence.SiteCollections) { ClientContext siteContext = null; switch (sitecollection) { case TeamSiteCollection t: { TeamSiteCollectionCreationInformation siteInfo = new TeamSiteCollectionCreationInformation() { Alias = tokenParser.ParseString(t.Alias), DisplayName = tokenParser.ParseString(t.Title), Description = tokenParser.ParseString(t.Description), Classification = tokenParser.ParseString(t.Classification), IsPublic = t.IsPublic, Lcid = (uint)t.Language }; if (Guid.TryParse(t.SiteDesign, out Guid siteDesignId)) { siteInfo.SiteDesignId = siteDesignId; } var groupSiteInfo = Sites.SiteCollection.GetGroupInfoAsync(tenant.Context as ClientContext, siteInfo.Alias).GetAwaiter().GetResult(); if (groupSiteInfo == null) { string graphAccessToken = null; try { graphAccessToken = PnPProvisioningContext.Current.AcquireCookie(Core.Utilities.Graph.GraphHelper.MicrosoftGraphBaseURI); } catch { graphAccessToken = PnPProvisioningContext.Current.AcquireToken(Core.Utilities.Graph.GraphHelper.MicrosoftGraphBaseURI, null); } WriteMessage($"Creating Team Site {siteInfo.Alias}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait, graphAccessToken: graphAccessToken); } else { if (groupSiteInfo.ContainsKey("siteUrl")) { WriteMessage($"Using existing Team Site {siteInfo.Alias}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(groupSiteInfo["siteUrl"], configuration.AccessTokens); } } if (t.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteContext.Url, siteContext.Site.Id, t.HubSiteLogoUrl, t.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(t.Theme)) { var parsedTheme = tokenParser.ParseString(t.Theme); if (tenantThemes.FirstOrDefault(th => th.Name == parsedTheme) != null) { tenant.SetWebTheme(parsedTheme, siteContext.Url); tenant.Context.ExecuteQueryRetry(); } else { WriteMessage($"Theme {parsedTheme} doesn't exist in the tenant, will not be applied", ProvisioningMessageType.Warning); } } if (t.Teamify) { try { WriteMessage($"Teamifying the O365 group connected site at URL - {siteContext.Url}", ProvisioningMessageType.Progress); siteContext.TeamifyAsync().GetAwaiter().GetResult(); } catch (Exception ex) { WriteMessage($"Teamifying site at URL - {siteContext.Url} failed due to an exception:- {ex.Message}", ProvisioningMessageType.Warning); } } if (t.HideTeamify) { try { WriteMessage($"Teamify prompt is now hidden for site at URL - {siteContext.Url}", ProvisioningMessageType.Progress); siteContext.HideTeamifyPrompt().GetAwaiter().GetResult(); } catch (Exception ex) { WriteMessage($"Teamify prompt couldn't be hidden for site at URL - {siteContext.Url} due to an exception:- {ex.Message}", ProvisioningMessageType.Warning); } } siteUrls.Add(t.Id, siteContext.Url); if (!string.IsNullOrEmpty(t.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, t.ProvisioningId, siteContext.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, t.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, t.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, t.ProvisioningId, siteContext.Site.GroupId)); } break; } case CommunicationSiteCollection c: { var siteUrl = tokenParser.ParseString(c.Url); if (!siteUrl.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); siteUrl = UrlUtility.Combine(rootSiteUrl.Value, siteUrl); } CommunicationSiteCollectionCreationInformation siteInfo = new CommunicationSiteCollectionCreationInformation() { ShareByEmailEnabled = c.AllowFileSharingForGuestUsers, Classification = tokenParser.ParseString(c.Classification), Description = tokenParser.ParseString(c.Description), Lcid = (uint)c.Language, Owner = tokenParser.ParseString(c.Owner), Title = tokenParser.ParseString(c.Title), Url = siteUrl }; if (Guid.TryParse(c.SiteDesign, out Guid siteDesignId)) { siteInfo.SiteDesignId = siteDesignId; } else { if (!string.IsNullOrEmpty(c.SiteDesign)) { siteInfo.SiteDesign = (CommunicationSiteDesign)Enum.Parse(typeof(CommunicationSiteDesign), c.SiteDesign); } else { siteInfo.SiteDesign = CommunicationSiteDesign.Showcase; } } // check if site exists if (tenant.SiteExistsAnywhere(siteInfo.Url) == SiteExistence.Yes) { WriteMessage($"Using existing Communications Site at {siteInfo.Url}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(siteInfo.Url, configuration.AccessTokens); } else if (tenant.SiteExistsAnywhere(siteInfo.Url) == SiteExistence.Recycled) { var errorMessage = $"The requested Communications Site at {siteInfo.Url} is in the Recycle Bin and cannot be created"; WriteMessage(errorMessage, ProvisioningMessageType.Error); throw new RecycledSiteException(errorMessage); } else { WriteMessage($"Creating Communications Site at {siteInfo.Url}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait); } if (c.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteInfo.Url, siteContext.Site.Id, c.HubSiteLogoUrl, c.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(c.Theme)) { var parsedTheme = tokenParser.ParseString(c.Theme); if (tenantThemes.FirstOrDefault(th => th.Name == parsedTheme) != null) { tenant.SetWebTheme(parsedTheme, siteInfo.Url); tenant.Context.ExecuteQueryRetry(); } else { WriteMessage($"Theme {parsedTheme} doesn't exist in the tenant, will not be applied", ProvisioningMessageType.Warning); } } siteUrls.Add(c.Id, siteInfo.Url); if (!string.IsNullOrEmpty(c.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, c.ProvisioningId, siteInfo.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, c.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, c.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, c.ProvisioningId, siteContext.Site.GroupId)); } break; } case TeamNoGroupSiteCollection t: { var siteUrl = tokenParser.ParseString(t.Url); TeamNoGroupSiteCollectionCreationInformation siteInfo = new TeamNoGroupSiteCollectionCreationInformation() { Lcid = (uint)t.Language, Url = siteUrl, Title = tokenParser.ParseString(t.Title), Description = tokenParser.ParseString(t.Description), Owner = tokenParser.ParseString(t.Owner) }; if (tenant.SiteExistsAnywhere(siteUrl) == SiteExistence.Yes) { WriteMessage($"Using existing Team Site at {siteUrl}", ProvisioningMessageType.Progress); siteContext = (tenant.Context as ClientContext).Clone(siteUrl, configuration.AccessTokens); } else if (tenant.SiteExistsAnywhere(siteUrl) == SiteExistence.Recycled) { var errorMessage = $"The requested Team Site at {siteUrl} is in the Recycle Bin and cannot be created"; WriteMessage(errorMessage, ProvisioningMessageType.Error); throw new RecycledSiteException(errorMessage); } else { WriteMessage($"Creating Team Site with no Office 365 group at {siteUrl}", ProvisioningMessageType.Progress); siteContext = Sites.SiteCollection.Create(tenant.Context as ClientContext, siteInfo, configuration.Tenant.DelayAfterModernSiteCreation, noWait: nowait); } if (t.Groupify) { if (string.IsNullOrEmpty(t.Alias)) { // We generate the alias, if it is missing t.Alias = t.Title.Replace(" ", string.Empty).ToLower(); } // In case we need to groupify the just created site var groupifyInformation = new TeamSiteCollectionGroupifyInformation { Alias = t.Alias, // Mandatory Classification = t.Classification, // Optional Description = t.Description, DisplayName = t.Title, HubSiteId = Guid.Empty, // Optional, so far we skip it IsPublic = t.IsPublic, // Mandatory KeepOldHomePage = t.KeepOldHomePage, // Optional, but we provide it Lcid = (uint)t.Language, Owners = new string[] { t.Owner }, }; tenant.GroupifySite(siteUrl, groupifyInformation); } if (t.IsHubSite) { siteContext.Load(siteContext.Site, s => s.Id); siteContext.ExecuteQueryRetry(); RegisterAsHubSite(tenant, siteContext.Url, siteContext.Site.Id, t.HubSiteLogoUrl, t.HubSiteTitle, tokenParser); } if (!string.IsNullOrEmpty(t.Theme)) { var parsedTheme = tokenParser.ParseString(t.Theme); if (tenantThemes.FirstOrDefault(th => th.Name == parsedTheme) != null) { tenant.SetWebTheme(parsedTheme, siteContext.Url); tenant.Context.ExecuteQueryRetry(); } else { WriteMessage($"Theme {parsedTheme} doesn't exist in the tenant, will not be applied", ProvisioningMessageType.Warning); } } siteUrls.Add(t.Id, siteContext.Url); if (!string.IsNullOrEmpty(t.ProvisioningId)) { _additionalTokens.Add(new SequenceSiteUrlUrlToken(null, t.ProvisioningId, siteContext.Url)); siteContext.Web.EnsureProperty(w => w.Id); _additionalTokens.Add(new SequenceSiteIdToken(null, t.ProvisioningId, siteContext.Web.Id)); siteContext.Site.EnsureProperties(s => s.Id, s => s.GroupId); _additionalTokens.Add(new SequenceSiteCollectionIdToken(null, t.ProvisioningId, siteContext.Site.Id)); _additionalTokens.Add(new SequenceSiteGroupIdToken(null, t.ProvisioningId, siteContext.Site.GroupId)); } break; } } var web = siteContext.Web; if (siteTokenParser == null) { siteTokenParser = new TokenParser(tenant, hierarchy, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); // Add the token to the global token parser, too tokenParser.AddToken(token); } } foreach (var subsite in sitecollection.Sites) { var subSiteObject = (TeamNoGroupSubSite)subsite; web.EnsureProperties(w => w.Webs.IncludeWithDefaultProperties(), w => w.ServerRelativeUrl); siteTokenParser = CreateSubSites(hierarchy, siteTokenParser, sitecollection, siteContext, web, subSiteObject); } siteTokenParser = null; } // System.Threading.Thread.Sleep(TimeSpan.FromMinutes(10)); WriteMessage("Applying templates", ProvisioningMessageType.Progress); var currentSite = ""; var provisioningTemplateApplyingInformation = configuration.ToApplyingInformation(); provisioningTemplateApplyingInformation.ProgressDelegate = (string message, int step, int total) => { configuration.ProgressDelegate?.Invoke($"{currentSite} : {message}", step, total); }; foreach (var sitecollection in sequence.SiteCollections) { currentSite = sitecollection.ProvisioningId != null ? sitecollection.ProvisioningId : sitecollection.Title; siteUrls.TryGetValue(sitecollection.Id, out string siteUrl); if (siteUrl != null) { using (var clonedContext = tenant.Context.Clone(siteUrl, configuration.AccessTokens)) { var web = clonedContext.Web; foreach (var templateRef in sitecollection.Templates) { var provisioningTemplate = hierarchy.Templates.FirstOrDefault(t => t.Id == templateRef); if (provisioningTemplate != null) { provisioningTemplate.Connector = hierarchy.Connector; //if (siteTokenParser == null) //{ siteTokenParser = new TokenParser(web, provisioningTemplate, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); } //} //else //{ // siteTokenParser.Rebase(web, provisioningTemplate); //} WriteMessage($"Applying Template", ProvisioningMessageType.Progress); new SiteToTemplateConversion().ApplyRemoteTemplate(web, provisioningTemplate, provisioningTemplateApplyingInformation, true, siteTokenParser); } else { WriteMessage($"Referenced template ID {templateRef} not found", ProvisioningMessageType.Error); } } if (siteTokenParser == null) { siteTokenParser = new TokenParser(tenant, hierarchy, configuration.ToApplyingInformation()); foreach (var token in _additionalTokens) { siteTokenParser.AddToken(token); } } foreach (var subsite in sitecollection.Sites) { var subSiteObject = (TeamNoGroupSubSite)subsite; web.EnsureProperties(w => w.Webs.IncludeWithDefaultProperties(), w => w.ServerRelativeUrl); siteTokenParser = ApplySubSiteTemplates(hierarchy, siteTokenParser, sitecollection, clonedContext, web, subSiteObject, provisioningTemplateApplyingInformation); } if (sitecollection.IsHubSite) { RESTUtilities.ExecuteGet(web, "/_api/web/hubsitedata(true)").GetAwaiter().GetResult(); } } } } } return(tokenParser); } }
public override bool WillProvision(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { return(hierarchy.Sequences.Count > 0); }
public static TokenParser ProcessApps(Tenant tenant, ProvisioningTenant provisioningTenant, FileConnectorBase connector, TokenParser parser, PnPMonitoredScope scope, ApplyConfiguration configuration, ProvisioningMessagesDelegate messagesDelegate) { if (provisioningTenant.AppCatalog != null && provisioningTenant.AppCatalog.Packages.Count > 0) { var rootSiteUrl = tenant.GetRootSiteUrl(); tenant.Context.ExecuteQueryRetry(); using (var context = ((ClientContext)tenant.Context).Clone(rootSiteUrl.Value, configuration.AccessTokens)) { var web = context.Web; Uri appCatalogUri = null; try { appCatalogUri = web.GetAppCatalog(); } catch (System.Net.WebException ex) { if (ex.Response != null) { var httpResponse = ex.Response as System.Net.HttpWebResponse; if (httpResponse != null && httpResponse.StatusCode == HttpStatusCode.Unauthorized) { // Ignore any security exception and simply keep // the AppCatalog URI null } else { throw ex; } } else { throw ex; } } if (appCatalogUri != null) { var manager = new AppManager(context); foreach (var app in provisioningTenant.AppCatalog.Packages) { AppMetadata appMetadata = null; if (app.Action == PackageAction.Upload || app.Action == PackageAction.UploadAndPublish) { var appSrc = parser.ParseString(app.Src); var appBytes = ConnectorFileHelper.GetFileBytes(connector, appSrc); var hash = string.Empty; using (var memoryStream = new MemoryStream(appBytes)) { hash = CalculateHash(memoryStream); } var exists = false; var appId = Guid.Empty; using (var appCatalogContext = ((ClientContext)tenant.Context).Clone(appCatalogUri, configuration.AccessTokens)) { // check if the app already is present var appList = appCatalogContext.Web.GetListByUrl("AppCatalog"); var camlQuery = new CamlQuery { ViewXml = string.Format(appExistsQuery, hash) }; var items = appList.GetItems(camlQuery); appCatalogContext.Load(items, i => i.IncludeWithDefaultProperties()); appCatalogContext.ExecuteQueryRetry(); if (items.Count > 0) { exists = true; appId = Guid.Parse(items[0].FieldValues["UniqueId"].ToString()); } } var appFilename = appSrc.Substring(appSrc.LastIndexOf('\\') + 1); if (!exists) { messagesDelegate?.Invoke($"Processing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.Add(appBytes, appFilename, app.Overwrite, timeoutSeconds: 500); } else { messagesDelegate?.Invoke($"Skipping existing solution {app.Src}", ProvisioningMessageType.Progress); appMetadata = manager.GetAvailable().FirstOrDefault(a => a.Id == appId); } if (appMetadata != null) { parser.AddToken(new AppPackageIdToken(web, appFilename, appMetadata.Id)); parser.AddToken(new AppPackageIdToken(web, appMetadata.Title, appMetadata.Id)); } } if (app.Action == PackageAction.Publish || app.Action == PackageAction.UploadAndPublish) { if (appMetadata == null) { appMetadata = manager.GetAvailable() .FirstOrDefault(a => a.Id == Guid.Parse(parser.ParseString(app.PackageId))); } if (appMetadata != null) { manager.Deploy(appMetadata, app.SkipFeatureDeployment); } else { scope.LogError("Referenced App Package {0} not available", app.PackageId); throw new Exception($"Referenced App Package {app.PackageId} not available"); } } if (app.Action == PackageAction.Remove) { var appId = Guid.Parse(parser.ParseString(app.PackageId)); // Get the apps already installed in the site var appExists = manager.GetAvailable()?.Any(a => a.Id == appId); if (appExists.HasValue && appExists.Value) { manager.Remove(appId); } else { messagesDelegate?.Invoke($"App Package with ID {appId} does not exist in the AppCatalog and cannot be removed!", ProvisioningMessageType.Warning); } } } } else { messagesDelegate?.Invoke($"Tenant app catalog doesn't exist. ALM step will be skipped!", ProvisioningMessageType.Warning); } } } return(parser); }
public override bool WillProvision(Tenant tenant, Model.ProvisioningHierarchy hierarchy, string sequenceId, ApplyConfiguration configuration) { return(hierarchy.Sequences.Where(s => s.TermStore != null && s.TermStore.TermGroups != null && s.TermStore.TermGroups.Any()).Any()); }