public void LogScanError(Exception ex, ScanError error)
        {
            if (this.telemetryClient == null || ex == null)
            {
                return;
            }

            try
            {
                // Prepare event data
                Dictionary <string, string> properties = new Dictionary <string, string>();
                Dictionary <string, double> metrics    = new Dictionary <string, double>();

                if (error != null)
                {
                    // Field 1 never contain PII data
                    if (!string.IsNullOrEmpty(error.Field1))
                    {
                        properties.Add(ScanCrash.StackTrace.ToString(), error.Field1);
                    }
                }

                this.telemetryClient.TrackException(ex, properties, metrics);
            }
            catch (Exception ex2)
            {
                // Eat all exceptions
            }
        }
        /// <summary>
        /// Analyses a web for it's blog page usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve blog data</param>
        /// <returns>Duration of the blog analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                var web = cc.Web;

                base.Analyze(cc);

                // Load the customized forms per site collection
                cc.Load(cc.Site, p => p.CustomizedFormsPages);
                cc.ExecuteQueryRetry();

                foreach (var formPage in cc.Site.CustomizedFormsPages)
                {
                    CustomizedFormsScanResult customizedFormsScanResult = new CustomizedFormsScanResult()
                    {
                        SiteColUrl = this.SiteCollectionUrl,
                        SiteURL    = this.SiteUrl,
                        //WebRelativeUrl = this.SiteUrl.Replace(this.SiteCollectionUrl, ""),
                        FormType  = formPage.formType,
                        Url       = formPage.Url,
                        PageId    = formPage.pageId,
                        WebpartId = formPage.webpartId,
                    };

                    if (!this.ScanJob.CustomizedFormsScanResults.TryAdd($"customizedFormsScanResult.WebURL.{Guid.NewGuid()}", customizedFormsScanResult))
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = $"Could not add customized forms scan result for {customizedFormsScanResult.SiteColUrl}",
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "CustomizedFormsAnalyzer",
                        };
                        this.ScanJob.ScanErrors.Push(error);
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                    Field1     = "CustomizedFormsAnalyzerLoop",
                    Field2     = ex.StackTrace
                };
                this.ScanJob.ScanErrors.Push(error);
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#3
0
        private async void buttonConvert_Click(object sender, RoutedEventArgs e)
        {
            buttonConvert.IsEnabled = false;
            Cursor = Cursors.Wait;
            textBlockScanStatus.Text          = "scanning...";
            progressBarScan.Visibility        = Visibility.Visible;
            taskBarProgressScan.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Indeterminate;

            monsterListDataTable.Rows.Clear();

            string            inputDir     = textBoxInputPath.Text;
            string            outputDir    = textBoxOutputPath.Text;
            IMonsterConverter inputFormat  = (IMonsterConverter)comboInputFormat.SelectedItem;
            IMonsterConverter outputFormat = (IMonsterConverter)comboOutputFormat.SelectedItem;
            ScanError         result       = ScanError.Success;
            await Task.Run(() =>
            {
                result = fileProcessor.ConvertMonsterFiles(inputDir, inputFormat, outputDir, outputFormat, true);
            });

            switch (result)
            {
            case ScanError.Success:
                textBlockScanStatus.Text = "Completed successfully.";
                break;

            case ScanError.NoMonstersFound:
                textBlockScanStatus.Text = "Couldn't find any monster files.";
                break;

            case ScanError.InvalidMonsterDirectory:
                textBlockScanStatus.Text = "The selected project directory is invald.";
                break;

            case ScanError.InvalidMonsterFormat:
                textBlockScanStatus.Text = "The selected input or output monster format is invalid.";
                break;

            case ScanError.CouldNotCreateDirectory:
                textBlockScanStatus.Text = "Couldn't create destination directory.";
                break;

            case ScanError.DirectoriesMatch:
                textBlockScanStatus.Text = "Input and output directories can't be the same.";
                break;

            default:
                break;
            }

            taskBarProgressScan.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
            progressBarScan.Visibility        = Visibility.Hidden;
            Cursor = Cursors.Arrow;
            buttonConvert.IsEnabled = true;
        }
示例#4
0
        public bool ScanFiles()
        {
            Console.WriteLine("Scanning...");
            ScanError result = fileProcessor.ConvertMonsterFiles(inputDirectory, input, outputDirectory, output, mirrorFolderStructure);

            switch (result)
            {
            case ScanError.Success:
                Console.WriteLine("Completed.");
                Console.WriteLine($"{ConvertSuccessCount} Monsters converted succesfully.");
                Console.WriteLine($"{ConvertWarningCount} Monsters converted with warnings.");
                Console.WriteLine($"{ConvertErrorCount} Monsters converted with errors.");
                break;

            case ScanError.NoMonstersFound:
                Console.WriteLine("Couldn't find any monster files.");
                break;

            case ScanError.InvalidMonsterDirectory:
                Console.WriteLine("The selected project directory is invald.");
                break;

            case ScanError.InvalidMonsterFormat:
                Console.WriteLine("The selected input or output monster format is invalid.");
                break;

            case ScanError.CouldNotCreateDirectory:
                Console.WriteLine("Couldn't create destination directory.");
                break;

            case ScanError.DirectoriesMatch:
                Console.WriteLine("Input and output directories can't be the same.");
                break;

            default:
                break;
            }

            return(result == ScanError.Success);
        }
        public void LogScanError(Exception ex, ScanError error)
        {
            if (this.telemetryClient == null || ex == null)
            {
                return;
            }

            try
            {
                // Prepare event data
                Dictionary <string, string> properties = new Dictionary <string, string>();
                Dictionary <string, double> metrics    = new Dictionary <string, double>();

                // Populate properties

                // Page transformation engine version
                properties.Add(EngineVersion, this.version);

                if (error != null)
                {
                    // Field 1 never contain PII data
                    if (!string.IsNullOrEmpty(error.Field1))
                    {
                        properties.Add(ScanCrash.StackTrace.ToString(), error.Field1);
                    }
                }
                // Azure AD tenant
                properties.Add(AADTenantId, this.aadTenantId.ToString());

                // Send the event
                this.telemetryClient.TrackException(ex, properties, metrics);
            }
            catch
            {
                // Eat all exceptions
            }
        }
示例#6
0
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                // Only scan when it's a valid publishing portal
                var pageCount = ContinueScanning(cc);
                if (pageCount > 0 || pageCount == -1)
                {
                    PublishingScanResult scanResult = new PublishingScanResult()
                    {
                        SiteColUrl     = this.SiteCollectionUrl,
                        SiteURL        = this.SiteUrl,
                        WebRelativeUrl = this.SiteUrl.Replace(this.SiteCollectionUrl, ""),
                        WebTemplate    = this.webScanResult.WebTemplate,
                        BrokenPermissionInheritance = this.webScanResult.BrokenPermissionInheritance,
                        PageCount        = pageCount == -1 ? 0 : pageCount,
                        SiteMasterPage   = this.webScanResult.CustomMasterPage,
                        SystemMasterPage = this.webScanResult.MasterPage,
                        AlternateCSS     = this.webScanResult.AlternateCSS,
                        Admins           = this.siteScanResult.Admins,
                        Owners           = this.webScanResult.Owners,
                    };

                    Web web = cc.Web;

                    // Load additional web properties
                    web.EnsureProperties(p => p.Language);
                    scanResult.Language = web.Language;

                    // PageLayouts handling
                    var availablePageLayouts = web.GetPropertyBagValueString(AvailablePageLayouts, "");
                    var defaultPageLayout    = web.GetPropertyBagValueString(DefaultPageLayout, "");

                    if (string.IsNullOrEmpty(availablePageLayouts))
                    {
                        scanResult.PageLayoutsConfiguration = "Any";
                    }
                    else if (availablePageLayouts.Equals("__inherit", StringComparison.InvariantCultureIgnoreCase))
                    {
                        scanResult.PageLayoutsConfiguration = "Inherit from parent";
                    }
                    else
                    {
                        scanResult.PageLayoutsConfiguration = "Defined list";

                        // Fill the defined list
                        var element = XElement.Parse(availablePageLayouts);
                        var nodes   = element.Descendants("layout");
                        if (nodes != null && nodes.Count() > 0)
                        {
                            string allowedPageLayouts = "";

                            foreach (var node in nodes)
                            {
                                allowedPageLayouts = allowedPageLayouts + node.Attribute("url").Value.Replace("_catalogs/masterpage/", "") + ",";
                            }

                            allowedPageLayouts = allowedPageLayouts.TrimEnd(new char[] { ',' });

                            scanResult.AllowedPageLayouts = allowedPageLayouts;
                        }
                    }

                    if (!string.IsNullOrEmpty(defaultPageLayout))
                    {
                        var element = XElement.Parse(defaultPageLayout);
                        scanResult.DefaultPageLayout = element.Attribute("url").Value.Replace("_catalogs/masterpage/", "");
                    }

                    // Navigation
                    var navigationSettings = web.GetNavigationSettings();
                    if (navigationSettings != null)
                    {
                        if (navigationSettings.GlobalNavigation.ManagedNavigation)
                        {
                            scanResult.GlobalNavigationType = "Managed";
                        }
                        else
                        {
                            scanResult.GlobalNavigationType = "Structural";
                            scanResult.GlobalStruturalNavigationMaxCount     = navigationSettings.GlobalNavigation.MaxDynamicItems;
                            scanResult.GlobalStruturalNavigationShowPages    = navigationSettings.GlobalNavigation.ShowPages;
                            scanResult.GlobalStruturalNavigationShowSiblings = navigationSettings.GlobalNavigation.ShowSiblings;
                            scanResult.GlobalStruturalNavigationShowSubSites = navigationSettings.GlobalNavigation.ShowSubsites;
                        }

                        if (navigationSettings.CurrentNavigation.ManagedNavigation)
                        {
                            scanResult.CurrentNavigationType = "Managed";
                        }
                        else
                        {
                            scanResult.CurrentNavigationType = "Structural";
                            scanResult.CurrentStruturalNavigationMaxCount     = navigationSettings.CurrentNavigation.MaxDynamicItems;
                            scanResult.CurrentStruturalNavigationShowPages    = navigationSettings.CurrentNavigation.ShowPages;
                            scanResult.CurrentStruturalNavigationShowSiblings = navigationSettings.CurrentNavigation.ShowSiblings;
                            scanResult.CurrentStruturalNavigationShowSubSites = navigationSettings.CurrentNavigation.ShowSubsites;
                        }

                        if (navigationSettings.GlobalNavigation.ManagedNavigation || navigationSettings.CurrentNavigation.ManagedNavigation)
                        {
                            scanResult.ManagedNavigationAddNewPages        = navigationSettings.AddNewPagesToNavigation;
                            scanResult.ManagedNavigationCreateFriendlyUrls = navigationSettings.CreateFriendlyUrlsForNewPages;

                            // get information about the managed nav term set configuration
                            var managedNavXml = web.GetPropertyBagValueString(WebNavigationSettings, "");

                            if (!string.IsNullOrEmpty(managedNavXml))
                            {
                                var managedNavSettings          = XElement.Parse(managedNavXml);
                                IEnumerable <XElement> navNodes = managedNavSettings.XPathSelectElements("./SiteMapProviderSettings/TaxonomySiteMapProviderSettings");
                                foreach (var node in navNodes)
                                {
                                    if (node.Attribute("Name").Value.Equals("CurrentNavigationTaxonomyProvider", StringComparison.InvariantCulture))
                                    {
                                        if (node.Attribute("TermSetId") != null)
                                        {
                                            scanResult.CurrentManagedNavigationTermSetId = node.Attribute("TermSetId").Value;
                                        }
                                        else if (node.Attribute("UseParentSiteMap") != null)
                                        {
                                            scanResult.CurrentManagedNavigationTermSetId = "Inherit from parent";
                                        }
                                    }
                                    else if (node.Attribute("Name").Value.Equals("GlobalNavigationTaxonomyProvider", StringComparison.InvariantCulture))
                                    {
                                        if (node.Attribute("TermSetId") != null)
                                        {
                                            scanResult.GlobalManagedNavigationTermSetId = node.Attribute("TermSetId").Value;
                                        }
                                        else if (node.Attribute("UseParentSiteMap") != null)
                                        {
                                            scanResult.GlobalManagedNavigationTermSetId = "Inherit from parent";
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Pages library
                    var pagesLibrary = web.GetListsToScan().Where(p => p.BaseTemplate == 850).FirstOrDefault();
                    if (pagesLibrary != null)
                    {
                        pagesLibrary.EnsureProperties(p => p.EnableModeration, p => p.EnableVersioning, p => p.EnableMinorVersions, p => p.EventReceivers, p => p.Fields, p => p.DefaultContentApprovalWorkflowId);
                        scanResult.LibraryEnableModeration        = pagesLibrary.EnableModeration;
                        scanResult.LibraryEnableVersioning        = pagesLibrary.EnableVersioning;
                        scanResult.LibraryEnableMinorVersions     = pagesLibrary.EnableMinorVersions;
                        scanResult.LibraryItemScheduling          = pagesLibrary.ItemSchedulingEnabled();
                        scanResult.LibraryApprovalWorkflowDefined = pagesLibrary.DefaultContentApprovalWorkflowId != Guid.Empty;
                    }

                    // Variations
                    if (scanResult.Level == 0)
                    {
                        var variationLabels = cc.GetVariationLabels();

                        string labels      = "";
                        string sourceLabel = "";
                        foreach (var label in variationLabels)
                        {
                            labels = labels + $"{label.Title} ({label.Language}),";

                            if (label.IsSource)
                            {
                                sourceLabel = label.Title;
                            }
                        }

                        scanResult.VariationLabels      = labels.TrimEnd(new char[] { ',' });;
                        scanResult.VariationSourceLabel = sourceLabel;
                    }

                    // Persist publishing scan results
                    if (!this.ScanJob.PublishingScanResults.TryAdd(this.SiteUrl, scanResult))
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = $"Could not add publishing scan result for {this.SiteUrl}",
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "PublishingAnalyzer",
                        };
                        this.ScanJob.ScanErrors.Push(error);
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#7
0
        /// <summary>
        /// Analyses a page
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve page data</param>
        /// <returns>Duration of the page analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);
                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration, p => p.Features);

                var homePageUrl = web.WelcomePage;
                if (string.IsNullOrEmpty(homePageUrl))
                {
                    // Will be case when the site home page is a web part page
                    homePageUrl = "default.aspx";
                }

                var listsToScan        = web.GetListsToScan();
                var sitePagesLibraries = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary);

                if (sitePagesLibraries.Count() > 0)
                {
                    foreach (var sitePagesLibrary in sitePagesLibraries)
                    {
                        CamlQuery query = new CamlQuery
                        {
                            ViewXml = CAMLQueryByExtension
                        };
                        var pages = sitePagesLibrary.GetItems(query);
                        web.Context.Load(pages);
                        web.Context.ExecuteQueryRetry();

                        if (pages.FirstOrDefault() != null)
                        {
                            DateTime start;
                            bool     forceCheckout = sitePagesLibrary.ForceCheckout;
                            foreach (var page in pages)
                            {
                                string pageUrl = null;
                                try
                                {
                                    if (page.FieldValues.ContainsKey(Field_FileRefField) && !String.IsNullOrEmpty(page[Field_FileRefField].ToString()))
                                    {
                                        pageUrl = page[Field_FileRefField].ToString();
                                    }
                                    else
                                    {
                                        //skip page
                                        continue;
                                    }

                                    start = DateTime.Now;
                                    PageScanResult pageResult = new PageScanResult()
                                    {
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        PageUrl    = pageUrl,
                                        Library    = sitePagesLibrary.RootFolder.ServerRelativeUrl,
                                    };

                                    // Is this page the web's home page?
                                    if (pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        pageResult.HomePage = true;
                                    }

                                    // Get the type of the page
                                    pageResult.PageType = page.PageType();

                                    // Get page web parts
                                    var pageAnalysis = page.WebParts(this.ScanJob.PageTransformation);
                                    if (pageAnalysis != null)
                                    {
                                        pageResult.Layout   = pageAnalysis.Item1.ToString().Replace("Wiki_", "").Replace("WebPart_", "");
                                        pageResult.WebParts = pageAnalysis.Item2;
                                    }

                                    // Determine if this site contains a default "uncustomized" home page
                                    bool isUncustomizedHomePage = false;
                                    try
                                    {
                                        string pageName = "";
                                        if (page.FieldValues.ContainsKey(Field_FileLeafRef) && !String.IsNullOrEmpty(page[Field_FileLeafRef].ToString()))
                                        {
                                            pageName = page[Field_FileLeafRef].ToString();
                                        }

                                        if (pageResult.HomePage && web.WebTemplate == "STS" && web.Configuration == 0 && pageName.Equals("home.aspx", StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            bool homePageModernizationOptedOut = web.Features.Where(f => f.DefinitionId == FeatureId_Web_HomePage).Count() > 0;
                                            if (!homePageModernizationOptedOut)
                                            {
                                                bool siteWasGroupified = web.Features.Where(f => f.DefinitionId == FeatureId_Web_GroupHomepage).Count() > 0;
                                                if (!siteWasGroupified)
                                                {
                                                    var wiki = page.FieldValues[Field_WikiField].ToString();
                                                    if (!string.IsNullOrEmpty(wiki))
                                                    {
                                                        var isHtmlUncustomized = IsHtmlUncustomized(wiki);

                                                        if (isHtmlUncustomized)
                                                        {
                                                            string pageType = GetPageWebPartInfo(pageResult.WebParts);

                                                            if (pageType == TeamSiteDefaultWebParts)
                                                            {
                                                                page.ContentType.EnsureProperty(p => p.DisplayFormTemplateName);
                                                                if (page.ContentType.DisplayFormTemplateName == "WikiEditForm")
                                                                {
                                                                    isUncustomizedHomePage = true;
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        // no point in failing the scan if something goes wrong here
                                    }
                                    finally
                                    {
                                        pageResult.UncustomizedHomePage = isUncustomizedHomePage;
                                    }

                                    // Get page change information
                                    pageResult.ModifiedAt = page.LastModifiedDateTime();
                                    pageResult.ModifiedBy = page.LastModifiedBy();

                                    // Grab this page from the search results to connect view information
                                    string fullPageUrl = $"https://{new Uri(this.SiteCollectionUrl).DnsSafeHost}{pageUrl}";
                                    if (pageResult.HomePage)
                                    {
                                        fullPageUrl = this.SiteUrl;
                                    }

                                    if (!this.ScanJob.SkipUsageInformation && this.pageSearchResults != null)
                                    {
                                        var searchPage = this.pageSearchResults.Where(x => x.Values.Contains(fullPageUrl)).FirstOrDefault();
                                        if (searchPage != null)
                                        {
                                            // Recent = last 14 days
                                            pageResult.ViewsRecent              = searchPage["ViewsRecent"].ToInt32();
                                            pageResult.ViewsRecentUniqueUsers   = searchPage["ViewsRecentUniqueUsers"].ToInt32();
                                            pageResult.ViewsLifeTime            = searchPage["ViewsLifeTime"].ToInt32();
                                            pageResult.ViewsLifeTimeUniqueUsers = searchPage["ViewsLifeTimeUniqueUsers"].ToInt32();
                                        }
                                    }

                                    if (!this.ScanJob.PageScanResults.TryAdd(pageResult.PageUrl, pageResult))
                                    {
                                        ScanError error = new ScanError()
                                        {
                                            Error      = $"Could not add page scan result for {pageResult.PageUrl}",
                                            SiteColUrl = this.SiteCollectionUrl,
                                            SiteURL    = this.SiteUrl,
                                            Field1     = "PageAnalyzer",
                                        };
                                        this.ScanJob.ScanErrors.Push(error);
                                    }
                                    var duration = new TimeSpan((DateTime.Now.Subtract(start).Ticks));
                                    Console.WriteLine($"Scan of page {pageUrl} took {duration.Seconds} seconds");
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "MainPageAnalyzerLoop",
                                        Field2     = ex.StackTrace,
                                        Field3     = pageUrl
                                    };

                                    // Send error to telemetry to make scanner better
                                    if (this.ScanJob.ScannerTelemetry != null)
                                    {
                                        this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                                    }

                                    this.ScanJob.ScanErrors.Push(error);
                                    Console.WriteLine("Error for page {1}: {0}", ex.Message, pageUrl);
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#8
0
        private void ModernizationScanJob_TimerJobRun(object sender, OfficeDevPnP.Core.Framework.TimerJobs.TimerJobRunEventArgs e)
        {
            // Validate ClientContext objects
            if (e.WebClientContext == null || e.SiteClientContext == null)
            {
                ScanError error = new ScanError()
                {
                    Error      = "No valid ClientContext objects",
                    SiteURL    = e.Url,
                    SiteColUrl = e.Url
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", "No valid ClientContext objects", e.Url);

                // bail out
                return;
            }

            // thread safe increase of the sites counter
            IncreaseScannedSites();

            try
            {
                // Set the first site collection done flag + perform telemetry
                SetFirstSiteCollectionDone(e.WebClientContext, this.Name);

                // Manually iterate over the content
                IEnumerable <string> expandedSites = e.SiteClientContext.Site.GetAllSubSites();
                bool   isFirstSiteInList           = true;
                string siteCollectionUrl           = "";
                List <Dictionary <string, string> > pageSearchResults = null;

                foreach (string site in expandedSites)
                {
                    try
                    {
                        // thread safe increase of the webs counter
                        IncreaseScannedWebs();

                        // Clone the existing ClientContext for the sub web
                        using (ClientContext ccWeb = e.SiteClientContext.Clone(site))
                        {
                            Console.WriteLine("Processing site {0}...", site);

                            // Allow max server time out, might be needed for sites having a lot of users
                            ccWeb.RequestTimeout = Timeout.Infinite;

                            if (isFirstSiteInList)
                            {
                                // Perf optimization: do one call per site to load all the needed properties
                                var spSite = (ccWeb as ClientContext).Site;
                                ccWeb.Load(spSite, p => p.RootWeb, p => p.Url, p => p.GroupId);
                                ccWeb.Load(spSite.RootWeb, p => p.Id);
                                ccWeb.Load(spSite, p => p.UserCustomActions); // User custom action site level
                                ccWeb.Load(spSite, p => p.Features);          // Features site level
                                ccWeb.ExecuteQueryRetry();

                                isFirstSiteInList = false;
                            }

                            // Perf optimization: do one call per web to load all the needed properties
                            ccWeb.Load(ccWeb.Web, p => p.Id, p => p.Title, p => p.Url);
                            ccWeb.Load(ccWeb.Web, p => p.WebTemplate, p => p.Configuration);
                            ccWeb.Load(ccWeb.Web, p => p.MasterUrl, p => p.CustomMasterUrl, // master page check
                                       p => p.AlternateCssUrl,                              // Alternate CSS
                                       p => p.UserCustomActions);                           // Web user custom actions
                            ccWeb.Load(ccWeb.Web, p => p.Features);                         // Features web level
                            ccWeb.Load(ccWeb.Web, p => p.RootFolder);                       // web home page
                            ccWeb.ExecuteQueryRetry();

                            // Split load in multiple batches to minimize timeout exceptions
                            if (!SkipUserInformation)
                            {
                                ccWeb.Load(ccWeb.Web, p => p.SiteUsers, p => p.AssociatedOwnerGroup, p => p.AssociatedMemberGroup, p => p.AssociatedVisitorGroup); // site user and groups
                                ccWeb.Load(ccWeb.Web, p => p.HasUniqueRoleAssignments, p => p.RoleAssignments, p => p.SiteGroups.Include(s => s.Users));           // permission inheritance at web level
                                ccWeb.ExecuteQueryRetry();

                                ccWeb.Load(ccWeb.Web.AssociatedOwnerGroup, p => p.Users);   // users in the Owners group
                                ccWeb.Load(ccWeb.Web.AssociatedMemberGroup, p => p.Users);  // users in the Members group
                                ccWeb.Load(ccWeb.Web.AssociatedVisitorGroup, p => p.Users); // users in the Visitors group
                                ccWeb.ExecuteQueryRetry();
                            }

                            // Do things only once per site collection
                            if (string.IsNullOrEmpty(siteCollectionUrl))
                            {
                                // Cross check Url property availability
                                ccWeb.Site.EnsureProperty(s => s.Url);
                                siteCollectionUrl = ccWeb.Site.Url;

                                // Site scan
                                SiteAnalyzer siteAnalyzer     = new SiteAnalyzer(site, siteCollectionUrl, this);
                                var          siteScanDuration = siteAnalyzer.Analyze(ccWeb);
                                pageSearchResults = siteAnalyzer.PageSearchResults;
                            }

                            // Web scan
                            WebAnalyzer webAnalyzer     = new WebAnalyzer(site, siteCollectionUrl, this, pageSearchResults);
                            var         webScanDuration = webAnalyzer.Analyze(ccWeb);
                        }
                    }
                    catch (Exception ex)
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = ex.Message,
                            SiteColUrl = e.Url,
                            SiteURL    = site,
                            Field1     = "MainWebLoop",
                            Field2     = ex.StackTrace,
                        };
                        this.ScanErrors.Push(error);
                        Console.WriteLine("Error for site {1}: {0}", ex.Message, site);
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = e.Url,
                    SiteURL    = e.Url,
                    Field1     = "MainSiteLoop",
                    Field2     = ex.StackTrace,
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", ex.Message, e.Url);
            }

            // Output the scanning progress
            try
            {
                TimeSpan ts = DateTime.Now.Subtract(this.StartTime);
                Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}. Processed {this.ScannedSites} of {this.SitesToScan} site collections ({Math.Round(((float)this.ScannedSites / (float)this.SitesToScan) * 100)}%). Process running for {ts.Days} days, {ts.Hours} hours, {ts.Minutes} minutes and {ts.Seconds} seconds.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error showing progress: {ex.ToString()}");
            }
        }
示例#9
0
        public override TimeSpan Analyze(ClientContext cc)
        {
            // Get site usage information
            List <string> propertiesToRetrieve = new List <string>
            {
                "LastModifiedTime",
                "ModifiedBy",
                "DetectedLanguage",
                "SPWebUrl",
                "Path",
                "Title",
                "ViewsRecent",
                "ViewsRecentUniqueUsers",
                "ViewsLifeTime",
                "ViewsLifeTimeUniqueUsers"
            };

            Uri    rootSite   = new Uri(this.SiteCollectionUrl);
            string pathFilter = $"{rootSite.Scheme}://{rootSite.DnsSafeHost}/portals/personal/*";

            Dictionary <string, BlogWebScanResult> tempWebResults = new Dictionary <string, BlogWebScanResult>();

            var results = this.ScanJob.Search(cc.Web, $"path:{pathFilter} AND ContentTypeId:\"0x010100DA3A7E6E3DB34DFF8FDEDE1F4EBAF95D*\"", propertiesToRetrieve);

            if (results != null && results.Count > 0)
            {
                foreach (var result in results)
                {
                    string url = result["SPWebUrl"]?.ToLower().Replace($"{rootSite.Scheme}://{rootSite.DnsSafeHost}".ToLower(), "");

                    DateTime lastModified = DateTime.MinValue;

                    if (result["LastModifiedTime"] != null)
                    {
                        DateTime.TryParse(result["LastModifiedTime"], out lastModified);
                    }

                    BlogWebScanResult  scanResult = null;
                    BlogPageScanResult blogPageScanResult;
                    if (tempWebResults.ContainsKey(url))
                    {
                        // Increase page counter
                        tempWebResults[url].BlogPageCount += 1;

                        // Build page record
                        blogPageScanResult = AddBlogPageResult($"{rootSite.Scheme}://{rootSite.DnsSafeHost}".ToLower(), url, result, lastModified);
                    }
                    else
                    {
                        scanResult = new BlogWebScanResult
                        {
                            SiteColUrl                = result["SPWebUrl"],
                            SiteURL                   = result["SPWebUrl"],
                            WebRelativeUrl            = url,
                            WebTemplate               = "POINTPUBLISHINGPERSONAL#0",
                            BlogType                  = BlogType.Delve,
                            BlogPageCount             = 1,
                            LastRecentBlogPageChange  = lastModified,
                            LastRecentBlogPagePublish = lastModified,
                            Language                  = 1033
                        };

                        tempWebResults.Add(url, scanResult);

                        // Build page record
                        blogPageScanResult = AddBlogPageResult($"{rootSite.Scheme}://{rootSite.DnsSafeHost}".ToLower(), url, result, lastModified);
                    }

                    if (blogPageScanResult != null)
                    {
                        if (!this.ScanJob.BlogPageScanResults.TryAdd($"blogScanResult.PageURL.{Guid.NewGuid()}", blogPageScanResult))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add delve blog page scan result for {blogPageScanResult.SiteColUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "DelveBlogPageAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                }

                // Copy the temp scan results to the actual structure
                foreach (var blogWebResult in tempWebResults)
                {
                    if (!this.ScanJob.BlogWebScanResults.TryAdd($"blogScanResult.WebURL.{Guid.NewGuid()}", blogWebResult.Value))
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = $"Could not add delve blog web scan result for {blogWebResult.Value.SiteColUrl}",
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "DelveBlogWebAnalyzer",
                        };
                        this.ScanJob.ScanErrors.Push(error);
                    }
                }
            }

            return(base.Analyze(cc));
        }
示例#10
0
        /// <summary>
        /// Analyses a web for it's blog page usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve blog data</param>
        /// <returns>Duration of the blog analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                // Is this a blog site
                if (cc.Web.WebTemplate.Equals("BLOG", StringComparison.InvariantCultureIgnoreCase))
                {
                    var web = cc.Web;

                    base.Analyze(cc);

                    BlogWebScanResult blogWebScanResult = new BlogWebScanResult()
                    {
                        SiteColUrl     = this.SiteCollectionUrl,
                        SiteURL        = this.SiteUrl,
                        WebRelativeUrl = this.SiteUrl.Replace(this.SiteCollectionUrl, ""),
                    };

                    // Log used web template
                    if (web.WebTemplate != null)
                    {
                        blogWebScanResult.WebTemplate = $"{web.WebTemplate}#{web.Configuration}";
                    }

                    // Load additional web properties
                    web.EnsureProperty(p => p.Language);
                    blogWebScanResult.Language = web.Language;

                    // Get the blog page list
                    List blogList = null;
                    var  lists    = web.GetListsToScan();
                    if (lists != null)
                    {
                        blogList = lists.Where(p => p.BaseTemplate == (int)ListTemplateType.Posts).FirstOrDefault();
                    }

                    // Query the blog posts
                    if (blogList != null)
                    {
                        CamlQuery query = CamlQuery.CreateAllItemsQuery(10000, new string[] { "Title", "Body", "NumComments", "PostCategory", "PublishedDate", "Modified", "Created", "Editor", "Author" });

                        var pages = blogList.GetItems(query);
                        cc.Load(pages);
                        cc.ExecuteQueryRetry();

                        if (pages != null)
                        {
                            blogWebScanResult.BlogPageCount             = pages.Count;
                            blogWebScanResult.LastRecentBlogPageChange  = blogList.LastItemUserModifiedDate;
                            blogWebScanResult.LastRecentBlogPagePublish = blogList.LastItemUserModifiedDate;

                            foreach (var page in pages)
                            {
                                string pageUrl = null;
                                try
                                {
                                    if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
                                    {
                                        pageUrl = page[FileRefField].ToString().ToLower();
                                    }
                                    else
                                    {
                                        //skip page
                                        continue;
                                    }

                                    BlogPageScanResult blogPageScanResult = new BlogPageScanResult()
                                    {
                                        SiteColUrl      = this.SiteCollectionUrl,
                                        SiteURL         = this.SiteUrl,
                                        WebRelativeUrl  = blogWebScanResult.WebRelativeUrl,
                                        PageRelativeUrl = pageUrl,
                                    };

                                    if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
                                    {
                                        blogPageScanResult.PageTitle = page["Title"].ToString();
                                    }

                                    // Add modified information
                                    blogPageScanResult.ModifiedBy    = page.LastModifiedBy();
                                    blogPageScanResult.ModifiedAt    = page.LastModifiedDateTime();
                                    blogPageScanResult.PublishedDate = page.LastPublishedDateTime();

                                    if (blogPageScanResult.ModifiedAt > blogWebScanResult.LastRecentBlogPageChange)
                                    {
                                        blogWebScanResult.LastRecentBlogPageChange = blogPageScanResult.ModifiedAt;
                                    }

                                    if (blogPageScanResult.PublishedDate > blogWebScanResult.LastRecentBlogPagePublish)
                                    {
                                        blogWebScanResult.LastRecentBlogPagePublish = blogPageScanResult.PublishedDate;
                                    }

                                    if (!this.ScanJob.BlogPageScanResults.TryAdd($"blogScanResult.PageURL.{Guid.NewGuid()}", blogPageScanResult))
                                    {
                                        ScanError error = new ScanError()
                                        {
                                            Error      = $"Could not add blog page scan result for {blogPageScanResult.SiteColUrl}",
                                            SiteColUrl = this.SiteCollectionUrl,
                                            SiteURL    = this.SiteUrl,
                                            Field1     = "BlogPageAnalyzer",
                                        };
                                        this.ScanJob.ScanErrors.Push(error);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "BlogPageAnalyzer",
                                        Field2     = ex.StackTrace,
                                        Field3     = pageUrl
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }

                    if (!this.ScanJob.BlogWebScanResults.TryAdd($"blogScanResult.WebURL.{Guid.NewGuid()}", blogWebScanResult))
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = $"Could not add blog web scan result for {blogWebScanResult.SiteColUrl}",
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "BlogWebAnalyzer",
                        };
                        this.ScanJob.ScanErrors.Push(error);
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                    Field1     = "BlogPageAnalyzerMainLoop",
                    Field2     = ex.StackTrace
                };
                this.ScanJob.ScanErrors.Push(error);
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#11
0
        private void VisioScanJob_TimerJobRun(object sender, OfficeDevPnP.Core.Framework.TimerJobs.TimerJobRunEventArgs e)
        {
            // Validate ClientContext objects
            if (e.WebClientContext == null || e.SiteClientContext == null)
            {
                ScanError error = new ScanError()
                {
                    Error      = "No valid ClientContext objects",
                    SiteURL    = e.Url,
                    SiteColUrl = e.Url
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", "No valid ClientContext objects", e.Url);

                // bail out
                return;
            }

            // thread safe increase of the sites counter
            IncreaseScannedSites();

            try
            {
                // Set the first site collection done flag + perform telemetry
                SetFirstSiteCollectionDone(e.WebClientContext, this.Name);

                // Manually iterate over the content
                IEnumerable <string> expandedSites = e.SiteClientContext.Site.GetAllSubSites();
                bool   isFirstSiteInList           = true;
                string siteCollectionUrl           = "";
                List <Dictionary <string, string> > pageSearchResults = null;

                foreach (string site in expandedSites)
                {
                    try
                    {
                        // thread safe increase of the webs counter
                        IncreaseScannedWebs();

                        // Clone the existing ClientContext for the sub web
                        using (ClientContext ccWeb = e.SiteClientContext.Clone(site))
                        {
                            Console.WriteLine("Processing site {0}...", site);

                            // Allow max server time out, might be needed for sites having a lot of users
                            ccWeb.RequestTimeout = Timeout.Infinite;

                            if (isFirstSiteInList)
                            {
                                // Perf optimization: do one call per site to load all the needed properties
                                var spSite = (ccWeb as ClientContext).Site;
                                ccWeb.Load(spSite, p => p.Url);
                                ccWeb.ExecuteQueryRetry();

                                isFirstSiteInList = false;
                            }

                            ListCollection listCollection = ccWeb.Web.Lists;
                            ccWeb.Load(listCollection, coll => coll.Include(li => li.Title, li => li.Hidden, li => li.DefaultViewUrl, li => li.BaseTemplate, li => li.RootFolder));
                            ccWeb.ExecuteQueryRetry();

                            // Do things only once per site collection
                            if (string.IsNullOrEmpty(siteCollectionUrl))
                            {
                                // Cross check Url property availability
                                ccWeb.Site.EnsureProperty(s => s.Url);
                                siteCollectionUrl = ccWeb.Site.Url;

                                // Site scan
                                SiteAnalyzer siteAnalyzer     = new SiteAnalyzer(site, siteCollectionUrl, this);
                                var          siteScanDuration = siteAnalyzer.Analyze(ccWeb);
                                pageSearchResults = siteAnalyzer.PageSearchResults;
                            }

                            VisioWebPartAnalyzer visioWebPartAnalyzer = new VisioWebPartAnalyzer(site, siteCollectionUrl, this, pageSearchResults);
                            visioWebPartAnalyzer.Analyze(ccWeb);
                        }
                    }
                    catch (Exception ex)
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = ex.Message,
                            SiteColUrl = e.Url,
                            SiteURL    = site,
                            Field1     = "MainWebLoop",
                            Field2     = ex.StackTrace,
                        };
                        this.ScanErrors.Push(error);
                        Console.WriteLine("Error for site {1}: {0}", ex.Message, site);
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = e.Url,
                    SiteURL    = e.Url,
                    Field1     = "MainSiteLoop",
                    Field2     = ex.StackTrace,
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", ex.Message, e.Url);
            }

            // Output the scanning progress
            try
            {
                TimeSpan ts = DateTime.Now.Subtract(this.StartTime);
                Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}. Processed {this.ScannedSites} of {this.SitesToScan} site collections ({Math.Round(((float)this.ScannedSites / (float)this.SitesToScan) * 100)}%). Process running for {ts.Days} days, {ts.Hours} hours, {ts.Minutes} minutes and {ts.Seconds} seconds.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error showing progress: {ex.ToString()}");
            }
        }
示例#12
0
        private void ReferenceScanJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
        {
            // thread safe increase of the sites counter
            IncreaseScannedSites();

            try
            {
                Console.WriteLine("Processing site {0}...", e.Url);

                #region Basic sample

                /*
                 * // Set the first site collection done flag + perform telemetry
                 * SetFirstSiteCollectionDone(e.WebClientContext);
                 *
                 * // add your custom scan logic here, ensure the catch errors as we don't want to terminate scanning
                 * e.WebClientContext.Load(e.WebClientContext.Web, p => p.Title);
                 * e.WebClientContext.ExecuteQueryRetry();
                 * ScanResult result = new ScanResult()
                 * {
                 *  SiteColUrl = e.Url,
                 *  SiteURL = e.Url,
                 *  SiteTitle = e.WebClientContext.Web.Title
                 * };
                 *
                 * // Store the scan result
                 * if (!ScanResults.TryAdd(e.Url, result))
                 * {
                 *  ScanError error = new ScanError()
                 *  {
                 *      SiteURL = e.Url,
                 *      SiteColUrl = e.Url,
                 *      Error = "Could not add scan result for this site"
                 *  };
                 *  this.ScanErrors.Push(error);
                 * }
                 */
                #endregion

                #region Search based sample
                // Set the first site collection done flag + perform telemetry
                SetFirstSiteCollectionDone(e.WebClientContext);

                // Need to use search inside this site collection?
                List <string> propertiesToRetrieve = new List <string>
                {
                    "Title",
                    "SPSiteUrl",
                    "FileExtension",
                    "OriginalPath"
                };
                var searchResults = this.Search(e.SiteClientContext.Web, $"((fileextension=htm OR fileextension=html) AND contentclass=STS_ListItem_DocumentLibrary AND Path:{e.Url.TrimEnd('/')}/*)", propertiesToRetrieve);
                foreach (var searchResult in searchResults)
                {
                    ScanResult result = new ScanResult()
                    {
                        SiteColUrl = e.Url,
                        FileName   = searchResult["OriginalPath"]
                    };

                    // Get web url
                    var webUrlData = Web.GetWebUrlFromPageUrl(e.SiteClientContext, result.FileName);
                    e.SiteClientContext.ExecuteQueryRetry();
                    result.SiteURL = webUrlData.Value;

                    // Store the scan result, use FileName as unique key in this sample
                    if (!ScanResults.TryAdd(result.FileName, result))
                    {
                        ScanError error = new ScanError()
                        {
                            SiteURL    = e.Url,
                            SiteColUrl = e.Url,
                            Error      = "Could not add scan result for this web"
                        };
                        this.ScanErrors.Push(error);
                    }
                }
                #endregion

                #region Sub site iteration sample

                /***
                 * // Set the first site collection done flag + perform telemetry
                 * SetFirstSiteCollectionDone(e.WebClientContext);
                 *
                 * // Manually iterate over the content
                 * IEnumerable<string> expandedSites = GetAllSubSites(e.SiteClientContext.Site);
                 * bool isFirstSiteInList = true;
                 * string siteCollectionUrl = "";
                 *
                 * foreach (string site in expandedSites)
                 * {
                 *  // thread safe increase of the webs counter
                 *  IncreaseScannedWebs();
                 *
                 *  // Clone the existing ClientContext for the sub web
                 *  using (ClientContext ccWeb = e.SiteClientContext.Clone(site))
                 *  {
                 *      Console.WriteLine("Processing site {0}...", site);
                 *
                 *      if (isFirstSiteInList)
                 *      {
                 *          // Perf optimization: do one call per site to load all the needed properties
                 *          var spSite = (ccWeb as ClientContext).Site;
                 *          ccWeb.Load(spSite, p => p.RootWeb, p => p.Url);
                 *          ccWeb.Load(spSite.RootWeb, p => p.Id);
                 *
                 *          isFirstSiteInList = false;
                 *      }
                 *
                 *      // Perf optimization: do one call per web to load all the needed properties
                 *      ccWeb.Load(ccWeb.Web, p => p.Id, p => p.Title);
                 *      ccWeb.Load(ccWeb.Web, p => p.WebTemplate, p => p.Configuration);
                 *      ccWeb.Load(ccWeb.Web, p => p.Lists.Include(li => li.UserCustomActions, li => li.Title, li => li.Hidden, li => li.DefaultViewUrl, li => li.BaseTemplate, li => li.RootFolder, li => li.ListExperienceOptions));
                 *      ccWeb.ExecuteQueryRetry();
                 *
                 *      // Fill site collection url
                 *      if (string.IsNullOrEmpty(siteCollectionUrl))
                 *      {
                 *          siteCollectionUrl = ccWeb.Site.Url;
                 *      }
                 *
                 *      // Need to know if this is a sub site?
                 *      if (ccWeb.Web.IsSubSite())
                 *      {
                 *          // Sub site specific logic
                 *      }
                 *
                 *      ScanResult result = new ScanResult()
                 *      {
                 *          SiteColUrl = e.Url,
                 *          SiteURL = site,
                 *          SiteTitle = ccWeb.Web.Title,
                 *      };
                 *
                 *      // Store the scan result
                 *      if (!ScanResults.TryAdd(site, result))
                 *      {
                 *          ScanError error = new ScanError()
                 *          {
                 *              SiteURL = site,
                 *              SiteColUrl = e.Url,
                 *              Error = "Could not add scan result for this web"
                 *          };
                 *          this.ScanErrors.Push(error);
                 *      }
                 *  }
                 * }
                 **/
                #endregion
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = e.Url,
                    SiteURL    = e.Url,
                    Field1     = "put additional info here"
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", ex.Message, e.Url);
            }

            // Output the scanning progress
            try
            {
                TimeSpan ts = DateTime.Now.Subtract(this.StartTime);
                Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}. Processed {this.ScannedSites} of {this.SitesToScan} site collections ({Math.Round(((float)this.ScannedSites / (float)this.SitesToScan) * 100)}%). Process running for {ts.Days} days, {ts.Hours} hours, {ts.Minutes} minutes and {ts.Seconds} seconds.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error showing progress: {ex.ToString()}");
            }
        }
        /// <summary>
        /// Analyze the web
        /// </summary>
        /// <param name="cc">ClientContext of the web to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                var baseUri   = new Uri(this.SiteUrl);
                var webAppUrl = baseUri.Scheme + "://" + baseUri.Host;

                var lists = cc.Web.GetListsToScan();

                foreach (var list in lists)
                {
                    try
                    {
                        this.ScanJob.IncreaseScannedLists();

                        ListScanResult listScanData;
                        if (list.DefaultViewUrl.ToLower().Contains(".aspx"))
                        {
                            File file = cc.Web.GetFileByServerRelativeUrl(list.DefaultViewUrl);
                            listScanData = file.ModernCompatability(list, ref this.ScanJob.ScanErrors);
                        }
                        else
                        {
                            listScanData = new ListScanResult()
                            {
                                BlockedByNotBeingAbleToLoadPage = true
                            };
                        }

                        if (listScanData != null && !listScanData.WorksInModern)
                        {
                            if (this.ScanJob.ExcludeListsOnlyBlockedByOobReasons && listScanData.OnlyBlockedByOOBReasons)
                            {
                                continue;
                            }

                            listScanData.SiteURL    = this.SiteUrl;
                            listScanData.ListUrl    = $"{webAppUrl}{list.DefaultViewUrl}";
                            listScanData.SiteColUrl = this.SiteCollectionUrl;
                            listScanData.ListTitle  = list.Title;

                            if (!this.ScanJob.ListScanResults.TryAdd($"{Guid.NewGuid().ToString()}{webAppUrl}{list.DefaultViewUrl}", listScanData))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add list scan result for {webAppUrl}{list.DefaultViewUrl} from web scan of {this.SiteUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "ListAnalyzer",
                                    Field2     = $"{webAppUrl}{list.DefaultViewUrl}"
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = ex.Message,
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "MainListAnalyzerLoop",
                            Field2     = ex.StackTrace,
                            Field3     = $"{webAppUrl}{list.DefaultViewUrl}"
                        };

                        // Send error to telemetry to make scanner better
                        if (this.ScanJob.ScannerTelemetry != null)
                        {
                            this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                        }

                        this.ScanJob.ScanErrors.Push(error);
                        Console.WriteLine("Error for page {1}: {0}", ex.Message, $"{webAppUrl}{list.DefaultViewUrl}");
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#14
0
        /// <summary>
        /// Analyses a web for it's workflow usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve workflow data</param>
        /// <returns>Duration of the workflow analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                var baseUri   = new Uri(this.SiteUrl);
                var webAppUrl = baseUri.Scheme + "://" + baseUri.Host;

                var lists = cc.Web.GetListsToScan(showHidden: true);

                foreach (var list in lists)
                {
                    if (list.BaseTemplate == (int)ListTemplateType.XMLForm ||
                        (!string.IsNullOrEmpty(list.DocumentTemplateUrl) && list.DocumentTemplateUrl.EndsWith(".xsn", StringComparison.InvariantCultureIgnoreCase))
                        )
                    {
                        // Form libraries depend on InfoPath
                        InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                        {
                            SiteColUrl               = this.SiteCollectionUrl,
                            SiteURL                  = this.SiteUrl,
                            InfoPathUsage            = "FormLibrary",
                            ListTitle                = list.Title,
                            ListId                   = list.Id,
                            ListUrl                  = list.RootFolder.ServerRelativeUrl,
                            Enabled                  = true,
                            InfoPathTemplate         = !string.IsNullOrEmpty(list.DocumentTemplateUrl) ? Path.GetFileName(list.DocumentTemplateUrl) : "",
                            ItemCount                = list.ItemCount,
                            LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                        };

                        if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add formlibrary InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "InfoPathAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                    else if (list.BaseTemplate == (int)ListTemplateType.DocumentLibrary || list.BaseTemplate == (int)ListTemplateType.WebPageLibrary)
                    {
                        // verify if a form content type was attached to this list
                        cc.Load(list, p => p.ContentTypes.Include(c => c.Id, c => c.DocumentTemplateUrl));
                        cc.ExecuteQueryRetry();

                        var formContentTypeFound = list.ContentTypes.Where(c => c.Id.StringValue.StartsWith(FormBaseContentType, StringComparison.InvariantCultureIgnoreCase)).OrderBy(c => c.Id.StringValue.Length).FirstOrDefault();
                        if (formContentTypeFound != null)
                        {
                            // Form libraries depend on InfoPath
                            InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                InfoPathUsage            = "ContentType",
                                ListTitle                = list.Title,
                                ListId                   = list.Id,
                                ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                Enabled                  = true,
                                InfoPathTemplate         = !string.IsNullOrEmpty(formContentTypeFound.DocumentTemplateUrl) ? Path.GetFileName(formContentTypeFound.DocumentTemplateUrl) : "",
                                ItemCount                = list.ItemCount,
                                LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                            };

                            if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add contenttype InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                    else if (list.BaseTemplate == (int)ListTemplateType.GenericList)
                    {
                        try
                        {
                            Folder folder = cc.Web.GetFolderByServerRelativeUrl($"{list.RootFolder.ServerRelativeUrl}/Item");
                            cc.Load(folder, p => p.Properties);
                            cc.ExecuteQueryRetry();

                            if (folder.Properties.FieldValues.ContainsKey("_ipfs_infopathenabled") && folder.Properties.FieldValues.ContainsKey("_ipfs_solutionName"))
                            {
                                bool infoPathEnabled = true;
                                if (bool.TryParse(folder.Properties.FieldValues["_ipfs_infopathenabled"].ToString(), out bool infoPathEnabledParsed))
                                {
                                    infoPathEnabled = infoPathEnabledParsed;
                                }

                                // List with an InfoPath customization
                                InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    InfoPathUsage            = "CustomForm",
                                    ListTitle                = list.Title,
                                    ListId                   = list.Id,
                                    ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                    Enabled                  = infoPathEnabled,
                                    InfoPathTemplate         = folder.Properties.FieldValues["_ipfs_solutionName"].ToString(),
                                    ItemCount                = list.ItemCount,
                                    LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                                };

                                if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add customform InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "InfoPathAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        catch (ServerException ex)
                        {
                            if (((ServerException)ex).ServerErrorTypeName == "System.IO.FileNotFoundException")
                            {
                                // Ignore
                            }
                            else
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = ex.Message,
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                    Field2     = ex.StackTrace,
                                    Field3     = $"{webAppUrl}{list.DefaultViewUrl}"
                                };

                                // Send error to telemetry to make scanner better
                                if (this.ScanJob.ScannerTelemetry != null)
                                {
                                    this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                                }

                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
        private void PermissiveScanJob_TimerJobRun(object sender, OfficeDevPnP.Core.Framework.TimerJobs.TimerJobRunEventArgs e)
        {
            // thread safe increase of the sites counter
            IncreaseScannedSites();

            try
            {
                Console.WriteLine("Processing site {0}...", e.Url);

                // Set the first site collection done flag + perform telemetry
                SetFirstSiteCollectionDone(e.WebClientContext);

                // Need to use search inside this site collection?
                List <string> propertiesToRetrieve = new List <string>
                {
                    "SPSiteUrl",
                    "FileExtension",
                    "OriginalPath"
                };
                var searchResults = this.Search(e.SiteClientContext.Web, $"({this.GetBaseSearchQuery()} AND Path:{e.Url.TrimEnd('/')}/*)", propertiesToRetrieve);
                foreach (var searchResult in searchResults)
                {
                    ScanResult result = new ScanResult()
                    {
                        SiteColUrl    = e.Url,
                        FileName      = searchResult["OriginalPath"],
                        FileExtension = searchResult["FileExtension"]
                    };

                    // Analyse the files
                    var webUrlData = Web.GetWebUrlFromPageUrl(e.SiteClientContext, result.FileName);

                    Uri fileUri;
                    if (Uri.TryCreate(result.FileName, UriKind.Absolute, out fileUri) &&
                        (result.FileExtension.ToLower().Equals("html") || result.FileExtension.ToLower().Equals("htm")))
                    {
                        var fileContents = e.SiteClientContext.Web.GetFileAsString(fileUri.LocalPath);
                        var htmlScan     = new HtmlScanner().Scan(fileContents);

                        result.EmbeddedLinkCount          = htmlScan.LinkReferences;
                        result.EmbeddedLocalHtmlLinkCount = htmlScan.LocalHtmlLinkReferences;
                        result.EmbeddedScriptTagCount     = htmlScan.ScriptReferences;
                    }

                    e.SiteClientContext.Load(e.SiteClientContext.Web, p => p.SiteUsers, p => p.AssociatedOwnerGroup);
                    e.SiteClientContext.Load(e.SiteClientContext.Web.AssociatedOwnerGroup, p => p.Users);
                    e.SiteClientContext.ExecuteQueryRetry();

                    if (e.SiteClientContext.Web.SiteUsers != null)
                    {
                        try
                        {
                            var admins = e.SiteClientContext.Web.SiteUsers.Where(p => p.IsSiteAdmin);
                            if (admins != null && admins.Count() > 0)
                            {
                                foreach (var admin in admins)
                                {
                                    if (!string.IsNullOrEmpty(admin.Email))
                                    {
                                        result.SiteAdmins = AddSiteOwner(result.SiteAdmins, admin.Email);
                                    }
                                }
                            }
                        }
                        catch
                        {
                            //Eat exceptions...rather log all files in the main result list instead of dropping some due to error getting owners
                        }

                        try
                        {
                            // grab folks from the Access Web App site owners group
                            if (e.SiteClientContext.Web.AssociatedOwnerGroup != null && e.SiteClientContext.Web.AssociatedOwnerGroup.Users != null && e.SiteClientContext.Web.AssociatedOwnerGroup.Users.Count > 0)
                            {
                                foreach (var owner in e.SiteClientContext.Web.AssociatedOwnerGroup.Users)
                                {
                                    if (!string.IsNullOrEmpty(owner.Email))
                                    {
                                        result.SiteAdmins = AddSiteOwner(result.SiteAdmins, owner.Email);
                                    }
                                }
                            }
                        }
                        catch
                        {
                            //Eat exceptions...rather log all files in the main result list instead of dropping some due to error getting owners
                        }
                    }

                    result.SiteURL = webUrlData.Value;

                    // Store the scan result, use FileName as unique key in this sample
                    if (!ScanResults.TryAdd(result.FileName, result))
                    {
                        ScanError error = new ScanError()
                        {
                            SiteURL    = result.SiteURL,
                            SiteColUrl = e.Url,
                            Error      = "Could not add scan result for this web"
                        };
                        this.ScanErrors.Push(error);
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = e.Url,
                    SiteURL    = e.Url,
                };
                this.ScanErrors.Push(error);
                Console.WriteLine("Error for site {1}: {0}", ex.Message, e.Url);
            }

            // Output the scanning progress
            try
            {
                TimeSpan ts = DateTime.Now.Subtract(this.StartTime);
                Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}. Processed {this.ScannedSites} of {this.SitesToScan} site collections ({Math.Round(((float)this.ScannedSites / (float)this.SitesToScan) * 100)}%). Process running for {ts.Days} days, {ts.Hours} hours, {ts.Minutes} minutes and {ts.Seconds} seconds.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error showing progress: {ex.ToString()}");
            }
        }
示例#16
0
        /// <summary>
        /// Analyze the web
        /// </summary>
        /// <param name="cc">ClientContext of the web to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                // Ensure needed data is loaded
                Web web = cc.Web;
                web.EnsureProperties(p => p.UserCustomActions, p => p.AlternateCssUrl, p => p.CustomMasterUrl, p => p.MasterUrl, p => p.Features, p => p.WebTemplate, p => p.Configuration, p => p.HasUniqueRoleAssignments, p => p.RootFolder);

                // Log in Site scan data that the scanned web is a sub site
                if (web.IsSubSite())
                {
                    SiteScanResult siteScanData;
                    if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData))
                    {
                        if (!siteScanData.SubSites)
                        {
                            var clonedSiteScandata = siteScanData.Clone();
                            clonedSiteScandata.SubSites = true;

                            if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WebAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }

                    // Check if we've broken permission inheritance in this site collection
                    if (web.HasUniqueRoleAssignments)
                    {
                        SiteScanResult siteScanData2;
                        if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData2))
                        {
                            if (!siteScanData2.SubSitesWithBrokenPermissionInheritance)
                            {
                                var clonedSiteScandata = siteScanData2.Clone();
                                clonedSiteScandata.SubSitesWithBrokenPermissionInheritance = true;

                                if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData2))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WebAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                }

                // Perform specific analysis work
                WebScanResult scanResult = new WebScanResult()
                {
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                };

                // Log used web template
                if (web.WebTemplate != null)
                {
                    scanResult.WebTemplate = $"{web.WebTemplate}#{web.Configuration}";
                }

                // Page feature check: users can disable this to prevent modern page creation
                scanResult.ModernPageWebFeatureDisabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_ModernPage).Count() == 0;
                // List feature check: users can enabled this to prevent modern lists from working
                scanResult.ModernListWebBlockingFeatureEnabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_ModernList).Count() > 0;
                // Publishing web feature enabled
                scanResult.WebPublishingFeatureEnabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_Publishing).Count() > 0;

                // Log permission inheritance details
                if (web.IsSubSite() && web.HasUniqueRoleAssignments)
                {
                    scanResult.BrokenPermissionInheritance = web.HasUniqueRoleAssignments;
                    scanResult.Owners   = web.GetOwners();
                    scanResult.Members  = web.GetMembers();
                    scanResult.Visitors = web.GetVisitors();
                    scanResult.EveryoneClaimsGranted = web.ClaimsHaveRoleAssignment(this.ScanJob.EveryoneClaim, this.ScanJob.EveryoneExceptExternalUsersClaim);
                }

                // If the web template is STS#0, GROUP#0 or SITEPAGEPUBLISHING#0 then the feature was activated by SPO, other templates never got it
                scanResult.ModernPageFeatureWasEnabledBySPO = false;
                if (scanResult.WebTemplate.Equals("STS#0", StringComparison.InvariantCultureIgnoreCase) ||
                    scanResult.WebTemplate.Equals("GROUP#0", StringComparison.InvariantCulture) ||
                    scanResult.WebTemplate.Equals("SITEPAGEPUBLISHING#0", StringComparison.InvariantCulture))
                {
                    // Since we did not enable the feature for all STS#0 sites (sites with publishing active did not get it, nor sites having a large number of webpart/wiki pages) we
                    // check if it should have been turned on by checking for the "site page" content type being added to the site pages library
                    var listsToScan      = web.GetListsToScan();
                    var sitePagesLibrary = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary).FirstOrDefault();

                    if (sitePagesLibrary != null)
                    {
                        cc.Load(sitePagesLibrary, p => p.ContentTypes.Include(c => c.Id));
                        cc.ExecuteQueryRetry();
                        if (sitePagesLibrary.ContentTypes.BestMatch(SitePageContentTypeId) != null)
                        {
                            scanResult.ModernPageFeatureWasEnabledBySPO = true;
                        }
                    }
                }

                // Get information about the master pages used
                if (!string.IsNullOrEmpty(web.MasterUrl) && !excludeMasterPage.Contains(web.MasterUrl.Substring(web.MasterUrl.LastIndexOf("/") + 1).ToLower()))
                {
                    scanResult.MasterPage = web.MasterUrl;
                }
                if (!string.IsNullOrEmpty(web.CustomMasterUrl) && !excludeMasterPage.Contains(web.CustomMasterUrl.Substring(web.CustomMasterUrl.LastIndexOf("/") + 1).ToLower()))
                {
                    scanResult.CustomMasterPage = web.CustomMasterUrl;
                }

                if (!string.IsNullOrEmpty(web.AlternateCssUrl))
                {
                    scanResult.AlternateCSS = web.AlternateCssUrl;
                }

                // Get the user custom actions
                scanResult.WebUserCustomActions = web.UserCustomActions.Analyze(this.SiteCollectionUrl, this.SiteUrl);

                // Get home page from the web and check whether it's a modern page or not
                scanResult.ModernHomePage = false;
                var homePageUrl  = web.RootFolder.WelcomePage;
                var homepageName = System.IO.Path.GetFileName(web.RootFolder.WelcomePage);
                if (string.IsNullOrEmpty(homepageName))
                {
                    homepageName = "Home.aspx";
                }
                var sitePagesLibraryForWeb = web.GetListsToScan().Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary).FirstOrDefault();
                if (sitePagesLibraryForWeb != null)
                {
                    var homePageFile = web.GetFileByServerRelativeUrl($"{sitePagesLibraryForWeb.RootFolder.ServerRelativeUrl}/{homepageName}");
                    cc.Load(homePageFile, f => f.ListItemAllFields, f => f.Exists);
                    cc.ExecuteQueryRetry();
                    if (homePageFile.Exists)
                    {
                        var item = homePageFile.ListItemAllFields;
                        if (item.FieldValues.ContainsKey(ClientSideApplicationId) && item[ClientSideApplicationId] != null && item[ClientSideApplicationId].ToString().Equals(FeatureId_Web_ModernPage.ToString(), StringComparison.InvariantCultureIgnoreCase))
                        {
                            scanResult.ModernHomePage = true;
                        }
                    }
                }

                // Push information from root web to respective SiteScanResult object
                if (!cc.Web.IsSubSite())
                {
                    SiteScanResult siteScanData;
                    if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData))
                    {
                        var clonedSiteScandata = siteScanData.Clone();
                        clonedSiteScandata.WebPublishingFeatureEnabled         = scanResult.WebPublishingFeatureEnabled;
                        clonedSiteScandata.ModernPageWebFeatureDisabled        = scanResult.ModernPageWebFeatureDisabled;
                        clonedSiteScandata.ModernPageFeatureWasEnabledBySPO    = scanResult.ModernPageFeatureWasEnabledBySPO;
                        clonedSiteScandata.ModernListWebBlockingFeatureEnabled = scanResult.ModernListWebBlockingFeatureEnabled;
                        clonedSiteScandata.ModernHomePage       = scanResult.ModernHomePage;
                        clonedSiteScandata.MasterPage           = (!String.IsNullOrEmpty(scanResult.MasterPage) || !String.IsNullOrEmpty(scanResult.CustomMasterPage));
                        clonedSiteScandata.AlternateCSS         = !String.IsNullOrEmpty(scanResult.AlternateCSS);
                        clonedSiteScandata.WebUserCustomActions = scanResult.WebUserCustomActions;

                        if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "WebAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                }

                // Persist web results
                if (!this.ScanJob.WebScanResults.TryAdd(this.SiteUrl, scanResult))
                {
                    ScanError error = new ScanError()
                    {
                        Error      = $"Could not add web scan result for {this.SiteUrl}",
                        SiteColUrl = this.SiteCollectionUrl,
                        SiteURL    = this.SiteUrl,
                        Field1     = "WebAnalyzer",
                    };
                    this.ScanJob.ScanErrors.Push(error);
                }

                if (this.ScanJob.Mode == Mode.Full)
                {
                    // Kickoff the page analysing
                    var pageAnalyzer = new PageAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob, this.pageSearchResults);
                    pageAnalyzer.Analyze(cc);
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#17
0
        /// <summary>
        /// Analyses a page
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve page data</param>
        /// <returns>Duration of the page analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);
                Site site = cc.Site;
                site.EnsureProperties(p => p.Features);
                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration, p => p.Features, p => p.Language, p => p.CustomMasterUrl, p => p.MasterUrl);

                var homePageUrl = web.WelcomePage;
                if (string.IsNullOrEmpty(homePageUrl))
                {
                    // Will be case when the site home page is a web part page
                    homePageUrl = "default.aspx";
                }

                var listsToScan        = web.GetListsToScan();
                var sitePagesLibraries = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary);

                if (sitePagesLibraries.Count() > 0)
                {
                    foreach (var sitePagesLibrary in sitePagesLibraries)
                    {
                        CamlQuery query = new CamlQuery
                        {
                            ViewXml = CAMLQueryByExtension
                        };
                        var pages = sitePagesLibrary.GetItems(query);
                        web.Context.Load(pages);
                        web.Context.ExecuteQueryRetry();

                        if (pages.FirstOrDefault() != null)
                        {
                            DateTime start;
                            bool     forceCheckout = sitePagesLibrary.ForceCheckout;
                            foreach (var page in pages)
                            {
                                string pageUrl = null;
                                try
                                {
                                    if (page.FieldValues.ContainsKey(Field_FileRefField) && !String.IsNullOrEmpty(page[Field_FileRefField].ToString()))
                                    {
                                        pageUrl = page[Field_FileRefField].ToString();

                                        // In home page only mode we only continue if this page is the site's home page
                                        if (Options.IsHomePageOnly(this.ScanJob.Mode) && !pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        //skip page
                                        continue;
                                    }

                                    start = DateTime.Now;
                                    PageScanResult pageResult = new PageScanResult()
                                    {
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        PageUrl    = pageUrl,
                                        Library    = sitePagesLibrary.RootFolder.ServerRelativeUrl,
                                    };

                                    // Is this page the web's home page?
                                    if (pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        pageResult.HomePage = true;
                                    }

                                    // Get the type of the page
                                    pageResult.PageType = page.PageType();

                                    // Get page web parts
                                    var pageAnalysis = page.WebParts(this.ScanJob.PageTransformation);
                                    if (pageAnalysis != null)
                                    {
                                        pageResult.Layout   = pageAnalysis.Item1.ToString().Replace("Wiki_", "").Replace("WebPart_", "");
                                        pageResult.WebParts = pageAnalysis.Item2;
                                    }

                                    // Determine if this site contains a default "uncustomized" home page
                                    bool isUncustomizedHomePage = false;

                                    bool canModernizeHomePageWorked = false;
                                    try
                                    {
                                        var canModernizeHomepage = web.CanModernizeHomepage;
                                        web.Context.Load(canModernizeHomepage);
                                        web.Context.ExecuteQueryRetry();

                                        isUncustomizedHomePage          = canModernizeHomepage.CanModernizeHomepage;
                                        canModernizeHomePageWorked      = true;
                                        pageResult.UncustomizedHomePage = isUncustomizedHomePage;
                                    }
                                    catch (Exception ex)
                                    {
                                    }
                                    // If for some reason the API did not work, then let's fall back to the old approach
                                    if (!canModernizeHomePageWorked)
                                    {
                                        try
                                        {
                                            string pageName = "";
                                            if (page.FieldValues.ContainsKey(Field_FileLeafRef) && !String.IsNullOrEmpty(page[Field_FileLeafRef].ToString()))
                                            {
                                                pageName = page[Field_FileLeafRef].ToString();
                                            }

                                            if (pageResult.HomePage && web.WebTemplate == "STS" && web.Configuration == 0)
                                            {
                                                bool publishingWebFeatureEnabled   = web.Features.Where(f => f.DefinitionId == WebAnalyzer.FeatureId_Web_Publishing).Count() > 0;
                                                bool publishingSiteFeatureEnabled  = site.Features.Where(f => f.DefinitionId == SiteAnalyzer.FeatureId_Site_Publishing).Count() > 0;
                                                bool homePageModernizationOptedOut = web.Features.Where(f => f.DefinitionId == FeatureId_Web_HomePage).Count() > 0;

                                                if (!homePageModernizationOptedOut && !publishingSiteFeatureEnabled && !publishingWebFeatureEnabled)
                                                {
                                                    bool siteWasGroupified = web.Features.Where(f => f.DefinitionId == FeatureId_Web_GroupHomepage).Count() > 0;
                                                    if (!siteWasGroupified)
                                                    {
                                                        // Check for master page url
                                                        if (web.MasterUrl.EndsWith("_catalogs/masterpage/seattle.master", StringComparison.InvariantCultureIgnoreCase))
                                                        {
                                                            // Check for home page name, only "default sts#0 home pages" should be considered, so
                                                            // home.aspx or the translated versions
                                                            var homePageName = this.ScanJob.Store.Get <string>(this.ScanJob.StoreOptions.GetKey(keyWikiHomePageName));
                                                            if (homePageName == null)
                                                            {
                                                                ClientResult <string> result = Microsoft.SharePoint.Client.Utilities.Utility.GetLocalizedString(web.Context, "$Resources:WikiPageHomePageName", "core", (int)web.Language);
                                                                web.Context.ExecuteQueryRetry();
                                                                homePageName = $"{new Regex(@"['´`]").Replace(result.Value, "")}.aspx";
                                                                this.ScanJob.Store.Set <string>(this.ScanJob.StoreOptions.GetKey(keyWikiHomePageName), homePageName, this.ScanJob.StoreOptions.EntryOptions);
                                                            }

                                                            if (pageName.Equals(homePageName, StringComparison.InvariantCultureIgnoreCase))
                                                            {
                                                                var wiki = page.FieldValues[Field_WikiField].ToString();
                                                                if (!string.IsNullOrEmpty(wiki))
                                                                {
                                                                    var isHtmlUncustomized = IsHtmlUncustomized(wiki);

                                                                    if (isHtmlUncustomized)
                                                                    {
                                                                        string pageType = GetPageWebPartInfo(pageResult.WebParts);

                                                                        if (pageType == TeamSiteDefaultWebParts)
                                                                        {
                                                                            page.ContentType.EnsureProperty(p => p.DisplayFormTemplateName);
                                                                            if (page.ContentType.DisplayFormTemplateName == "WikiEditForm")
                                                                            {
                                                                                isUncustomizedHomePage = true;
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            // no point in failing the scan if something goes wrong here
                                        }
                                        finally
                                        {
                                            pageResult.UncustomizedHomePage = isUncustomizedHomePage;
                                        }
                                    }

                                    // Get page change information
                                    pageResult.ModifiedAt = page.LastModifiedDateTime();
                                    pageResult.ModifiedBy = page.LastModifiedBy();

                                    // Grab this page from the search results to connect view information
                                    string fullPageUrl = $"https://{new Uri(this.SiteCollectionUrl).DnsSafeHost}{pageUrl}";
                                    if (pageResult.HomePage)
                                    {
                                        fullPageUrl = this.SiteUrl;
                                    }

                                    if (!this.ScanJob.SkipUsageInformation && this.pageSearchResults != null)
                                    {
                                        var searchPage = this.pageSearchResults.Where(x => x.Values.Contains(fullPageUrl)).FirstOrDefault();
                                        if (searchPage != null)
                                        {
                                            // Recent = last 14 days
                                            pageResult.ViewsRecent              = searchPage["ViewsRecent"].ToInt32();
                                            pageResult.ViewsRecentUniqueUsers   = searchPage["ViewsRecentUniqueUsers"].ToInt32();
                                            pageResult.ViewsLifeTime            = searchPage["ViewsLifeTime"].ToInt32();
                                            pageResult.ViewsLifeTimeUniqueUsers = searchPage["ViewsLifeTimeUniqueUsers"].ToInt32();
                                        }
                                    }

                                    if (!this.ScanJob.PageScanResults.TryAdd(pageResult.PageUrl, pageResult))
                                    {
                                        ScanError error = new ScanError()
                                        {
                                            Error      = $"Could not add page scan result for {pageResult.PageUrl}",
                                            SiteColUrl = this.SiteCollectionUrl,
                                            SiteURL    = this.SiteUrl,
                                            Field1     = "PageAnalyzer",
                                        };
                                        this.ScanJob.ScanErrors.Push(error);
                                    }
                                    var duration = new TimeSpan((DateTime.Now.Subtract(start).Ticks));
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "MainPageAnalyzerLoop",
                                        Field2     = ex.StackTrace,
                                        Field3     = pageUrl
                                    };

                                    // Send error to telemetry to make scanner better
                                    if (this.ScanJob.ScannerTelemetry != null)
                                    {
                                        this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                                    }

                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#18
0
        /// <summary>
        /// Analyses a web for it's workflow usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve workflow data</param>
        /// <returns>Duration of the workflow analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                Web web = cc.Web;

                // Pre-load needed properties in a single call
                cc.Load(web, w => w.Id, w => w.ServerRelativeUrl, w => w.Url, w => w.WorkflowTemplates, w => w.WorkflowAssociations);
                cc.Load(web, p => p.ContentTypes.Include(ct => ct.WorkflowAssociations, ct => ct.Name, ct => ct.StringId));
                cc.Load(web, p => p.Lists.Include(li => li.Id, li => li.Title, li => li.Hidden, li => li.DefaultViewUrl, li => li.BaseTemplate, li => li.RootFolder, li => li.ItemCount, li => li.WorkflowAssociations));
                cc.ExecuteQueryRetry();

                var lists = web.Lists;

                // *******************************************
                // Site, reusable and list level 2013 workflow
                // *******************************************

                // Retrieve the 2013 site level workflow definitions (including unpublished ones)
                WorkflowDefinition[] siteDefinitions = null;
                // Retrieve the 2013 site level workflow subscriptions
                WorkflowSubscription[] siteSubscriptions = null;

                try
                {
                    var servicesManager     = new WorkflowServicesManager(web.Context, web);
                    var deploymentService   = servicesManager.GetWorkflowDeploymentService();
                    var subscriptionService = servicesManager.GetWorkflowSubscriptionService();

                    var definitions = deploymentService.EnumerateDefinitions(false);
                    web.Context.Load(definitions);

                    var subscriptions = subscriptionService.EnumerateSubscriptions();
                    web.Context.Load(subscriptions);

                    web.Context.ExecuteQueryRetry();

                    siteDefinitions   = definitions.ToArray();
                    siteSubscriptions = subscriptions.ToArray();
                }
                catch (ServerException)
                {
                    // If there is no workflow service present in the farm this method will throw an error.
                    // Swallow the exception
                }

                // We've found SP2013 site scoped workflows
                if (siteDefinitions.Count() > 0)
                {
                    foreach (var siteDefinition in siteDefinitions.Where(p => p.RestrictToType.Equals("site", StringComparison.InvariantCultureIgnoreCase) || p.RestrictToType.Equals("universal", StringComparison.InvariantCultureIgnoreCase)))
                    {
                        // Check if this workflow is also in use
                        var siteWorkflowSubscriptions = siteSubscriptions.Where(p => p.DefinitionId.Equals(siteDefinition.Id));

                        if (siteWorkflowSubscriptions.Count() > 0)
                        {
                            foreach (var siteWorkflowSubscription in siteWorkflowSubscriptions)
                            {
                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl            = this.SiteCollectionUrl,
                                    SiteURL               = this.SiteUrl,
                                    ListTitle             = "",
                                    ListUrl               = "",
                                    ContentTypeId         = "",
                                    ContentTypeName       = "",
                                    Version               = "2013",
                                    Scope                 = "Site",
                                    RestrictToType        = siteDefinition.RestrictToType,
                                    DefinitionName        = siteDefinition.DisplayName,
                                    DefinitionDescription = siteDefinition.Description,
                                    SubscriptionName      = siteWorkflowSubscription.Name,
                                    HasSubscriptions      = true,
                                    Enabled               = siteWorkflowSubscription.Enabled,
                                    DefinitionId          = siteDefinition.Id,
                                    IsOOBWorkflow         = false,
                                    SubscriptionId        = siteWorkflowSubscription.Id,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2013 site workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                            {
                                SiteColUrl            = this.SiteCollectionUrl,
                                SiteURL               = this.SiteUrl,
                                ListTitle             = "",
                                ListUrl               = "",
                                ContentTypeId         = "",
                                ContentTypeName       = "",
                                Version               = "2013",
                                Scope                 = "Site",
                                RestrictToType        = siteDefinition.RestrictToType,
                                DefinitionName        = siteDefinition.DisplayName,
                                DefinitionDescription = siteDefinition.Description,
                                SubscriptionName      = "",
                                HasSubscriptions      = false,
                                Enabled               = false,
                                DefinitionId          = siteDefinition.Id,
                                IsOOBWorkflow         = false,
                                SubscriptionId        = Guid.Empty,
                            };

                            if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add 2013 site workflow scan result for {workflowScanResult.SiteColUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WorkflowAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }

                // We've found SP2013 list scoped workflows
                if (siteDefinitions.Count() > 0)
                {
                    foreach (var listDefinition in siteDefinitions.Where(p => p.RestrictToType.Equals("list", StringComparison.InvariantCultureIgnoreCase) || p.RestrictToType.Equals("universal", StringComparison.InvariantCultureIgnoreCase)))
                    {
                        // Check if this workflow is also in use
                        var listWorkflowSubscriptions = siteSubscriptions.Where(p => p.DefinitionId.Equals(listDefinition.Id));

                        if (listWorkflowSubscriptions.Count() > 0)
                        {
                            foreach (var listWorkflowSubscription in listWorkflowSubscriptions)
                            {
                                Guid   associatedListId    = Guid.Empty;
                                string associatedListTitle = "";
                                string associatedListUrl   = "";
                                if (Guid.TryParse(GetWorkflowProperty(listWorkflowSubscription, "Microsoft.SharePoint.ActivationProperties.ListId"), out Guid associatedListIdValue))
                                {
                                    associatedListId = associatedListIdValue;

                                    // Lookup this list and update title and url
                                    var listLookup = lists.Where(p => p.Id.Equals(associatedListId)).FirstOrDefault();
                                    if (listLookup != null)
                                    {
                                        associatedListTitle = listLookup.Title;
                                        associatedListUrl   = listLookup.RootFolder.ServerRelativeUrl;
                                    }
                                }

                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl            = this.SiteCollectionUrl,
                                    SiteURL               = this.SiteUrl,
                                    ListTitle             = associatedListTitle,
                                    ListUrl               = associatedListUrl,
                                    ListId                = associatedListId,
                                    ContentTypeId         = "",
                                    ContentTypeName       = "",
                                    Version               = "2013",
                                    Scope                 = "List",
                                    RestrictToType        = listDefinition.RestrictToType,
                                    DefinitionName        = listDefinition.DisplayName,
                                    DefinitionDescription = listDefinition.Description,
                                    SubscriptionName      = listWorkflowSubscription.Name,
                                    HasSubscriptions      = true,
                                    Enabled               = listWorkflowSubscription.Enabled,
                                    DefinitionId          = listDefinition.Id,
                                    IsOOBWorkflow         = false,
                                    SubscriptionId        = listWorkflowSubscription.Id,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2013 list workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                            {
                                SiteColUrl            = this.SiteCollectionUrl,
                                SiteURL               = this.SiteUrl,
                                ListTitle             = "",
                                ListUrl               = "",
                                ListId                = Guid.Empty,
                                ContentTypeId         = "",
                                ContentTypeName       = "",
                                Version               = "2013",
                                Scope                 = "List",
                                RestrictToType        = listDefinition.RestrictToType,
                                DefinitionName        = listDefinition.DisplayName,
                                DefinitionDescription = listDefinition.Description,
                                SubscriptionName      = "",
                                HasSubscriptions      = false,
                                Enabled               = false,
                                DefinitionId          = listDefinition.Id,
                                IsOOBWorkflow         = false,
                                SubscriptionId        = Guid.Empty,
                            };

                            if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add 2013 list workflow scan result for {workflowScanResult.SiteColUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WorkflowAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }

                // ***********************************************
                // Site, list and content type level 2010 workflow
                // ***********************************************

                // Find all places where we have workflows associated (=subscribed) to SharePoint objects
                if (web.WorkflowAssociations.Count > 0)
                {
                    foreach (var workflowAssociation in web.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "Site", WorkflowAssociation = workflowAssociation
                        });
                    }
                }

                foreach (var list in lists.Where(p => p.WorkflowAssociations.Count > 0))
                {
                    foreach (var workflowAssociation in list.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "List", WorkflowAssociation = workflowAssociation, AssociatedList = list
                        });
                    }
                }

                foreach (var ct in web.ContentTypes.Where(p => p.WorkflowAssociations.Count > 0))
                {
                    foreach (var workflowAssociation in ct.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "ContentType", WorkflowAssociation = workflowAssociation, AssociatedContentType = ct
                        });
                    }
                }

                // Process 2010 worflows
                System.Collections.Generic.List <Guid> processedWorkflowAssociations = new System.Collections.Generic.List <Guid>(this.sp2010WorkflowAssociations.Count);
                if (web.WorkflowTemplates.Count > 0)
                {
                    foreach (var workflowTemplate in web.WorkflowTemplates)
                    {
                        // do we have workflows associated for this template?
                        var associatedWorkflows = this.sp2010WorkflowAssociations.Where(p => p.WorkflowAssociation.BaseId.Equals(workflowTemplate.Id));

                        if (associatedWorkflows.Count() > 0)
                        {
                            foreach (var associatedWorkflow in associatedWorkflows)
                            {
                                processedWorkflowAssociations.Add(associatedWorkflow.WorkflowAssociation.Id);

                                // Skip previous versions of a workflow
                                // todo: non-english sites will use another string
                                if (associatedWorkflow.WorkflowAssociation.Name.Contains("(Previous Version:"))
                                {
                                    continue;
                                }

                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl            = this.SiteCollectionUrl,
                                    SiteURL               = this.SiteUrl,
                                    ListTitle             = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Title : "",
                                    ListUrl               = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.RootFolder.ServerRelativeUrl : "",
                                    ListId                = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Id : Guid.Empty,
                                    ContentTypeId         = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.StringId : "",
                                    ContentTypeName       = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.Name : "",
                                    Version               = "2010",
                                    Scope                 = associatedWorkflow.Scope,
                                    RestrictToType        = "N/A",
                                    DefinitionName        = workflowTemplate.Name,
                                    DefinitionDescription = workflowTemplate.Description,
                                    SubscriptionName      = associatedWorkflow.WorkflowAssociation.Name,
                                    HasSubscriptions      = true,
                                    Enabled               = associatedWorkflow.WorkflowAssociation.Enabled,
                                    DefinitionId          = workflowTemplate.Id,
                                    IsOOBWorkflow         = IsOOBWorkflow(workflowTemplate.Id.ToString()),
                                    SubscriptionId        = associatedWorkflow.WorkflowAssociation.Id,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2010 {associatedWorkflow.Scope} type workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            // Only add non OOB workflow templates when there's no associated workflow - makes the dataset smaller
                            if (!IsOOBWorkflow(workflowTemplate.Id.ToString()))
                            {
                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl            = this.SiteCollectionUrl,
                                    SiteURL               = this.SiteUrl,
                                    ListTitle             = "",
                                    ListUrl               = "",
                                    ListId                = Guid.Empty,
                                    ContentTypeId         = "",
                                    ContentTypeName       = "",
                                    Version               = "2010",
                                    Scope                 = "",
                                    RestrictToType        = "N/A",
                                    DefinitionName        = workflowTemplate.Name,
                                    DefinitionDescription = workflowTemplate.Description,
                                    SubscriptionName      = "",
                                    HasSubscriptions      = false,
                                    Enabled               = false,
                                    DefinitionId          = workflowTemplate.Id,
                                    IsOOBWorkflow         = IsOOBWorkflow(workflowTemplate.Id.ToString()),
                                    SubscriptionId        = Guid.Empty,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2010 type workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                }

                // Are there associated workflows for which we did not find a template
                foreach (var associatedWorkflow in this.sp2010WorkflowAssociations)
                {
                    if (!processedWorkflowAssociations.Contains(associatedWorkflow.WorkflowAssociation.Id))
                    {
                        // Skip previous versions of a workflow
                        // todo: non-english sites will use another string
                        if (associatedWorkflow.WorkflowAssociation.Name.Contains("(Previous Version:"))
                        {
                            continue;
                        }

                        WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                        {
                            SiteColUrl            = this.SiteCollectionUrl,
                            SiteURL               = this.SiteUrl,
                            ListTitle             = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Title : "",
                            ListUrl               = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.RootFolder.ServerRelativeUrl : "",
                            ListId                = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Id : Guid.Empty,
                            ContentTypeId         = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.StringId : "",
                            ContentTypeName       = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.Name : "",
                            Version               = "2010",
                            Scope                 = associatedWorkflow.Scope,
                            RestrictToType        = "N/A",
                            DefinitionName        = associatedWorkflow.WorkflowAssociation.Name,
                            DefinitionDescription = "",
                            SubscriptionName      = associatedWorkflow.WorkflowAssociation.Name,
                            HasSubscriptions      = true,
                            Enabled               = associatedWorkflow.WorkflowAssociation.Enabled,
                            DefinitionId          = Guid.Empty,
                            IsOOBWorkflow         = false,
                            SubscriptionId        = associatedWorkflow.WorkflowAssociation.Id,
                        };

                        if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add 2010 {associatedWorkflow.Scope} type workflow scan result for {workflowScanResult.SiteColUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "WorkflowAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#19
0
        /// <summary>
        /// Analyses a web for it's workflow usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve workflow data</param>
        /// <returns>Duration of the workflow analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                // Workflow analysis does not work as the xoml / xaml files can't be read with Sites.Read.All permission
                if (!this.ScanJob.AppOnlyHasFullControl)
                {
                    return(TimeSpan.Zero);
                }

                Web web = cc.Web;

                // Pre-load needed properties in a single call
                cc.Load(web, w => w.Id, w => w.ServerRelativeUrl, w => w.Url, w => w.WorkflowTemplates, w => w.WorkflowAssociations);
                cc.Load(web, p => p.ContentTypes.Include(ct => ct.WorkflowAssociations, ct => ct.Name, ct => ct.StringId));
                cc.Load(web, p => p.Lists.Include(li => li.Id, li => li.Title, li => li.Hidden, li => li.DefaultViewUrl, li => li.BaseTemplate, li => li.RootFolder.ServerRelativeUrl, li => li.ItemCount, li => li.WorkflowAssociations));
                cc.Load(cc.Site, p => p.RootWeb);
                cc.Load(cc.Site.RootWeb, p => p.Lists.Include(li => li.Id, li => li.Title, li => li.Hidden, li => li.DefaultViewUrl, li => li.BaseTemplate, li => li.RootFolder.ServerRelativeUrl, li => li.ItemCount, li => li.WorkflowAssociations));
                cc.ExecuteQueryRetry();

                var lists = web.Lists;

                // *******************************************
                // Site, reusable and list level 2013 workflow
                // *******************************************

                // Retrieve the 2013 site level workflow definitions (including unpublished ones)
                WorkflowDefinition[] siteDefinitions = null;
                // Retrieve the 2013 site level workflow subscriptions
                WorkflowSubscription[] siteSubscriptions = null;

                try
                {
                    var servicesManager     = new WorkflowServicesManager(web.Context, web);
                    var deploymentService   = servicesManager.GetWorkflowDeploymentService();
                    var subscriptionService = servicesManager.GetWorkflowSubscriptionService();

                    var definitions = deploymentService.EnumerateDefinitions(false);
                    web.Context.Load(definitions);

                    var subscriptions = subscriptionService.EnumerateSubscriptions();
                    web.Context.Load(subscriptions);

                    web.Context.ExecuteQueryRetry();

                    siteDefinitions   = definitions.ToArray();
                    siteSubscriptions = subscriptions.ToArray();
                }
                catch (ServerException ex)
                {
                    // If there is no workflow service present in the farm this method will throw an error.
                    // Swallow the exception
                }

                // We've found SP2013 site scoped workflows
                if (siteDefinitions != null && siteDefinitions.Count() > 0)
                {
                    foreach (var siteDefinition in siteDefinitions.Where(p => p.RestrictToType != null && (p.RestrictToType.Equals("site", StringComparison.InvariantCultureIgnoreCase) || p.RestrictToType.Equals("universal", StringComparison.InvariantCultureIgnoreCase))))
                    {
                        // Check if this workflow is also in use
                        var siteWorkflowSubscriptions = siteSubscriptions.Where(p => p.DefinitionId.Equals(siteDefinition.Id));

                        // Perform workflow analysis
                        WorkflowActionAnalysis  workFlowAnalysisResult        = null;
                        WorkflowTriggerAnalysis workFlowTriggerAnalysisResult = null;
                        if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                        {
                            workFlowAnalysisResult        = WorkflowManager.Instance.ParseWorkflowDefinition(siteDefinition.Xaml, WorkflowTypes.SP2013);
                            workFlowTriggerAnalysisResult = WorkflowManager.Instance.ParseWorkflowTriggers(GetWorkflowPropertyBool(siteDefinition.Properties, "SPDConfig.StartOnCreate"), GetWorkflowPropertyBool(siteDefinition.Properties, "SPDConfig.StartOnChange"), GetWorkflowPropertyBool(siteDefinition.Properties, "SPDConfig.StartManually"));
                        }

                        if (siteWorkflowSubscriptions.Count() > 0)
                        {
                            foreach (var siteWorkflowSubscription in siteWorkflowSubscriptions)
                            {
                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    ListTitle                = "",
                                    ListUrl                  = "",
                                    ContentTypeId            = "",
                                    ContentTypeName          = "",
                                    Version                  = "2013",
                                    Scope                    = "Site",
                                    RestrictToType           = siteDefinition.RestrictToType,
                                    DefinitionName           = siteDefinition.DisplayName,
                                    DefinitionDescription    = siteDefinition.Description,
                                    SubscriptionName         = siteWorkflowSubscription.Name,
                                    HasSubscriptions         = true,
                                    Enabled                  = siteWorkflowSubscription.Enabled,
                                    DefinitionId             = siteDefinition.Id,
                                    IsOOBWorkflow            = false,
                                    SubscriptionId           = siteWorkflowSubscription.Id,
                                    UsedActions              = workFlowAnalysisResult?.WorkflowActions,
                                    ActionCount              = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                    UsedTriggers             = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                    UnsupportedActionsInFlow = workFlowAnalysisResult?.UnsupportedActions,
                                    UnsupportedActionCount   = workFlowAnalysisResult != null ? workFlowAnalysisResult.UnsupportedAccountCount : 0,
                                    LastDefinitionEdit       = GetWorkflowPropertyDateTime(siteDefinition.Properties, "Definition.ModifiedDateUTC"),
                                    LastSubscriptionEdit     = GetWorkflowPropertyDateTime(siteWorkflowSubscription.PropertyDefinitions, "SharePointWorkflowContext.Subscription.ModifiedDateUTC"),
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2013 site workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                ListTitle                = "",
                                ListUrl                  = "",
                                ContentTypeId            = "",
                                ContentTypeName          = "",
                                Version                  = "2013",
                                Scope                    = "Site",
                                RestrictToType           = siteDefinition.RestrictToType,
                                DefinitionName           = siteDefinition.DisplayName,
                                DefinitionDescription    = siteDefinition.Description,
                                SubscriptionName         = "",
                                HasSubscriptions         = false,
                                Enabled                  = false,
                                DefinitionId             = siteDefinition.Id,
                                IsOOBWorkflow            = false,
                                SubscriptionId           = Guid.Empty,
                                UsedActions              = workFlowAnalysisResult?.WorkflowActions,
                                ActionCount              = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                UnsupportedActionsInFlow = workFlowAnalysisResult?.UnsupportedActions,
                                UnsupportedActionCount   = workFlowAnalysisResult != null ? workFlowAnalysisResult.UnsupportedAccountCount : 0,
                                UsedTriggers             = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                LastDefinitionEdit       = GetWorkflowPropertyDateTime(siteDefinition.Properties, "Definition.ModifiedDateUTC"),
                            };

                            if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add 2013 site workflow scan result for {workflowScanResult.SiteColUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WorkflowAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }

                // We've found SP2013 list scoped workflows
                if (siteDefinitions != null && siteDefinitions.Count() > 0)
                {
                    foreach (var listDefinition in siteDefinitions.Where(p => p.RestrictToType != null && (p.RestrictToType.Equals("list", StringComparison.InvariantCultureIgnoreCase) || p.RestrictToType.Equals("universal", StringComparison.InvariantCultureIgnoreCase))))
                    {
                        // Check if this workflow is also in use
                        var listWorkflowSubscriptions = siteSubscriptions.Where(p => p.DefinitionId.Equals(listDefinition.Id));

                        // Perform workflow analysis
                        WorkflowActionAnalysis  workFlowAnalysisResult        = null;
                        WorkflowTriggerAnalysis workFlowTriggerAnalysisResult = null;
                        if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                        {
                            workFlowAnalysisResult        = WorkflowManager.Instance.ParseWorkflowDefinition(listDefinition.Xaml, WorkflowTypes.SP2013);
                            workFlowTriggerAnalysisResult = WorkflowManager.Instance.ParseWorkflowTriggers(GetWorkflowPropertyBool(listDefinition.Properties, "SPDConfig.StartOnCreate"), GetWorkflowPropertyBool(listDefinition.Properties, "SPDConfig.StartOnChange"), GetWorkflowPropertyBool(listDefinition.Properties, "SPDConfig.StartManually"));
                        }

                        if (listWorkflowSubscriptions.Count() > 0)
                        {
                            foreach (var listWorkflowSubscription in listWorkflowSubscriptions)
                            {
                                Guid   associatedListId    = Guid.Empty;
                                string associatedListTitle = "";
                                string associatedListUrl   = "";
                                if (Guid.TryParse(GetWorkflowProperty(listWorkflowSubscription, "Microsoft.SharePoint.ActivationProperties.ListId"), out Guid associatedListIdValue))
                                {
                                    associatedListId = associatedListIdValue;

                                    // Lookup this list and update title and url
                                    var listLookup = lists.Where(p => p.Id.Equals(associatedListId)).FirstOrDefault();
                                    if (listLookup != null)
                                    {
                                        associatedListTitle = listLookup.Title;
                                        associatedListUrl   = listLookup.RootFolder.ServerRelativeUrl;
                                    }
                                }

                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    ListTitle                = associatedListTitle,
                                    ListUrl                  = associatedListUrl,
                                    ListId                   = associatedListId,
                                    ContentTypeId            = "",
                                    ContentTypeName          = "",
                                    Version                  = "2013",
                                    Scope                    = "List",
                                    RestrictToType           = listDefinition.RestrictToType,
                                    DefinitionName           = listDefinition.DisplayName,
                                    DefinitionDescription    = listDefinition.Description,
                                    SubscriptionName         = listWorkflowSubscription.Name,
                                    HasSubscriptions         = true,
                                    Enabled                  = listWorkflowSubscription.Enabled,
                                    DefinitionId             = listDefinition.Id,
                                    IsOOBWorkflow            = false,
                                    SubscriptionId           = listWorkflowSubscription.Id,
                                    UsedActions              = workFlowAnalysisResult?.WorkflowActions,
                                    ActionCount              = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                    UsedTriggers             = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                    UnsupportedActionsInFlow = workFlowAnalysisResult?.UnsupportedActions,
                                    UnsupportedActionCount   = workFlowAnalysisResult != null ? workFlowAnalysisResult.UnsupportedAccountCount : 0,
                                    LastDefinitionEdit       = GetWorkflowPropertyDateTime(listDefinition.Properties, "Definition.ModifiedDateUTC"),
                                    LastSubscriptionEdit     = GetWorkflowPropertyDateTime(listWorkflowSubscription.PropertyDefinitions, "SharePointWorkflowContext.Subscription.ModifiedDateUTC"),
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2013 list workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                ListTitle                = "",
                                ListUrl                  = "",
                                ListId                   = Guid.Empty,
                                ContentTypeId            = "",
                                ContentTypeName          = "",
                                Version                  = "2013",
                                Scope                    = "List",
                                RestrictToType           = listDefinition.RestrictToType,
                                DefinitionName           = listDefinition.DisplayName,
                                DefinitionDescription    = listDefinition.Description,
                                SubscriptionName         = "",
                                HasSubscriptions         = false,
                                Enabled                  = false,
                                DefinitionId             = listDefinition.Id,
                                IsOOBWorkflow            = false,
                                SubscriptionId           = Guid.Empty,
                                UsedActions              = workFlowAnalysisResult?.WorkflowActions,
                                ActionCount              = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                UsedTriggers             = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                UnsupportedActionsInFlow = workFlowAnalysisResult?.UnsupportedActions,
                                UnsupportedActionCount   = workFlowAnalysisResult != null ? workFlowAnalysisResult.UnsupportedAccountCount : 0,
                                LastDefinitionEdit       = GetWorkflowPropertyDateTime(listDefinition.Properties, "Definition.ModifiedDateUTC"),
                            };

                            if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add 2013 list workflow scan result for {workflowScanResult.SiteColUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WorkflowAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }

                // ***********************************************
                // Site, list and content type level 2010 workflow
                // ***********************************************

                // Find all places where we have workflows associated (=subscribed) to SharePoint objects
                if (web.WorkflowAssociations.Count > 0)
                {
                    foreach (var workflowAssociation in web.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "Site", WorkflowAssociation = workflowAssociation
                        });
                    }
                }

                foreach (var list in lists.Where(p => p.WorkflowAssociations.Count > 0))
                {
                    foreach (var workflowAssociation in list.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "List", WorkflowAssociation = workflowAssociation, AssociatedList = list
                        });
                    }
                }

                foreach (var ct in web.ContentTypes.Where(p => p.WorkflowAssociations.Count > 0))
                {
                    foreach (var workflowAssociation in ct.WorkflowAssociations)
                    {
                        this.sp2010WorkflowAssociations.Add(new SP2010WorkFlowAssociation()
                        {
                            Scope = "ContentType", WorkflowAssociation = workflowAssociation, AssociatedContentType = ct
                        });
                    }
                }

                // Process 2010 worflows
                List <Guid> processedWorkflowAssociations = new List <Guid>(this.sp2010WorkflowAssociations.Count);

                if (web.WorkflowTemplates.Count > 0)
                {
                    // Process the templates
                    foreach (var workflowTemplate in web.WorkflowTemplates)
                    {
                        // do we have workflows associated for this template?
                        var associatedWorkflows = this.sp2010WorkflowAssociations.Where(p => p.WorkflowAssociation.BaseId.Equals(workflowTemplate.Id));
                        if (associatedWorkflows.Count() > 0)
                        {
                            // Perform workflow analysis
                            // If returning null than this workflow template was an OOB workflow one
                            WorkflowActionAnalysis   workFlowAnalysisResult = null;
                            Tuple <string, DateTime> loadedWorkflow         = null;

                            if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                            {
                                loadedWorkflow = LoadWorkflowDefinition(cc, workflowTemplate);
                                if (!string.IsNullOrEmpty(loadedWorkflow?.Item1))
                                {
                                    workFlowAnalysisResult = WorkflowManager.Instance.ParseWorkflowDefinition(loadedWorkflow.Item1, WorkflowTypes.SP2010);
                                }
                            }

                            foreach (var associatedWorkflow in associatedWorkflows)
                            {
                                processedWorkflowAssociations.Add(associatedWorkflow.WorkflowAssociation.Id);

                                // Skip previous versions of a workflow
                                // TODO: non-english sites will use another string
                                if (associatedWorkflow.WorkflowAssociation.Name.Contains("(Previous Version:"))
                                {
                                    continue;
                                }

                                WorkflowTriggerAnalysis workFlowTriggerAnalysisResult = null;
                                if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                                {
                                    workFlowTriggerAnalysisResult = WorkflowManager.Instance.ParseWorkflowTriggers(associatedWorkflow.WorkflowAssociation.AutoStartCreate, associatedWorkflow.WorkflowAssociation.AutoStartChange, associatedWorkflow.WorkflowAssociation.AllowManual);
                                }

                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    ListTitle                = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Title : "",
                                    ListUrl                  = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.RootFolder.ServerRelativeUrl : "",
                                    ListId                   = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Id : Guid.Empty,
                                    ContentTypeId            = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.StringId : "",
                                    ContentTypeName          = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.Name : "",
                                    Version                  = "2010",
                                    Scope                    = associatedWorkflow.Scope,
                                    RestrictToType           = "N/A",
                                    DefinitionName           = workflowTemplate.Name,
                                    DefinitionDescription    = workflowTemplate.Description,
                                    SubscriptionName         = associatedWorkflow.WorkflowAssociation.Name,
                                    HasSubscriptions         = true,
                                    Enabled                  = associatedWorkflow.WorkflowAssociation.Enabled,
                                    DefinitionId             = workflowTemplate.Id,
                                    IsOOBWorkflow            = IsOOBWorkflow(workflowTemplate.Id.ToString()),
                                    SubscriptionId           = associatedWorkflow.WorkflowAssociation.Id,
                                    UsedActions              = workFlowAnalysisResult?.WorkflowActions,
                                    ActionCount              = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                    UsedTriggers             = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                    UnsupportedActionsInFlow = workFlowAnalysisResult?.UnsupportedActions,
                                    UnsupportedActionCount   = workFlowAnalysisResult != null ? workFlowAnalysisResult.UnsupportedAccountCount : 0,
                                    LastDefinitionEdit       = loadedWorkflow != null ? loadedWorkflow.Item2 : associatedWorkflow.WorkflowAssociation.Modified,
                                    LastSubscriptionEdit     = associatedWorkflow.WorkflowAssociation.Modified,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2010 {associatedWorkflow.Scope} type workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        else
                        {
                            // Only add non OOB workflow templates when there's no associated workflow - makes the dataset smaller
                            if (!IsOOBWorkflow(workflowTemplate.Id.ToString()))
                            {
                                // Perform workflow analysis
                                WorkflowActionAnalysis   workFlowAnalysisResult        = null;
                                WorkflowTriggerAnalysis  workFlowTriggerAnalysisResult = null;
                                Tuple <string, DateTime> loadedWorkflow = null;

                                if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                                {
                                    loadedWorkflow = LoadWorkflowDefinition(cc, workflowTemplate);
                                    if (!string.IsNullOrEmpty(loadedWorkflow?.Item1))
                                    {
                                        workFlowAnalysisResult = WorkflowManager.Instance.ParseWorkflowDefinition(loadedWorkflow.Item1, WorkflowTypes.SP2010);
                                    }
                                    workFlowTriggerAnalysisResult = WorkflowManager.Instance.ParseWorkflowTriggers(workflowTemplate.AutoStartCreate, workflowTemplate.AutoStartChange, workflowTemplate.AllowManual);
                                }

                                WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                                {
                                    SiteColUrl            = this.SiteCollectionUrl,
                                    SiteURL               = this.SiteUrl,
                                    ListTitle             = "",
                                    ListUrl               = "",
                                    ListId                = Guid.Empty,
                                    ContentTypeId         = "",
                                    ContentTypeName       = "",
                                    Version               = "2010",
                                    Scope                 = "",
                                    RestrictToType        = "N/A",
                                    DefinitionName        = workflowTemplate.Name,
                                    DefinitionDescription = workflowTemplate.Description,
                                    SubscriptionName      = "",
                                    HasSubscriptions      = false,
                                    Enabled               = false,
                                    DefinitionId          = workflowTemplate.Id,
                                    IsOOBWorkflow         = IsOOBWorkflow(workflowTemplate.Id.ToString()),
                                    SubscriptionId        = Guid.Empty,
                                    UsedActions           = workFlowAnalysisResult?.WorkflowActions,
                                    ActionCount           = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                                    UsedTriggers          = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                                    LastDefinitionEdit    = loadedWorkflow != null ? loadedWorkflow.Item2 : DateTime.MinValue,
                                };

                                if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add 2010 type workflow scan result for {workflowScanResult.SiteColUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WorkflowAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                }

                // Are there associated workflows for which we did not find a template (especially when the WF is created for a list)
                foreach (var associatedWorkflow in this.sp2010WorkflowAssociations)
                {
                    if (!processedWorkflowAssociations.Contains(associatedWorkflow.WorkflowAssociation.Id))
                    {
                        // Skip previous versions of a workflow
                        // TODO: non-english sites will use another string
                        if (associatedWorkflow.WorkflowAssociation.Name.Contains("(Previous Version:"))
                        {
                            continue;
                        }

                        // Perform workflow analysis
                        WorkflowActionAnalysis   workFlowAnalysisResult        = null;
                        WorkflowTriggerAnalysis  workFlowTriggerAnalysisResult = null;
                        Tuple <string, DateTime> loadedWorkflow = null;

                        if (Options.IncludeWorkflowWithDetails(this.ScanJob.Mode))
                        {
                            loadedWorkflow = LoadWorkflowDefinition(cc, associatedWorkflow.WorkflowAssociation);
                            if (!string.IsNullOrEmpty(loadedWorkflow?.Item1))
                            {
                                workFlowAnalysisResult = WorkflowManager.Instance.ParseWorkflowDefinition(loadedWorkflow.Item1, WorkflowTypes.SP2010);
                            }
                            workFlowTriggerAnalysisResult = WorkflowManager.Instance.ParseWorkflowTriggers(associatedWorkflow.WorkflowAssociation.AutoStartCreate, associatedWorkflow.WorkflowAssociation.AutoStartChange, associatedWorkflow.WorkflowAssociation.AllowManual);
                        }

                        WorkflowScanResult workflowScanResult = new WorkflowScanResult()
                        {
                            SiteColUrl            = this.SiteCollectionUrl,
                            SiteURL               = this.SiteUrl,
                            ListTitle             = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Title : "",
                            ListUrl               = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.RootFolder.ServerRelativeUrl : "",
                            ListId                = associatedWorkflow.AssociatedList != null ? associatedWorkflow.AssociatedList.Id : Guid.Empty,
                            ContentTypeId         = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.StringId : "",
                            ContentTypeName       = associatedWorkflow.AssociatedContentType != null ? associatedWorkflow.AssociatedContentType.Name : "",
                            Version               = "2010",
                            Scope                 = associatedWorkflow.Scope,
                            RestrictToType        = "N/A",
                            DefinitionName        = associatedWorkflow.WorkflowAssociation.Name,
                            DefinitionDescription = "",
                            SubscriptionName      = associatedWorkflow.WorkflowAssociation.Name,
                            HasSubscriptions      = true,
                            Enabled               = associatedWorkflow.WorkflowAssociation.Enabled,
                            DefinitionId          = Guid.Empty,
                            IsOOBWorkflow         = false,
                            SubscriptionId        = associatedWorkflow.WorkflowAssociation.Id,
                            UsedActions           = workFlowAnalysisResult?.WorkflowActions,
                            ActionCount           = workFlowAnalysisResult != null ? workFlowAnalysisResult.ActionCount : 0,
                            UsedTriggers          = workFlowTriggerAnalysisResult?.WorkflowTriggers,
                            LastSubscriptionEdit  = associatedWorkflow.WorkflowAssociation.Modified,
                            LastDefinitionEdit    = loadedWorkflow != null ? loadedWorkflow.Item2 : associatedWorkflow.WorkflowAssociation.Modified,
                        };

                        if (!this.ScanJob.WorkflowScanResults.TryAdd($"workflowScanResult.SiteURL.{Guid.NewGuid()}", workflowScanResult))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add 2010 {associatedWorkflow.Scope} type workflow scan result for {workflowScanResult.SiteColUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "WorkflowAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ScanError error = new ScanError()
                {
                    Error      = ex.Message,
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                    Field1     = "WorkflowAnalyzer",
                    Field2     = ex.StackTrace,
                };

                // Send error to telemetry to make scanner better
                if (this.ScanJob.ScannerTelemetry != null)
                {
                    this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                }

                this.ScanJob.ScanErrors.Push(error);
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#20
0
        /// <summary>
        /// Analyze the web
        /// </summary>
        /// <param name="cc">ClientContext of the web to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration, p => p.RootFolder);

                var homePageUrl        = web.RootFolder.WelcomePage;
                var listsToScan        = web.GetListsToScan();
                var sitePagesLibraries = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary);
                var assetLibraries     = listsToScan.Where(p => p.IsSiteAssetsLibrary == true);

                var librariesToScan = sitePagesLibraries.Union(assetLibraries);

                if (librariesToScan.Count() > 0)
                {
                    foreach (var libraryToScan in librariesToScan)
                    {
                        CamlQuery query = new CamlQuery
                        {
                            ViewXml = CAMLQueryByExtension
                        };
                        var pages = libraryToScan.GetItems(query);
                        web.Context.Load(pages);
                        web.Context.ExecuteQueryRetry();

                        if (pages.FirstOrDefault() != null)
                        {
                            DateTime start;
                            bool     forceCheckout = libraryToScan.ForceCheckout;
                            foreach (var page in pages)
                            {
                                string pageUrl = null;
                                try
                                {
                                    if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
                                    {
                                        pageUrl = page[FileRefField].ToString();
                                    }
                                    else
                                    {
                                        //skip page
                                        continue;
                                    }

                                    start = DateTime.Now;

                                    VisioWebPartScanResult visioWebPartResult = null;

                                    // Get page web parts
                                    var foundWebParts = page.WebParts();
                                    if (foundWebParts != null)
                                    {
                                        // Do we have a visio web part?
                                        var visioParts = foundWebParts.Where(p => p.Type == "Microsoft.Office.Visio.Server.WebControls.VisioWebAccess, Microsoft.Office.Visio.Server, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c").ToList();
                                        if (visioParts.Count > 0)
                                        {
                                            Console.WriteLine($"Visio web part found on page {pageUrl}");

                                            visioWebPartResult = new VisioWebPartScanResult()
                                            {
                                                SiteColUrl = this.SiteCollectionUrl,
                                                SiteURL    = this.SiteUrl,
                                                PageUrl    = pageUrl,
                                                Library    = libraryToScan.RootFolder.ServerRelativeUrl,
                                                WebParts   = foundWebParts,
                                            };

                                            // Get page change information
                                            visioWebPartResult.ModifiedAt = page.LastModifiedDateTime();
                                            visioWebPartResult.ModifiedBy = page.LastModifiedBy();

                                            // Grab this page from the search results to connect view information
                                            // Is this page the web's home page?
                                            bool isHomePage = false;
                                            if (pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
                                            {
                                                isHomePage = true;
                                            }

                                            string fullPageUrl = $"https://{new Uri(this.SiteCollectionUrl).DnsSafeHost}{pageUrl}";
                                            if (isHomePage)
                                            {
                                                fullPageUrl = this.SiteUrl;
                                            }

                                            var searchPage = this.pageSearchResults.Where(x => x.Values.Contains(fullPageUrl)).FirstOrDefault();
                                            if (searchPage != null)
                                            {
                                                // Recent = last 14 days
                                                visioWebPartResult.ViewsRecent              = searchPage["ViewsRecent"].ToInt32();
                                                visioWebPartResult.ViewsRecentUniqueUsers   = searchPage["ViewsRecentUniqueUsers"].ToInt32();
                                                visioWebPartResult.ViewsLifeTime            = searchPage["ViewsLifeTime"].ToInt32();
                                                visioWebPartResult.ViewsLifeTimeUniqueUsers = searchPage["ViewsLifeTimeUniqueUsers"].ToInt32();
                                            }

                                            if (!this.ScanJob.VisioWebPartScanResults.TryAdd(visioWebPartResult.PageUrl, visioWebPartResult))
                                            {
                                                ScanError error = new ScanError()
                                                {
                                                    Error      = $"Could not add page scan result for {visioWebPartResult.PageUrl}",
                                                    SiteColUrl = this.SiteCollectionUrl,
                                                    SiteURL    = this.SiteUrl,
                                                    Field1     = "PageAnalyzer",
                                                };
                                                this.ScanJob.ScanErrors.Push(error);
                                            }
                                        }
                                    }

                                    var duration = new TimeSpan((DateTime.Now.Subtract(start).Ticks));
                                    Console.WriteLine($"Scan of page {pageUrl} took {duration.Seconds} seconds");
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "MainPageAnalyzerLoop",
                                        Field2     = ex.StackTrace,
                                        Field3     = pageUrl
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                    Console.WriteLine("Error for page {1}: {0}", ex.Message, pageUrl);
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#21
0
 private static void AssertFailScanErrorHandler(ScanError scanError)
 {
     throw scanError;
 }
示例#22
0
        /// <summary>
        /// Analyses a web for it's workflow usage
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve workflow data</param>
        /// <returns>Duration of the workflow analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                var baseUri   = new Uri(this.SiteUrl);
                var webAppUrl = baseUri.Scheme + "://" + baseUri.Host;

                var lists = cc.Web.GetListsToScan(showHidden: true);

                foreach (var list in lists)
                {
                    // Skip system lists, except for Converted Forms and Form Templates libraries
                    if ((list.IsSystemList || list.IsCatalog || list.IsSiteAssetsLibrary || list.IsEnterpriseGalleryLibrary) &&
                        ((int)list.BaseTemplate != 10102 || !string.Equals(list.RootFolder.Name, "FormServerTemplates", StringComparison.InvariantCultureIgnoreCase)))
                    {
                        continue;
                    }

                    if ((int)list.BaseTemplate == 10102)
                    {
                        // Converted Forms library
                        // Stores converted InfoPath forms for browser rendering. This can become bloated
                        // with many versions stored after every republish. Recommended to clean this out
                        // after migrating away from InfoPath
                        if (list.ItemCount > 0)
                        {
                            InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                InfoPathUsage            = "ConvertedFormLibrary",
                                ListTitle                = list.Title,
                                ListId                   = list.Id,
                                ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                Enabled                  = true,
                                InfoPathTemplate         = string.Empty,
                                InfoPathTemplateUrl      = string.Empty,
                                ItemCount                = list.ItemCount,
                                LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                            };
                            if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add formlibrary InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                        continue;
                    }

                    if (string.Equals(list.RootFolder.Name, "FormServerTemplates", StringComparison.InvariantCultureIgnoreCase))
                    {
                        // Form Templates library
                        // Any templates in here indicate sandbox solution/admin approved forms
                        // Possibly from an on-prem migration?
                        if (list.ItemCount > 0)
                        {
                            InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                InfoPathUsage            = "FormServerTemplates",
                                ListTitle                = list.Title,
                                ListId                   = list.Id,
                                ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                Enabled                  = true,
                                InfoPathTemplate         = string.Empty,
                                InfoPathTemplateUrl      = string.Empty,
                                ItemCount                = list.ItemCount,
                                LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                            };
                            if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add formlibrary InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                        continue;
                    }


                    if (list.BaseType == BaseType.DocumentLibrary)
                    {
                        if (!String.IsNullOrEmpty(list.DocumentTemplateUrl) && list.DocumentTemplateUrl.EndsWith(".xsn", StringComparison.InvariantCultureIgnoreCase))
                        {
                            // Library using an InfoPath file as New Item template
                            InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                            {
                                SiteColUrl               = this.SiteCollectionUrl,
                                SiteURL                  = this.SiteUrl,
                                InfoPathUsage            = "FormLibrary",
                                ListTitle                = list.Title,
                                ListId                   = list.Id,
                                ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                Enabled                  = true,
                                InfoPathTemplate         = list.DocumentTemplateUrl,
                                InfoPathTemplateUrl      = this.SiteUrl.TrimEnd('/') + "/_layouts/16/download.aspx?SourceUrl=" + list.DocumentTemplateUrl,
                                ItemCount                = list.ItemCount,
                                LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                            };
                            // Root relative URL for the template
                            var templateFile = cc.Web.GetFileByServerRelativeUrl(list.DocumentTemplateUrl);
                            infoPathScanResult = ScrapeXsn(cc, infoPathScanResult, templateFile);

                            if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add formlibrary InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }

                        // Iterate through all content types - we may not have a template assigned to the library itself,
                        // only to content types
                        cc.Load(list, p => p.ContentTypes.Include(i => i.Name, i => i.DocumentTemplate, i => i.DocumentTemplateUrl, i => i.Id));
                        cc.ExecuteQueryRetry();

                        foreach (var contentType in list.ContentTypes)
                        {
                            if ((!string.IsNullOrEmpty(contentType.DocumentTemplateUrl) &&
                                 contentType.DocumentTemplateUrl.EndsWith(".xsn", StringComparison.InvariantCultureIgnoreCase)) ||
                                contentType.Id.StringValue.StartsWith(FormBaseContentType))
                            {
                                InfoPathScanResult ctInfoPathScanResult = new InfoPathScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    InfoPathUsage            = "FormLibraryContentType",
                                    ListTitle                = list.Title,
                                    ListId                   = list.Id,
                                    ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                    Enabled                  = true,
                                    InfoPathTemplate         = contentType.DocumentTemplateUrl,
                                    InfoPathTemplateUrl      = this.SiteUrl.TrimEnd('/') + "/_layouts/16/download.aspx?SourceUrl=" + contentType.DocumentTemplateUrl,
                                    ItemCount                = list.ItemCount,
                                    ContentTypeName          = contentType.Name,
                                    LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                                };
                                // Root relative URL for the template
                                var templateFile = cc.Web.GetFileByServerRelativeUrl(contentType.DocumentTemplateUrl);
                                ctInfoPathScanResult = ScrapeXsn(cc, ctInfoPathScanResult, templateFile);
                                if (!this.ScanJob.InfoPathScanResults.TryAdd($"{ctInfoPathScanResult.SiteURL}.{Guid.NewGuid()}", ctInfoPathScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add formlibrary InfoPath scan result for {ctInfoPathScanResult.SiteColUrl} and list {ctInfoPathScanResult.ListUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "InfoPathAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                    else if (list.BaseType == BaseType.GenericList)
                    {
                        try
                        {
                            Folder folder = cc.Web.GetFolderByServerRelativeUrl($"{list.RootFolder.ServerRelativeUrl}/Item");
                            cc.Load(folder, p => p.Properties);
                            cc.ExecuteQueryRetry();

                            if (folder.Properties.FieldValues.ContainsKey("_ipfs_infopathenabled") && folder.Properties.FieldValues.ContainsKey("_ipfs_solutionName"))
                            {
                                bool infoPathEnabled = true;
                                if (bool.TryParse(folder.Properties.FieldValues["_ipfs_infopathenabled"].ToString(), out bool infoPathEnabledParsed))
                                {
                                    infoPathEnabled = infoPathEnabledParsed;
                                }

                                // List with an InfoPath customization
                                InfoPathScanResult infoPathScanResult = new InfoPathScanResult()
                                {
                                    SiteColUrl               = this.SiteCollectionUrl,
                                    SiteURL                  = this.SiteUrl,
                                    InfoPathUsage            = "CustomForm",
                                    ListTitle                = list.Title,
                                    ListId                   = list.Id,
                                    ListUrl                  = list.RootFolder.ServerRelativeUrl,
                                    Enabled                  = infoPathEnabled,
                                    InfoPathTemplate         = folder.Properties.FieldValues["_ipfs_solutionName"].ToString(),
                                    InfoPathTemplateUrl      = this.SiteUrl.TrimEnd('/') + "/_layouts/16/download.aspx?SourceUrl=" + cc.Web.Url.TrimEnd('/') + "/Lists/" + list.RootFolder.Name + "/" + folder.Properties.FieldValues["_ipfs_solutionName"].ToString(),
                                    ItemCount                = list.ItemCount,
                                    LastItemUserModifiedDate = list.LastItemUserModifiedDate,
                                };

                                // Run the scraper
                                var templateFile = list.RootFolder.GetFile($"item/{infoPathScanResult.InfoPathTemplate}");
                                infoPathScanResult = ScrapeXsn(cc, infoPathScanResult, templateFile);

                                if (!this.ScanJob.InfoPathScanResults.TryAdd($"{infoPathScanResult.SiteURL}.{Guid.NewGuid()}", infoPathScanResult))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add customform InfoPath scan result for {infoPathScanResult.SiteColUrl} and list {infoPathScanResult.ListUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "InfoPathAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                        catch (ServerException ex)
                        {
                            if (((ServerException)ex).ServerErrorTypeName == "System.IO.FileNotFoundException")
                            {
                                // Ignore
                            }
                            else
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = ex.Message,
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "InfoPathAnalyzer",
                                    Field2     = ex.StackTrace,
                                    Field3     = $"{webAppUrl}{list.DefaultViewUrl}"
                                };

                                // Send error to telemetry to make scanner better
                                if (this.ScanJob.ScannerTelemetry != null)
                                {
                                    this.ScanJob.ScannerTelemetry.LogScanError(ex, error);
                                }

                                this.ScanJob.ScanErrors.Push(error);
                                Console.WriteLine("Error during InfoPath analysis for list {1}: {0}", ex.Message, $"{webAppUrl}{list.DefaultViewUrl}");
                            }
                        }
                        catch (Exception ex)
                        {
                        }
                    }
                }
            }
            catch (Exception ex)
            {
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
        /// <summary>
        /// Scans a list for "modern" compatibility
        /// </summary>
        /// <param name="file">List form page to start the scan from</param>
        /// <param name="list">List linked to the form page</param>
        /// <returns>Object describing modern compatiblity</returns>
        public static ListScanResult ModernCompatability(this File file, List list, ref ConcurrentStack <ScanError> scanErrors)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            if (list == null)
            {
                throw new ArgumentNullException("list");
            }

            ClientContext cc = file.Context as ClientContext;

            ListScanResult result = new ListScanResult();

            // Load properties
            file.EnsureProperties(p => p.PageRenderType);

            // If it works in modern, we're good
            if (file.PageRenderType == ListPageRenderType.Modern)
            {
                // let's return since we know it will work
                return(result);
            }
            else
            {
                result.PageRenderType = file.PageRenderType;
            }

            // Hmmm...it's not working, so let's list *all* reasons why it's not working in modern

            // Step 1: load the tenant / site / web / list level blocking options
            // Tenant
            // Currently we've no API to detect tenant setting...but since we anyhow should scan all lists this does not matter that much

            // Site
            Site site = cc.Site;

            site.EnsureProperties(p => p.Features, p => p.Url);
            result.BlockedAtSiteLevel = site.Features.Where(f => f.DefinitionId == FeatureId_Site_Modern).Count() > 0;
            // Web
            cc.Web.EnsureProperties(p => p.Features, p => p.Url);
            result.BlockedAtWebLevel = cc.Web.Features.Where(f => f.DefinitionId == FeatureId_Web_Modern).Count() > 0;
            // List
            list.EnsureProperties(p => p.ListExperienceOptions, p => p.UserCustomActions, p => p.BaseTemplate);
            result.ListExperience = list.ListExperienceOptions;
            result.XsltViewWebPartCompatibility.ListBaseTemplate = list.BaseTemplate;

            if (list.ListExperienceOptions == ListExperience.ClassicExperience)
            {
                result.BlockedAtListLevel = true;
            }

            // Step 2: verify we can load a web part manager and ensure there's only one web part of the page
            LimitedWebPartManager wpm;

            try
            {
                wpm = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
                file.Context.Load(wpm.WebParts, wps => wps.Include(wp => wp.WebPart.Title, wp => wp.WebPart.Properties));
                file.Context.ExecuteQueryRetry();
            }
            catch (Exception ex)
            {
                result.BlockedByNotBeingAbleToLoadPage          = true;
                result.BlockedByNotBeingAbleToLoadPageException = ex.ToString();
                return(result);
            }

            if (wpm.WebParts.Count != 1)
            {
                result.BlockedByZeroOrMultipleWebParts = true;
                return(result);
            }

            var webPart = wpm.WebParts[0].WebPart;

            // Step 3: Inspect the web part used to render the list
            // Step 3.1: JSLink web part check
            if (webPart.Properties.FieldValues.Keys.Contains("JSLink"))
            {
                if (webPart.Properties["JSLink"] != null && !String.IsNullOrEmpty(webPart.Properties["JSLink"].ToString()) && webPart.Properties["JSLink"].ToString().ToLower() != "clienttemplates.js")
                {
                    result.XsltViewWebPartCompatibility.BlockedByJSLink = true;
                    result.XsltViewWebPartCompatibility.JSLink          = webPart.Properties["JSLink"].ToString();
                }
            }

            // Step 3.2: XslLink web part check
            if (webPart.Properties.FieldValues.Keys.Contains("XslLink"))
            {
                if (webPart.Properties["XslLink"] != null && !String.IsNullOrEmpty(webPart.Properties["XslLink"].ToString()) && webPart.Properties["XslLink"].ToString().ToLower() != "main.xsl")
                {
                    result.XsltViewWebPartCompatibility.BlockedByXslLink = true;
                    result.XsltViewWebPartCompatibility.XslLink          = webPart.Properties["XslLink"].ToString();
                }
            }

            // Step 3.3: Xsl web part check
            if (webPart.Properties.FieldValues.Keys.Contains("Xsl"))
            {
                if (webPart.Properties["Xsl"] != null && !String.IsNullOrEmpty(webPart.Properties["Xsl"].ToString()))
                {
                    result.XsltViewWebPartCompatibility.BlockedByXsl = true;
                }
            }

            // Step 3.4: Process fields in view
            if (webPart.Properties.FieldValues.Keys.Contains("XmlDefinition"))
            {
                if (webPart.Properties["XmlDefinition"] != null && !String.IsNullOrEmpty(webPart.Properties["XmlDefinition"].ToString()))
                {
                    try
                    {
                        // Get the fields in this view
                        var viewFields = GetViewFields(webPart.Properties["XmlDefinition"].ToString());

                        // Load fields in one go
                        List <Field> fieldsToProcess = new List <Field>(viewFields.Count);
                        try
                        {
                            foreach (var viewField in viewFields)
                            {
                                Field field = list.Fields.GetByInternalNameOrTitle(viewField);
                                cc.Load(field, p => p.JSLink, p => p.TypeAsString, p => p.FieldTypeKind, p => p.InternalName);
                                fieldsToProcess.Add(field);
                            }
                            cc.ExecuteQueryRetry();
                        }
                        catch
                        {
                            // try to load the fields again, but now individually so we can collect the needed errors + evaulate the fields that do load
                            fieldsToProcess.Clear();
                            foreach (var viewField in viewFields)
                            {
                                try
                                {
                                    Field field = list.Fields.GetByInternalNameOrTitle(viewField);
                                    cc.Load(field, p => p.JSLink, p => p.TypeAsString, p => p.FieldTypeKind);
                                    cc.ExecuteQueryRetry();
                                    fieldsToProcess.Add(field);
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteURL    = cc.Web.Url,
                                        SiteColUrl = site.Url
                                    };
                                    scanErrors.Push(error);
                                    Console.WriteLine("Error for site {1}: {0}", ex.Message, cc.Web.Url);
                                }
                            }
                        }

                        // Verify the fields
                        foreach (var field in fieldsToProcess)
                        {
                            try
                            {
                                // JSLink on field
                                if (!string.IsNullOrEmpty(field.JSLink) && field.JSLink != "clienttemplates.js" &&
                                    field.JSLink != "sp.ui.reputation.js" && !field.IsTaxField())
                                {
                                    result.XsltViewWebPartCompatibility.BlockedByJSLinkField = true;
                                    result.XsltViewWebPartCompatibility.JSLinkFields         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.JSLinkFields) ? $"{field.InternalName}" : $"{result.XsltViewWebPartCompatibility.JSLinkFields},{field.InternalName}";
                                }

                                //Business data field
                                if (field.IsBusinessDataField())
                                {
                                    result.XsltViewWebPartCompatibility.BlockedByBusinessDataField = true;
                                    result.XsltViewWebPartCompatibility.BusinessDataFields         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.BusinessDataFields) ? $"{field.InternalName}" : $"{result.XsltViewWebPartCompatibility.BusinessDataFields},{field.InternalName}";
                                }

                                // Geolocation field
                                if (field.FieldTypeKind == FieldType.Geolocation)
                                {
                                    result.XsltViewWebPartCompatibility.BlockedByGeoLocationField = true;
                                    result.XsltViewWebPartCompatibility.GeoLocationFields         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.GeoLocationFields) ? $"{field.InternalName}" : $"{result.XsltViewWebPartCompatibility.GeoLocationFields},{field.InternalName}";
                                }

                                // TaskOutcome field
                                if (field.IsTaskOutcomeField())
                                {
                                    result.XsltViewWebPartCompatibility.BlockedByTaskOutcomeField = true;
                                    result.XsltViewWebPartCompatibility.TaskOutcomeFields         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.TaskOutcomeFields) ? $"{field.InternalName}" : $"{result.XsltViewWebPartCompatibility.TaskOutcomeFields},{field.InternalName}";
                                }

                                // Publishing field
                                if (field.IsPublishingField())
                                {
                                    result.XsltViewWebPartCompatibility.BlockedByPublishingField = true;
                                    result.XsltViewWebPartCompatibility.PublishingFields         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.PublishingFields) ? $"{field.InternalName}" : $"{result.XsltViewWebPartCompatibility.PublishingFields},{field.InternalName}";
                                }
                            }
                            catch (Exception ex)
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = ex.Message,
                                    SiteURL    = cc.Web.Url,
                                    SiteColUrl = site.Url,
                                };
                                scanErrors.Push(error);
                                Console.WriteLine("Error for site {1}: {0}", ex.Message, cc.Web.Url);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = ex.Message,
                            SiteURL    = cc.Web.Url,
                            SiteColUrl = site.Url
                        };
                        scanErrors.Push(error);
                        Console.WriteLine("Error for site {1}: {0}", ex.Message, cc.Web.Url);
                    }
                }
            }

            // Step 3.5: Process list custom actions
            if (list.UserCustomActions.Count > 0)
            {
                foreach (var customAction in list.UserCustomActions)
                {
                    if (!string.IsNullOrEmpty(customAction.Location) && customAction.Location.Equals("scriptlink", StringComparison.InvariantCultureIgnoreCase))
                    {
                        if (!string.IsNullOrEmpty(customAction.ScriptSrc))
                        {
                            result.XsltViewWebPartCompatibility.BlockedByListCustomAction = true;
                            result.XsltViewWebPartCompatibility.ListCustomActions         = string.IsNullOrEmpty(result.XsltViewWebPartCompatibility.ListCustomActions) ? $"{customAction.Name}" : $"{result.XsltViewWebPartCompatibility.ListCustomActions},{customAction.Name}";
                        }
                    }
                }
            }

            // Step 3.6: managed metadata navigation is not an issue anymore
            result.XsltViewWebPartCompatibility.BlockedByManagedMetadataNavFeature = false;

            // Step 4: check the view
            if (webPart.Properties.FieldValues.Keys.Contains("ViewFlags") && webPart.Properties["ViewFlags"] != null && !String.IsNullOrEmpty(webPart.Properties["ViewFlags"].ToString()))
            {
                uint flags;
                if (uint.TryParse(webPart.Properties["ViewFlags"].ToString(), out flags))
                {
                    if ((flags & ViewFlag_Gantt) != 0 || (flags & ViewFlag_Calendar) != 0 || (flags & ViewFlag_Grid) != 0)
                    {
                        result.XsltViewWebPartCompatibility.BlockedByViewType = true;
                        if ((flags & ViewFlag_Gantt) != 0)
                        {
                            result.XsltViewWebPartCompatibility.ViewType = "Gantt";
                        }
                        else if ((flags & ViewFlag_Calendar) != 0)
                        {
                            result.XsltViewWebPartCompatibility.ViewType = "Calendar";
                        }
                        else if ((flags & ViewFlag_Grid) != 0)
                        {
                            if (list.BaseTemplate == (int)ListTemplateType.GenericList ||
                                list.BaseTemplate == (int)ListTemplateType.DocumentLibrary)
                            {
                                // unblock...we've added support for datasheet rendering for custom lists in July 2018 (see https://techcommunity.microsoft.com/t5/Microsoft-SharePoint-Blog/Updates-to-metadata-handling-and-list-templates/ba-p/202113)
                                result.XsltViewWebPartCompatibility.BlockedByViewType = false;
                            }
                            else
                            {
                                result.XsltViewWebPartCompatibility.ViewType = "Grid";
                            }
                        }
                    }
                }
            }

            // Step 5: check the list
            // Step 5.1: check the base template
            if (!list.CanRenderNewExperience())
            {
                result.XsltViewWebPartCompatibility.BlockedByListBaseTemplate = true;
                result.XsltViewWebPartCompatibility.ListBaseTemplate          = list.BaseTemplate;
            }

            return(result);
        }
示例#24
0
 private static void AssertFailScanErrorHandler(ScanError scanError)
 {
     // Note: does not contain stack trace, so no point in wrapping in Exception() at this point.
     throw scanError;
 }
示例#25
0
        /// <summary>
        /// Analyses a page
        /// </summary>
        /// <param name="cc">ClientContext instance used to retrieve page data</param>
        /// <returns>Duration of the page analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);
                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration, p => p.RootFolder);

                var homePageUrl        = web.RootFolder.WelcomePage;
                var listsToScan        = web.GetListsToScan();
                var sitePagesLibraries = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary);

                if (sitePagesLibraries.Count() > 0)
                {
                    foreach (var sitePagesLibrary in sitePagesLibraries)
                    {
                        CamlQuery query = new CamlQuery
                        {
                            ViewXml = CAMLQueryByExtension
                        };
                        var pages = sitePagesLibrary.GetItems(query);
                        web.Context.Load(pages);
                        web.Context.ExecuteQueryRetry();

                        if (pages.FirstOrDefault() != null)
                        {
                            DateTime start;
                            bool     forceCheckout = sitePagesLibrary.ForceCheckout;
                            foreach (var page in pages)
                            {
                                string pageUrl = null;
                                try
                                {
                                    if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
                                    {
                                        pageUrl = page[FileRefField].ToString();
                                    }
                                    else
                                    {
                                        //skip page
                                        continue;
                                    }

                                    start = DateTime.Now;
                                    PageScanResult pageResult = new PageScanResult()
                                    {
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        PageUrl    = pageUrl,
                                        Library    = sitePagesLibrary.RootFolder.ServerRelativeUrl,
                                    };

                                    // Is this page the web's home page?
                                    if (pageUrl.EndsWith(homePageUrl, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        pageResult.HomePage = true;
                                    }

                                    // Get the type of the page
                                    pageResult.PageType = page.PageType();

                                    // Get page web parts
                                    var pageAnalysis = page.WebParts(this.ScanJob.PageTransformation);
                                    if (pageAnalysis != null)
                                    {
                                        pageResult.Layout   = pageAnalysis.Item1.ToString().Replace("Wiki_", "").Replace("WebPart_", "");
                                        pageResult.WebParts = pageAnalysis.Item2;
                                    }

                                    // Get page change information
                                    pageResult.ModifiedAt = page.LastModifiedDateTime();
                                    pageResult.ModifiedBy = page.LastModifiedBy();

                                    // Grab this page from the search results to connect view information
                                    string fullPageUrl = $"https://{new Uri(this.SiteCollectionUrl).DnsSafeHost}{pageUrl}";
                                    if (pageResult.HomePage)
                                    {
                                        fullPageUrl = this.SiteUrl;
                                    }

                                    var searchPage = this.pageSearchResults.Where(x => x.Values.Contains(fullPageUrl)).FirstOrDefault();
                                    if (searchPage != null)
                                    {
                                        // Recent = last 14 days
                                        pageResult.ViewsRecent              = searchPage["ViewsRecent"].ToInt32();
                                        pageResult.ViewsRecentUniqueUsers   = searchPage["ViewsRecentUniqueUsers"].ToInt32();
                                        pageResult.ViewsLifeTime            = searchPage["ViewsLifeTime"].ToInt32();
                                        pageResult.ViewsLifeTimeUniqueUsers = searchPage["ViewsLifeTimeUniqueUsers"].ToInt32();
                                    }

                                    if (!this.ScanJob.PageScanResults.TryAdd(pageResult.PageUrl, pageResult))
                                    {
                                        ScanError error = new ScanError()
                                        {
                                            Error      = $"Could not add page scan result for {pageResult.PageUrl}",
                                            SiteColUrl = this.SiteCollectionUrl,
                                            SiteURL    = this.SiteUrl,
                                            Field1     = "PageAnalyzer",
                                        };
                                        this.ScanJob.ScanErrors.Push(error);
                                    }
                                    var duration = new TimeSpan((DateTime.Now.Subtract(start).Ticks));
                                    Console.WriteLine($"Scan of page {pageUrl} took {duration.Seconds} seconds");
                                }
                                catch (Exception ex)
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = ex.Message,
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "MainPageAnalyzerLoop",
                                        Field2     = ex.StackTrace,
                                        Field3     = pageUrl
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                    Console.WriteLine("Error for page {1}: {0}", ex.Message, pageUrl);
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#26
0
 private void ScanError(ScanError scanError)
 {
     ReportError(scanError.Line, String.Empty, scanError.Message);
 }
示例#27
0
        /// <summary>
        /// Analyze the web
        /// </summary>
        /// <param name="cc">ClientContext of the web to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                // Ensure needed data is loaded
                Web web = cc.Web;
                web.EnsureProperties(p => p.UserCustomActions, p => p.AlternateCssUrl, p => p.CustomMasterUrl, p => p.MasterUrl, p => p.Features, p => p.WebTemplate, p => p.Configuration, p => p.HasUniqueRoleAssignments);

                // Log in Site scan data that the scanned web is a sub site
                if (web.IsSubSite())
                {
                    SiteScanResult siteScanData;
                    if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData))
                    {
                        if (!siteScanData.SubSites)
                        {
                            var clonedSiteScandata = siteScanData.Clone();
                            clonedSiteScandata.SubSites = true;

                            if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WebAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }

                    // Check if we've broken permission inheritance in this site collection
                    if (web.HasUniqueRoleAssignments)
                    {
                        SiteScanResult siteScanData2;
                        if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData2))
                        {
                            if (!siteScanData2.SubSitesWithBrokenPermissionInheritance)
                            {
                                var clonedSiteScandata = siteScanData2.Clone();
                                clonedSiteScandata.SubSitesWithBrokenPermissionInheritance = true;

                                if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData2))
                                {
                                    ScanError error = new ScanError()
                                    {
                                        Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                        SiteColUrl = this.SiteCollectionUrl,
                                        SiteURL    = this.SiteUrl,
                                        Field1     = "WebAnalyzer",
                                    };
                                    this.ScanJob.ScanErrors.Push(error);
                                }
                            }
                        }
                    }
                }

                // Perform specific analysis work
                WebScanResult scanResult = new WebScanResult()
                {
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                };

                // Log used web template
                if (web.WebTemplate != null)
                {
                    scanResult.WebTemplate = $"{web.WebTemplate}#{web.Configuration}";
                }

                // Page feature check: users can disable this to prevent modern page creation
                scanResult.ModernPageWebFeatureDisabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_ModernPage).Count() == 0;
                // List feature check: users can enabled this to prevent modern lists from working
                scanResult.ModernListWebBlockingFeatureEnabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_ModernList).Count() > 0;
                // Publishing web feature enabled
                scanResult.WebPublishingFeatureEnabled = web.Features.Where(f => f.DefinitionId == FeatureId_Web_Publishing).Count() > 0;

                // Site is using the publishing "Pages" library?
                if (scanResult.WebPublishingFeatureEnabled)
                {
                    if (!(scanResult.WebTemplate.Equals("BICENTERSITE#0", StringComparison.InvariantCultureIgnoreCase) ||
                          scanResult.WebTemplate.Equals("BLANKINTERNET#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("SRCHCEN#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("CMSPUBLISHING#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("SRCHCENTERLITE#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("POINTPUBLISHINGHUB#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("POINTPUBLISHINGTOPIC#0", StringComparison.InvariantCulture) ||
                          scanResult.WebTemplate.Equals("ENTERWIKI#0", StringComparison.InvariantCulture)))
                    {
                        var pagesLibrary = web.GetListsToScan().Where(p => p.BaseTemplate == 850).FirstOrDefault();
                        if (pagesLibrary != null)
                        {
                            if (pagesLibrary.ItemCount > 0)
                            {
                                scanResult.PublishingPagesLibraryContainsPages = true;
                            }
                        }
                    }
                }

                // Log permission inheritance details
                if (web.IsSubSite() && web.HasUniqueRoleAssignments)
                {
                    scanResult.BrokenPermissionInheritance = web.HasUniqueRoleAssignments;

                    if (!this.ScanJob.SkipUserInformation)
                    {
                        scanResult.Owners   = web.GetOwners();
                        scanResult.Members  = web.GetMembers();
                        scanResult.Visitors = web.GetVisitors();
                        scanResult.EveryoneClaimsGranted = web.ClaimsHaveRoleAssignment(this.ScanJob.EveryoneClaim, this.ScanJob.EveryoneExceptExternalUsersClaim);
                    }
                }

                // If the web template is STS#0, GROUP#0 or SITEPAGEPUBLISHING#0 then the feature was activated by SPO, other templates never got it
                scanResult.ModernPageFeatureWasEnabledBySPO = false;
                if (scanResult.WebTemplate.Equals("STS#0", StringComparison.InvariantCultureIgnoreCase) ||
                    scanResult.WebTemplate.Equals("STS#3", StringComparison.InvariantCultureIgnoreCase) ||
                    scanResult.WebTemplate.Equals("GROUP#0", StringComparison.InvariantCulture) ||
                    scanResult.WebTemplate.Equals("SITEPAGEPUBLISHING#0", StringComparison.InvariantCulture))
                {
                    // Since we did not enable the feature for all STS#0 sites (sites with publishing active did not get it, nor sites having a large number of webpart/wiki pages) we
                    // check if it should have been turned on by checking for the "site page" content type being added to the site pages library
                    var listsToScan      = web.GetListsToScan();
                    var sitePagesLibrary = listsToScan.Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary).FirstOrDefault();

                    if (sitePagesLibrary != null)
                    {
                        cc.Load(sitePagesLibrary, p => p.ContentTypes.Include(c => c.Id));
                        cc.ExecuteQueryRetry();

                        var sitePageContentTypeFound = sitePagesLibrary.ContentTypes.Where(c => c.Id.StringValue.StartsWith(SitePageContentTypeId, StringComparison.InvariantCultureIgnoreCase)).OrderBy(c => c.Id.StringValue.Length).FirstOrDefault();
                        if (sitePageContentTypeFound != null)
                        {
                            scanResult.ModernPageFeatureWasEnabledBySPO = true;
                        }
                    }
                }


                // Get information about the master pages used
                if (!string.IsNullOrEmpty(web.MasterUrl) && !excludeMasterPage.Contains(web.MasterUrl.Substring(web.MasterUrl.LastIndexOf("/") + 1).ToLower()))
                {
                    scanResult.MasterPage = web.MasterUrl;
                }
                if (!string.IsNullOrEmpty(web.CustomMasterUrl) && !excludeMasterPage.Contains(web.CustomMasterUrl.Substring(web.CustomMasterUrl.LastIndexOf("/") + 1).ToLower()))
                {
                    scanResult.CustomMasterPage = web.CustomMasterUrl;
                }

                if (!string.IsNullOrEmpty(web.AlternateCssUrl))
                {
                    scanResult.AlternateCSS = web.AlternateCssUrl;
                }

                // Get the user custom actions
                scanResult.WebUserCustomActions = web.UserCustomActions.Analyze(this.SiteCollectionUrl, this.SiteUrl);

                // Get home page from the web and check whether it's a modern page or not
                scanResult.ModernHomePage = false;

                var homePageUrl = web.WelcomePage;
                if (string.IsNullOrEmpty(homePageUrl))
                {
                    // Will be case when the site home page is a web part page
                    homePageUrl = "default.aspx";
                }
                var homepageName = System.IO.Path.GetFileName(homePageUrl);

                var sitePagesLibraryForWeb = web.GetListsToScan().Where(p => p.BaseTemplate == (int)ListTemplateType.WebPageLibrary).FirstOrDefault();
                if (sitePagesLibraryForWeb != null && homePageUrl.StartsWith("SitePages", StringComparison.InvariantCultureIgnoreCase))
                {
                    var homePageFile = web.GetFileByServerRelativeUrl($"{(web.ServerRelativeUrl.Length == 1 ? "" : web.ServerRelativeUrl)}/{homePageUrl}");
                    cc.Load(homePageFile, f => f.ListItemAllFields, f => f.Exists);
                    cc.ExecuteQueryRetry();
                    if (homePageFile.Exists)
                    {
                        var item = homePageFile.ListItemAllFields;
                        if (item.FieldValues.ContainsKey(ClientSideApplicationId) && item[ClientSideApplicationId] != null && item[ClientSideApplicationId].ToString().Equals(FeatureId_Web_ModernPage.ToString(), StringComparison.InvariantCultureIgnoreCase))
                        {
                            scanResult.ModernHomePage = true;
                        }
                    }
                }


                // Push information from root web to respective SiteScanResult object
                if (!cc.Web.IsSubSite())
                {
                    SiteScanResult siteScanData;
                    if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out siteScanData))
                    {
                        var clonedSiteScandata = siteScanData.Clone();
                        clonedSiteScandata.WebPublishingFeatureEnabled         = scanResult.WebPublishingFeatureEnabled;
                        clonedSiteScandata.ModernPageWebFeatureDisabled        = scanResult.ModernPageWebFeatureDisabled;
                        clonedSiteScandata.ModernPageFeatureWasEnabledBySPO    = scanResult.ModernPageFeatureWasEnabledBySPO;
                        clonedSiteScandata.ModernListWebBlockingFeatureEnabled = scanResult.ModernListWebBlockingFeatureEnabled;
                        clonedSiteScandata.ModernHomePage       = scanResult.ModernHomePage;
                        clonedSiteScandata.MasterPage           = (!String.IsNullOrEmpty(scanResult.MasterPage) || !String.IsNullOrEmpty(scanResult.CustomMasterPage));
                        clonedSiteScandata.AlternateCSS         = !String.IsNullOrEmpty(scanResult.AlternateCSS);
                        clonedSiteScandata.WebUserCustomActions = scanResult.WebUserCustomActions;

                        if (scanResult.PublishingPagesLibraryContainsPages && clonedSiteScandata.PublishingPagesUsed == false)
                        {
                            clonedSiteScandata.PublishingPagesUsed = true;
                        }

                        if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "WebAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                }
                else
                {
                    if (scanResult.PublishingPagesLibraryContainsPages)
                    {
                        if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out SiteScanResult siteScanData))
                        {
                            var clonedSiteScandata = siteScanData.Clone();

                            if (clonedSiteScandata.PublishingPagesUsed == false)
                            {
                                clonedSiteScandata.PublishingPagesUsed = true;
                            }

                            if (!this.ScanJob.SiteScanResults.TryUpdate(this.SiteCollectionUrl, clonedSiteScandata, siteScanData))
                            {
                                ScanError error = new ScanError()
                                {
                                    Error      = $"Could not add update site scan result for {this.SiteCollectionUrl} from web scan of {this.SiteUrl}",
                                    SiteColUrl = this.SiteCollectionUrl,
                                    SiteURL    = this.SiteUrl,
                                    Field1     = "WebAnalyzer",
                                };
                                this.ScanJob.ScanErrors.Push(error);
                            }
                        }
                    }
                }

                // Persist web results
                if (!this.ScanJob.WebScanResults.TryAdd(this.SiteUrl, scanResult))
                {
                    ScanError error = new ScanError()
                    {
                        Error      = $"Could not add web scan result for {this.SiteUrl}",
                        SiteColUrl = this.SiteCollectionUrl,
                        SiteURL    = this.SiteUrl,
                        Field1     = "WebAnalyzer",
                    };
                    this.ScanJob.ScanErrors.Push(error);
                }

                if (Options.IncludeLists(this.ScanJob.Mode))
                {
                    // Kickoff the list analyzer
                    var listAnalyzer = new ListAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob);
                    listAnalyzer.Analyze(cc);
                }

                if (Options.IncludePage(this.ScanJob.Mode))
                {
                    // Kickoff the page analysing
                    var pageAnalyzer = new PageAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob, this.pageSearchResults);
                    pageAnalyzer.Analyze(cc);
                }

                if (Options.IncludePublishing(this.ScanJob.Mode))
                {
                    // Kickoff publishing analysis
                    PublishingAnalyzer publishingAnalyzer = null;
                    if (this.ScanJob.SiteScanResults.TryGetValue(this.SiteCollectionUrl, out SiteScanResult siteScanData))
                    {
                        publishingAnalyzer = new PublishingAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob, scanResult, siteScanData);
                    }
                    else
                    {
                        publishingAnalyzer = new PublishingAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob, scanResult, null);
                    }

                    // Assign the current masterpage gallery results
                    publishingAnalyzer.MasterPageGalleryCustomization = this.MasterPageGalleryCustomization;
                    // Run the publishing analyzer
                    publishingAnalyzer.Analyze(cc);

                    // Store the masterpage gallery results
                    this.MasterPageGalleryCustomization = publishingAnalyzer.MasterPageGalleryCustomization;
                }

                if (Options.IncludeInfoPath(this.ScanJob.Mode))
                {
                    // Kick off InfoPath analysis
                    var infoPathAnalyzer = new InfoPathAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob);
                    infoPathAnalyzer.Analyze(cc);
                }

                if (Options.IncludeBlog(this.ScanJob.Mode))
                {
                    // Kick off Blog analysis
                    var blogAnalyzer = new BlogAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob);
                    blogAnalyzer.Analyze(cc);
                }

                // Place workflow as last scan as it's reloading the web.Lists with different properties. The GetListsToScan method will not reload and hence cause missing properties otherwise
                if (Options.IncludeWorkflow(this.ScanJob.Mode))
                {
                    // Kick off workflow analysis
                    var workflowAnalyzer = new WorkflowAnalyzer(this.SiteUrl, this.SiteCollectionUrl, this.ScanJob);
                    workflowAnalyzer.Analyze(cc);
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#28
0
        /// <summary>
        /// Analyze the site collection
        /// </summary>
        /// <param name="cc">ClientContext of the site to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);
                Site site = cc.Site;
                site.EnsureProperties(p => p.UserCustomActions, p => p.Features, p => p.Url, p => p.GroupId);
                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration);

                // Perform specific analysis work
                SiteScanResult scanResult = new SiteScanResult()
                {
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                };

                // Persist web template of the root site
                scanResult.WebTemplate = $"{web.WebTemplate}#{web.Configuration}";

                // Get security information for this site
                scanResult.Admins                = web.GetAdmins();
                scanResult.Owners                = web.GetOwners();
                scanResult.Members               = web.GetMembers();
                scanResult.Visitors              = web.GetVisitors();
                scanResult.Office365GroupId      = site.GroupId;
                scanResult.EveryoneClaimsGranted = web.ClaimsHaveRoleAssignment(this.ScanJob.EveryoneClaim, this.ScanJob.EveryoneExceptExternalUsersClaim);

                scanResult.ModernListSiteBlockingFeatureEnabled = site.Features.Where(f => f.DefinitionId == FeatureId_Site_ModernList).Count() > 0;
                scanResult.SitePublishingFeatureEnabled         = site.Features.Where(f => f.DefinitionId == FeatureId_Site_Publishing).Count() > 0;

                // Get site user custom actions
                scanResult.SiteUserCustomActions = site.UserCustomActions.Analyze(this.SiteCollectionUrl, this.SiteUrl);

                // Get site usage information
                List <string> propertiesToRetrieve = new List <string>
                {
                    "ViewsRecent",
                    "ViewsRecentUniqueUsers",
                    "ViewsLifeTime",
                    "ViewsLifeTimeUniqueUsers"
                };

                var results = this.ScanJob.Search(cc.Web, $"path:{this.SiteCollectionUrl} AND contentclass=STS_Site", propertiesToRetrieve);
                if (results != null && results.Count == 1)
                {
                    scanResult.ViewsRecent              = results[0]["ViewsRecent"].ToInt32();
                    scanResult.ViewsRecentUniqueUsers   = results[0]["ViewsRecentUniqueUsers"].ToInt32();
                    scanResult.ViewsLifeTime            = results[0]["ViewsLifeTime"].ToInt32();
                    scanResult.ViewsLifeTimeUniqueUsers = results[0]["ViewsLifeTimeUniqueUsers"].ToInt32();
                }

                try
                {
                    // Get tenant information
                    var siteInformation = this.ScanJob.SPOTenant.GetSitePropertiesByUrl(this.SiteCollectionUrl, true);
                    this.ScanJob.SPOTenant.Context.Load(siteInformation);
                    this.ScanJob.SPOTenant.Context.ExecuteQueryRetry();

                    if (!siteInformation.ServerObjectIsNull())
                    {
                        scanResult.SharingCapabilities = siteInformation.SharingCapability.ToString();
                    }
                }
                // Eat all exceptions for now
                // TODO move to single loop after scanning has been done - post processing
                catch { }

                if (this.ScanJob.Mode == Mode.Full)
                {
                    // Use search to retrieve all view information for the indexed webpart/wiki/clientside pages in this site collection
                    // Need to use search inside this site collection?
                    List <string> propertiesToRetrieveForPage = new List <string>
                    {
                        "OriginalPath",
                        "ViewsRecent",
                        "ViewsRecentUniqueUsers",
                        "ViewsLifeTime",
                        "ViewsLifeTimeUniqueUsers"
                    };

                    this.PageSearchResults = this.ScanJob.Search(cc.Web, $"path:{this.SiteCollectionUrl} AND fileextension=aspx AND (contentclass=STS_ListItem_WebPageLibrary OR contentclass=STS_Site OR contentclass=STS_Web)", propertiesToRetrieveForPage);
                }

                if (!this.ScanJob.SiteScanResults.TryAdd(this.SiteCollectionUrl, scanResult))
                {
                    ScanError error = new ScanError()
                    {
                        Error      = $"Could not add site scan result for {this.SiteUrl}",
                        SiteColUrl = this.SiteCollectionUrl,
                        SiteURL    = this.SiteUrl,
                        Field1     = "SiteAnalyzer",
                    };
                    this.ScanJob.ScanErrors.Push(error);
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#29
0
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);

                // Only scan when it's a valid publishing portal
                var pageCount = ContinueScanning(cc);
                if (pageCount > 0 || pageCount == -1)
                {
                    try
                    {
                        PublishingWebScanResult scanResult = new PublishingWebScanResult()
                        {
                            SiteColUrl     = this.SiteCollectionUrl,
                            SiteURL        = this.SiteUrl,
                            WebRelativeUrl = this.SiteUrl.Replace(this.SiteCollectionUrl, ""),
                            WebTemplate    = this.webScanResult.WebTemplate,
                            BrokenPermissionInheritance = this.webScanResult.BrokenPermissionInheritance,
                            PageCount         = pageCount == -1 ? 0 : pageCount,
                            SiteMasterPage    = this.webScanResult.CustomMasterPage,
                            SystemMasterPage  = this.webScanResult.MasterPage,
                            AlternateCSS      = this.webScanResult.AlternateCSS,
                            Admins            = this.siteScanResult.Admins,
                            Owners            = this.webScanResult.Owners,
                            UserCustomActions = new List <UserCustomActionResult>()
                        };

                        // User custom actions will play a role in complexity calculation
                        if (this.siteScanResult.SiteUserCustomActions != null && this.siteScanResult.SiteUserCustomActions.Count > 0)
                        {
                            scanResult.UserCustomActions.AddRange(this.siteScanResult.SiteUserCustomActions);
                        }
                        if (this.webScanResult.WebUserCustomActions != null && this.webScanResult.WebUserCustomActions.Count > 0)
                        {
                            scanResult.UserCustomActions.AddRange(this.webScanResult.WebUserCustomActions);
                        }

                        Web web = cc.Web;

                        // Load additional web properties
                        web.EnsureProperties(p => p.Language);
                        scanResult.Language = web.Language;

                        // PageLayouts handling
                        var availablePageLayouts = web.GetPropertyBagValueString(AvailablePageLayouts, "");
                        var defaultPageLayout    = web.GetPropertyBagValueString(DefaultPageLayout, "");

                        if (string.IsNullOrEmpty(availablePageLayouts))
                        {
                            scanResult.PageLayoutsConfiguration = "Any";
                        }
                        else if (availablePageLayouts.Equals("__inherit", StringComparison.InvariantCultureIgnoreCase))
                        {
                            scanResult.PageLayoutsConfiguration = "Inherit from parent";
                        }
                        else
                        {
                            scanResult.PageLayoutsConfiguration = "Defined list";

                            // Fill the defined list
                            var element = XElement.Parse(availablePageLayouts);
                            var nodes   = element.Descendants("layout");
                            if (nodes != null && nodes.Count() > 0)
                            {
                                string allowedPageLayouts = "";

                                foreach (var node in nodes)
                                {
                                    allowedPageLayouts = allowedPageLayouts + node.Attribute("url").Value.Replace("_catalogs/masterpage/", "") + ",";
                                }

                                allowedPageLayouts = allowedPageLayouts.TrimEnd(new char[] { ',' });

                                scanResult.AllowedPageLayouts = allowedPageLayouts;
                            }
                        }

                        if (!string.IsNullOrEmpty(defaultPageLayout))
                        {
                            var element = XElement.Parse(defaultPageLayout);
                            scanResult.DefaultPageLayout = element.Attribute("url").Value.Replace("_catalogs/masterpage/", "");
                        }

                        // Navigation
                        var navigationSettings = web.GetNavigationSettings();
                        if (navigationSettings != null)
                        {
                            if (navigationSettings.GlobalNavigation.ManagedNavigation)
                            {
                                scanResult.GlobalNavigationType = "Managed";
                            }
                            else
                            {
                                scanResult.GlobalNavigationType = "Structural";
                                scanResult.GlobalStructuralNavigationMaxCount     = navigationSettings.GlobalNavigation.MaxDynamicItems;
                                scanResult.GlobalStructuralNavigationShowPages    = navigationSettings.GlobalNavigation.ShowPages;
                                scanResult.GlobalStructuralNavigationShowSiblings = navigationSettings.GlobalNavigation.ShowSiblings;
                                scanResult.GlobalStructuralNavigationShowSubSites = navigationSettings.GlobalNavigation.ShowSubsites;
                            }

                            if (navigationSettings.CurrentNavigation.ManagedNavigation)
                            {
                                scanResult.CurrentNavigationType = "Managed";
                            }
                            else
                            {
                                scanResult.CurrentNavigationType = "Structural";
                                scanResult.CurrentStructuralNavigationMaxCount     = navigationSettings.CurrentNavigation.MaxDynamicItems;
                                scanResult.CurrentStructuralNavigationShowPages    = navigationSettings.CurrentNavigation.ShowPages;
                                scanResult.CurrentStructuralNavigationShowSiblings = navigationSettings.CurrentNavigation.ShowSiblings;
                                scanResult.CurrentStructuralNavigationShowSubSites = navigationSettings.CurrentNavigation.ShowSubsites;
                            }

                            if (navigationSettings.GlobalNavigation.ManagedNavigation || navigationSettings.CurrentNavigation.ManagedNavigation)
                            {
                                scanResult.ManagedNavigationAddNewPages        = navigationSettings.AddNewPagesToNavigation;
                                scanResult.ManagedNavigationCreateFriendlyUrls = navigationSettings.CreateFriendlyUrlsForNewPages;

                                // get information about the managed nav term set configuration
                                var managedNavXml = web.GetPropertyBagValueString(WebNavigationSettings, "");

                                if (!string.IsNullOrEmpty(managedNavXml))
                                {
                                    var managedNavSettings          = XElement.Parse(managedNavXml);
                                    IEnumerable <XElement> navNodes = managedNavSettings.XPathSelectElements("./SiteMapProviderSettings/TaxonomySiteMapProviderSettings");
                                    foreach (var node in navNodes)
                                    {
                                        if (node.Attribute("Name").Value.Equals("CurrentNavigationTaxonomyProvider", StringComparison.InvariantCulture))
                                        {
                                            if (node.Attribute("TermSetId") != null)
                                            {
                                                scanResult.CurrentManagedNavigationTermSetId = node.Attribute("TermSetId").Value;
                                            }
                                            else if (node.Attribute("UseParentSiteMap") != null)
                                            {
                                                scanResult.CurrentManagedNavigationTermSetId = "Inherit from parent";
                                            }
                                        }
                                        else if (node.Attribute("Name").Value.Equals("GlobalNavigationTaxonomyProvider", StringComparison.InvariantCulture))
                                        {
                                            if (node.Attribute("TermSetId") != null)
                                            {
                                                scanResult.GlobalManagedNavigationTermSetId = node.Attribute("TermSetId").Value;
                                            }
                                            else if (node.Attribute("UseParentSiteMap") != null)
                                            {
                                                scanResult.GlobalManagedNavigationTermSetId = "Inherit from parent";
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        // Pages library
                        var pagesLibrary = web.GetListsToScan().Where(p => p.BaseTemplate == 850).FirstOrDefault();
                        if (pagesLibrary != null)
                        {
                            pagesLibrary.EnsureProperties(p => p.EnableModeration, p => p.EnableVersioning, p => p.EnableMinorVersions, p => p.EventReceivers, p => p.Fields, p => p.DefaultContentApprovalWorkflowId);
                            scanResult.LibraryEnableModeration        = pagesLibrary.EnableModeration;
                            scanResult.LibraryEnableVersioning        = pagesLibrary.EnableVersioning;
                            scanResult.LibraryEnableMinorVersions     = pagesLibrary.EnableMinorVersions;
                            scanResult.LibraryItemScheduling          = pagesLibrary.ItemSchedulingEnabled();
                            scanResult.LibraryApprovalWorkflowDefined = pagesLibrary.DefaultContentApprovalWorkflowId != Guid.Empty;
                        }

                        // Variations
                        if (scanResult.Level == 0)
                        {
                            var variationLabels = cc.GetVariationLabels();

                            string labels      = "";
                            string sourceLabel = "";
                            foreach (var label in variationLabels)
                            {
                                labels = labels + $"{label.Title} ({label.Language}),";

                                if (label.IsSource)
                                {
                                    sourceLabel = label.Title;
                                }
                            }

                            scanResult.VariationLabels      = labels.TrimEnd(new char[] { ',' });;
                            scanResult.VariationSourceLabel = sourceLabel;
                        }

                        // Scan pages inside the pages library
                        if (pagesLibrary != null && Options.IncludePublishingWithPages(this.ScanJob.Mode))
                        {
                            CamlQuery query = new CamlQuery
                            {
                                ViewXml = CAMLQueryByExtension,
                            };

                            var pages = pagesLibrary.GetItems(query);

                            // Load additional page related information
                            IEnumerable <ListItem> enumerable = web.Context.LoadQuery(pages.IncludeWithDefaultProperties((ListItem item) => item.ContentType));
                            web.Context.ExecuteQueryRetry();

                            if (enumerable.FirstOrDefault() != null)
                            {
                                foreach (var page in enumerable)
                                {
                                    string pageUrl = null;
                                    try
                                    {
                                        if (page.FieldValues.ContainsKey(FileRefField) && !String.IsNullOrEmpty(page[FileRefField].ToString()))
                                        {
                                            pageUrl = page[FileRefField].ToString();
                                        }
                                        else
                                        {
                                            //skip page
                                            continue;
                                        }

                                        // Basic information about the page
                                        PublishingPageScanResult pageScanResult = new PublishingPageScanResult()
                                        {
                                            SiteColUrl      = this.SiteCollectionUrl,
                                            SiteURL         = this.SiteUrl,
                                            WebRelativeUrl  = scanResult.WebRelativeUrl,
                                            PageRelativeUrl = scanResult.WebRelativeUrl.Length > 0 ? pageUrl.Replace(scanResult.WebRelativeUrl, "") : pageUrl,
                                        };

                                        // Page name
                                        if (page.FieldValues.ContainsKey(FileLeafRefField) && !String.IsNullOrEmpty(page[FileLeafRefField].ToString()))
                                        {
                                            pageScanResult.PageName = page[FileLeafRefField].ToString();
                                        }

                                        // Get page change information
                                        pageScanResult.ModifiedAt = page.LastModifiedDateTime();
                                        if (!this.ScanJob.SkipUserInformation)
                                        {
                                            pageScanResult.ModifiedBy = page.LastModifiedBy();
                                        }

                                        // Page layout
                                        pageScanResult.PageLayout     = page.PageLayout();
                                        pageScanResult.PageLayoutFile = page.PageLayoutFile().Replace(pageScanResult.SiteColUrl, "").Replace("/_catalogs/masterpage/", "");

                                        // Customization status
                                        if (this.MasterPageGalleryCustomization == null)
                                        {
                                            this.MasterPageGalleryCustomization = new Dictionary <string, CustomizedPageStatus>();
                                        }

                                        // Load the file to check the customization status, only do this if the file was not loaded before for this site collection
                                        Uri uri = new Uri(page.PageLayoutFile());
                                        var url = page.PageLayoutFile().Replace($"{uri.Scheme}://{uri.DnsSafeHost}".ToLower(), "");
                                        if (!this.MasterPageGalleryCustomization.ContainsKey(url))
                                        {
                                            try
                                            {
                                                var publishingPageLayout = cc.Site.RootWeb.GetFileByServerRelativeUrl(url);
                                                cc.Load(publishingPageLayout);
                                                cc.ExecuteQueryRetry();

                                                this.MasterPageGalleryCustomization.Add(url, publishingPageLayout.CustomizedPageStatus);
                                            }
                                            catch (Exception ex)
                                            {
                                                // eat potential exceptions
                                            }
                                        }

                                        // store the page layout customization status
                                        if (this.MasterPageGalleryCustomization.TryGetValue(url, out CustomizedPageStatus pageStatus))
                                        {
                                            if (pageStatus == CustomizedPageStatus.Uncustomized)
                                            {
                                                pageScanResult.PageLayoutWasCustomized = false;
                                            }
                                            else
                                            {
                                                pageScanResult.PageLayoutWasCustomized = true;
                                            }
                                        }
                                        else
                                        {
                                            // If the file was not loaded for some reason then assume it was customized
                                            pageScanResult.PageLayoutWasCustomized = true;
                                        }

                                        // Page audiences
                                        var audiences = page.Audiences();
                                        if (audiences != null)
                                        {
                                            pageScanResult.GlobalAudiences          = audiences.GlobalAudiences;
                                            pageScanResult.SecurityGroupAudiences   = audiences.SecurityGroups;
                                            pageScanResult.SharePointGroupAudiences = audiences.SharePointGroups;
                                        }

                                        // Contenttype
                                        pageScanResult.ContentType   = page.ContentType.Name;
                                        pageScanResult.ContentTypeId = page.ContentType.Id.StringValue;

                                        // Get page web parts
                                        var pageAnalysis = page.WebParts(this.ScanJob.PageTransformation);
                                        if (pageAnalysis != null)
                                        {
                                            pageScanResult.WebParts = pageAnalysis.Item2;
                                        }

                                        // Persist publishing page scan results
                                        if (!this.ScanJob.PublishingPageScanResults.TryAdd(pageUrl, pageScanResult))
                                        {
                                            ScanError error = new ScanError()
                                            {
                                                Error      = $"Could not add publishing page scan result for {pageScanResult.PageRelativeUrl}",
                                                SiteColUrl = this.SiteCollectionUrl,
                                                SiteURL    = this.SiteUrl,
                                                Field1     = "PublishingAnalyzer",
                                                Field2     = pageScanResult.PageRelativeUrl,
                                            };
                                            this.ScanJob.ScanErrors.Push(error);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        ScanError error = new ScanError()
                                        {
                                            Error      = ex.Message,
                                            SiteColUrl = this.SiteCollectionUrl,
                                            SiteURL    = this.SiteUrl,
                                            Field1     = "MainPublishingPageAnalyzerLoop",
                                            Field2     = ex.StackTrace,
                                            Field3     = pageUrl
                                        };
                                        this.ScanJob.ScanErrors.Push(error);
                                        Console.WriteLine("Error for page {1}: {0}", ex.Message, pageUrl);
                                    }
                                }
                            }
                        }

                        // Persist publishing scan results
                        if (!this.ScanJob.PublishingWebScanResults.TryAdd(this.SiteUrl, scanResult))
                        {
                            ScanError error = new ScanError()
                            {
                                Error      = $"Could not add publishing scan result for {this.SiteUrl}",
                                SiteColUrl = this.SiteCollectionUrl,
                                SiteURL    = this.SiteUrl,
                                Field1     = "PublishingAnalyzer",
                            };
                            this.ScanJob.ScanErrors.Push(error);
                        }
                    }
                    catch (Exception ex)
                    {
                        ScanError error = new ScanError()
                        {
                            Error      = ex.Message,
                            SiteColUrl = this.SiteCollectionUrl,
                            SiteURL    = this.SiteUrl,
                            Field1     = "MainPublishingAnalyzerLoop",
                            Field2     = ex.StackTrace,
                        };
                        this.ScanJob.ScanErrors.Push(error);
                        Console.WriteLine("Error for web {1}: {0}", ex.Message, this.SiteUrl);
                    }
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }
示例#30
0
        /// <summary>
        /// Analyze the site collection
        /// </summary>
        /// <param name="cc">ClientContext of the site to be analyzed</param>
        /// <returns>Duration of the analysis</returns>
        public override TimeSpan Analyze(ClientContext cc)
        {
            try
            {
                base.Analyze(cc);
                Site site = cc.Site;
                site.EnsureProperties(p => p.UserCustomActions, p => p.Features, p => p.Url, p => p.GroupId, p => p.Id);
                Web web = cc.Web;
                cc.Web.EnsureProperties(p => p.WebTemplate, p => p.Configuration);

                if (cc.Web.WebTemplate.Equals("TEAMCHANNEL", StringComparison.InvariantCultureIgnoreCase))
                {
                    return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
                }

                SiteScanResult scanResult = new SiteScanResult()
                {
                    SiteColUrl = this.SiteCollectionUrl,
                    SiteURL    = this.SiteUrl,
                    SiteId     = site.Id.ToString(),
                };

                // Perform specific analysis work

                // Persist web template of the root site
                scanResult.WebTemplate = $"{web.WebTemplate}#{web.Configuration}";

                // Is this the root site collection of the tenant
                scanResult.IsRootSite = new Uri(this.SiteCollectionUrl).PathAndQuery.Equals("/");

                // Is this site group connected
                scanResult.Office365GroupId = site.GroupId;

                if (site.GroupId != Guid.Empty)
                {
                    if (this.ScanJob.TeamifiedSiteCollectionsLoaded)
                    {
                        if (this.ScanJob.TeamifiedSiteCollections.Contains(site.GroupId))
                        {
                            scanResult.HasTeamsTeam = true;
                        }
                        else
                        {
                            scanResult.HasTeamsTeam = false;
                        }
                    }
                    else
                    {
                        // we did not have the needed permissions to load the groups, hence leave the nullable bool null
                    }
                }
                else
                {
                    // We're sure there's no team as there's no group
                    scanResult.HasTeamsTeam = false;
                }

                // Search for site scoped search center url
                if (web.AllProperties.FieldValues.ContainsKey("SRCH_ENH_FTR_URL_SITE"))
                {
                    scanResult.SearchCenterUrl = web.AllProperties.FieldValues["SRCH_ENH_FTR_URL_SITE"] as string;
                }
                else if (web.AllProperties.FieldValues.ContainsKey("SRCH_ENH_FTR_URL_WEB"))
                {
                    scanResult.SearchCenterUrl = web.AllProperties.FieldValues["SRCH_ENH_FTR_URL_WEB"] as string;
                }

                // If no search site override check for a search results page override
                if (string.IsNullOrEmpty(scanResult.SearchCenterUrl))
                {
                    CheckForCustomSearchExperience(web, scanResult, "SRCH_SB_SET_SITE");
                    if (string.IsNullOrEmpty(scanResult.SearchCenterUrl))
                    {
                        CheckForCustomSearchExperience(web, scanResult, "SRCH_SB_SET_WEB");
                    }
                }

                // Get security information for this site
                if (!this.ScanJob.SkipUserInformation)
                {
                    scanResult.Admins   = web.GetAdmins();
                    scanResult.Owners   = web.GetOwners();
                    scanResult.Members  = web.GetMembers();
                    scanResult.Visitors = web.GetVisitors();
                    scanResult.EveryoneClaimsGranted = web.ClaimsHaveRoleAssignment(this.ScanJob.EveryoneClaim, this.ScanJob.EveryoneExceptExternalUsersClaim);
                }

                scanResult.ModernListSiteBlockingFeatureEnabled = site.Features.Where(f => f.DefinitionId == FeatureId_Site_ModernList).Count() > 0;
                scanResult.SitePublishingFeatureEnabled         = site.Features.Where(f => f.DefinitionId == FeatureId_Site_Publishing).Count() > 0;

                // Get site user custom actions
                scanResult.SiteUserCustomActions = site.UserCustomActions.Analyze(this.SiteCollectionUrl, this.SiteUrl);

                if (!this.ScanJob.SkipUsageInformation)
                {
                    // Get site usage information
                    List <string> propertiesToRetrieve = new List <string>
                    {
                        "ViewsRecent",
                        "ViewsRecentUniqueUsers",
                        "ViewsLifeTime",
                        "ViewsLifeTimeUniqueUsers"
                    };

                    var results = this.ScanJob.Search(cc.Web, $"path:{this.SiteCollectionUrl} AND contentclass=STS_Site", propertiesToRetrieve);
                    if (results != null && results.Count == 1)
                    {
                        scanResult.ViewsRecent              = results[0]["ViewsRecent"].ToInt32();
                        scanResult.ViewsRecentUniqueUsers   = results[0]["ViewsRecentUniqueUsers"].ToInt32();
                        scanResult.ViewsLifeTime            = results[0]["ViewsLifeTime"].ToInt32();
                        scanResult.ViewsLifeTimeUniqueUsers = results[0]["ViewsLifeTimeUniqueUsers"].ToInt32();
                    }
                }

                if (!this.ScanJob.AppOnlyHasFullControl)
                {
                    var siteInfo = this.ScanJob.AppOnlyManager.SiteInformation.Where(p => p.SiteUrl.Equals(this.SiteCollectionUrl, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
                    if (siteInfo != null && siteInfo.ExternalSharing.HasValue)
                    {
                        if (!siteInfo.ExternalSharing.Value)
                        {
                            scanResult.SharingCapabilities = "Disabled";
                        }
                        else
                        {
                            if (siteInfo.AllowGuestUserSignIn.HasValue && !siteInfo.AllowGuestUserSignIn.Value)
                            {
                                scanResult.SharingCapabilities = "ExternalUserAndGuestSharing";
                            }
                            else
                            {
                                scanResult.SharingCapabilities = "ExternalUserSharingOnly";
                            }
                        }
                    }
                    else
                    {
                        scanResult.SharingCapabilities = "Unknown";
                    }
                }
                else
                {
                    try
                    {
                        // Get tenant information
                        var siteInformation = this.ScanJob.SPOTenant.GetSitePropertiesByUrl(this.SiteCollectionUrl, true);
                        this.ScanJob.SPOTenant.Context.Load(siteInformation);
                        this.ScanJob.SPOTenant.Context.ExecuteQueryRetry();

                        if (!siteInformation.ServerObjectIsNull())
                        {
                            scanResult.SharingCapabilities = siteInformation.SharingCapability.ToString();
                        }
                    }
                    // Eat all exceptions for now
                    // TODO move to single loop after scanning has been done - post processing
                    catch { }
                }

                if (Options.IncludePage(this.ScanJob.Mode))
                {
                    // Use search to retrieve all view information for the indexed webpart/wiki/clientside pages in this site collection
                    // Need to use search inside this site collection?
                    List <string> propertiesToRetrieveForPage = new List <string>
                    {
                        "OriginalPath",
                        "ViewsRecent",
                        "ViewsRecentUniqueUsers",
                        "ViewsLifeTime",
                        "ViewsLifeTimeUniqueUsers"
                    };

                    if (new Uri(this.SiteCollectionUrl).PathAndQuery == "/")
                    {
                        this.PageSearchResults = this.ScanJob.Search(cc.Web, $"path={this.SiteCollectionUrl} AND fileextension=aspx AND (contentclass=STS_ListItem_WebPageLibrary OR contentclass=STS_Site OR contentclass=STS_Web)", propertiesToRetrieveForPage);
                    }
                    else
                    {
                        this.PageSearchResults = this.ScanJob.Search(cc.Web, $"path:{this.SiteCollectionUrl} AND fileextension=aspx AND (contentclass=STS_ListItem_WebPageLibrary OR contentclass=STS_Site OR contentclass=STS_Web)", propertiesToRetrieveForPage);
                    }
                }

                if (!this.ScanJob.SiteScanResults.TryAdd(this.SiteCollectionUrl, scanResult))
                {
                    ScanError error = new ScanError()
                    {
                        Error      = $"Could not add site scan result for {this.SiteUrl}",
                        SiteColUrl = this.SiteCollectionUrl,
                        SiteURL    = this.SiteUrl,
                        Field1     = "SiteAnalyzer",
                    };
                    this.ScanJob.ScanErrors.Push(error);
                }
            }
            finally
            {
                this.StopTime = DateTime.Now;
            }

            // return the duration of this scan
            return(new TimeSpan((this.StopTime.Subtract(this.StartTime).Ticks)));
        }