Exemple #1
0
 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);
        }
Exemple #10
0
        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);
            }
        }
Exemple #11
0
        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);
Exemple #15
0
 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);
 }
Exemple #18
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());
 }