Import-Function Get-CurrentSxaVersion
Import-Function Get-TenantItem
Class ValidationStep {
[String]$Title
[String]$Description
[System.Object]$Script
[System.Object]$Version
[ID[]]$Dependency
[ValidationResult]$ValidationResult
}
enum Result {
OK;
Error;
Warning
}
class ValidationResult {
[Result]$Result
[System.String]$Message
}
function Test-ValidVersion {
param (
[ValidationStep]$Step
)
$current = Get-CurrentSxaVersion
$from = $Step.Version.From
$to = $Step.Version.To
$from -le $current -and ($to -eq "*" -or $to -ge $current)
}
function Test-Dependency {
param (
[ValidationStep]$Step,
[Sitecore.Data.Fields.MultilistField]$SitesModulesField,
[Sitecore.Data.Fields.MultilistField]$TenantModulesField
)
$unresolved = $Step.Dependency | ? { $_ -ne $null } | ? {
$SitesModulesField.Contains($_) -eq $false -and $TenantModulesField.Contains($_) -eq $false
}
if ($unresolved.Count -eq 0) {
$true
}
else {
Write-Host "Skipping step: $($Step.Title) due to lack of required dependencies" -ForegroundColor Gray
$false
}
}
function Test-BrokenLink {
param (
[Sitecore.Data.Items.Item]$Item,
[Sitecore.Data.ID]$FieldID
)
[ValidationResult]$result = New-Object ValidationResult
$result.Result = [Result]::OK
[Sitecore.Data.Fields.ReferenceField]$field = $Item.Fields[$FieldID]
if ($field.Value -ne $null -and $field.TargetItem -eq $null) {
$result.Message = "Could not find an item with id: $($field.Value)"
$result.Result = [Result]::Error
}
return $result
}
function New-ResultObject {
param ()
[ValidationResult]$result = New-Object ValidationResult
$result.Result = [Result]::OK
$result.Message = ""
$result
}
$steps =
@{
Title = "SXA Best practices - limit the number of renderings on a page";
Description = "Checks whether there are pages with more than 30 renderings";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[ValidationResult]$result = New-ResultObject
function Get-PresentationDetails($Item) {
Write-Verbose "Cmdlet Get-PresentationDetails - Process"
$layoutFieldValue = $Item.Fields[[Sitecore.FieldIDs]::LayoutField].Value
$finalLayoutFieldValue = $Item.Fields[[Sitecore.FieldIDs]::FinalLayoutField].Value
[Sitecore.Data.Fields.XmlDeltas]::ApplyDelta($layoutFieldValue, $finalLayoutFieldValue)
}
function Test-ExceededRenderingsLimit($pageItem) {
$presentation = Get-PresentationDetails $pageItem
$definition = [Sitecore.Layouts.LayoutDefinition]::Parse($presentation)
$d = $definition.Devices | ? {
$_.Renderings.Count -gt 30
}
$d.Count -gt 0
}
$pages = $SiteItem.Axes.GetDescendants() | `
? { [Sitecore.Data.Managers.TemplateManager]::GetTemplate($_).InheritsFrom([Sitecore.XA.Foundation.Multisite.Templates+Page]::ID) } | `
? { Test-ExceededRenderingsLimit $_ }
if ($pages.Count -gt 0) {
$result.Result = [Result]::Warning
$result.Message = "Do not use too many renderings on a page; we recommend absolutely no more than 30. Having too many editable renderings on a single page can slow down the Experience EditorAffected pages:"
$pages | % {
$id = $_.ID
$name = $_.Name
$result.Message += ", $name"
}
}
return $result
}
},
@{
Title = "SXA Best practices - media under virtual media folder";
Description = "Checks whether there are media items stored directly under virtual media folder";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SiteMediaItem
[ValidationResult]$result = New-ResultObject
$mediaVirtualFolder = Get-SiteMediaItem $SiteItem
$mediaItems = $mediaVirtualFolder.Children | ? {
[Sitecore.Data.Managers.TemplateManager]::GetTemplate($_).InheritsFrom([Sitecore.TemplateIDs]::UnversionedFile) -or [Sitecore.Data.Managers.TemplateManager]::GetTemplate($_).InheritsFrom([Sitecore.TemplateIDs]::VersionedFile)
}
if ($mediaItems.Count -gt 0) {
$result.Result = [Result]::Error
$result.Message = "Do not store media items under Virtual Media Folder"
}
return $result
}
},
@{
Title = "Field 'SiteMediaLibrary'";
Description = "Checks whether 'SiteMediaLibrary' field contains proper reference to a site specific media library item";
Version = @{
From = 1400;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Multisite.Templates+Site+Fields]::SiteMediaLibrary
$temp = Test-BrokenLink $SiteItem $id
if ($temp.Result -eq [Result]::Error) {
return $temp
}
[ValidationResult]$result = New-ResultObject
return $result
}
},
@{
Title = "Field 'ThemesFolder'";
Description = "Checks whether 'ThemesFolder' field contains proper reference to a site specific themes folder item";
Version = @{
From = 1400;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Multisite.Templates+Site+Fields]::ThemesFolder
$temp = Test-BrokenLink $SiteItem $id
if ($temp.Result -eq [Result]::Error) {
return $temp
}
[ValidationResult]$result = New-ResultObject
return $result
}
},
@{
Title = "Field 'AdditionalChildren'";
Description = "Checks whether 'AdditionalChildren' field contains proper reference to a tenant shared media library folder and there are no broken links";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SiteMediaItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Multisite.Templates+Media+Fields]::AdditionalChildren
$siteMediaItem = Get-SiteMediaItem $SiteItem
[Sitecore.Data.Fields.MultilistField]$field = $siteMediaItem.Fields[$id]
$items = $field.GetItems()
if ($items.Count -ne $field.TargetIDs.Count) {
$result.Result = [Result]::Error
$missingIDs = $field.TargetIDs | ? { $items.ID.Contains($_) -eq $false }
$result.Message = "Could not find items with id: $($missingIDs -join ',')"
return $result
}
return $result
}
},
@{
Title = "Field 'Styles Optimizing Enabled'";
Description = "Checks 'Styles Optimizing Enabled' field to determine if styles optimization is disabled";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-PageDesignsItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Theming.Templates+_Optimizable+Fields]::StylesOptimisingEnabled
[Sitecore.Data.Items.Item]$pageDesignItem = Get-PageDesignsItem $SiteItem
$fieldValue = $pageDesignItem.Fields[$id].Value
$state = [Sitecore.MainUtil]::GetTristate($fieldValue, [Sitecore.Tristate]::Undefined)
if ($state -eq [Sitecore.Tristate]::False) {
$result.Result = [Result]::Warning
$result.Message = "Styles optimization for yor site is explicitly disabled. This may cause performance problems. You should enable assests optimization on production"
return $result
}
return $result
}
},
@{
Title = "Field 'Scripts Optimizing Enabled'";
Description = "Checks 'Scripts Optimizing Enabled' field to determine if scripts optimization is disabled";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-PageDesignsItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Theming.Templates+_Optimizable+Fields]::ScriptsOptimisingEnabled
[Sitecore.Data.Items.Item]$pageDesignItem = Get-PageDesignsItem $SiteItem
$fieldValue = $pageDesignItem.Fields[$id].Value
$state = [Sitecore.MainUtil]::GetTristate($fieldValue, [Sitecore.Tristate]::Undefined)
if ($state -eq [Sitecore.Tristate]::False) {
$result.Result = [Result]::Warning
$result.Message = "Scripts optimization for yor site is explicitly disabled. This may cause performance problems. You should enable assests optimization on production"
return $result
}
return $result
}
},
@{
Title = "Theme for Default device";
Description = "Checks whether any theme is assigned to a default device";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$defaultDeviceID = "{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}"
$deviceItem = Get-Item master: -ID $defaultDeviceID
$theme = [Sitecore.XA.Foundation.Theming.ThemingContext]::new().GetThemeItem($siteItem, $deviceItem)
if ($theme -eq $null) {
$result.Result = [Result]::Error
$result.Message = "There is no theme assigned to the Default device"
return $result
}
return $result
}
},
@{
Title = "Theme and Compatible Themes field consistency";
Description = "Checks whether themes used in Theme-to-Device mapping are compatible with current site";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-PageDesignsItem
Import-Function Get-SettingsItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$themesMappingFieldID = [Sitecore.XA.Foundation.Theming.Templates+SiteTheme+Fields]::Theme
[Sitecore.Data.ID]$compatibleThemesFieldIdD = [Sitecore.XA.Foundation.Theming.Templates+_Compatiblethemes+Fields]::Themes
[Sitecore.Data.Items.Item]$pageDesignItem = Get-PageDesignsItem $SiteItem
[Sitecore.Data.Items.Item]$settingsItem = Get-SettingsItem $SiteItem
[Sitecore.XA.Foundation.SitecoreExtensions.CustomFields.MappingField]$themesMappingFields = $pageDesignItem.Fields[$themesMappingFieldID]
[Sitecore.Data.Fields.MultilistField]$compatibleThemesField = $settingsItem.Fields[$compatibleThemesFieldIdD]
$incorrectDeviceMapping = $themesMappingFields.Keys | % { $_.ToString() } | ? {
$key = $_
$theme = $themesMappingFields.Lookup($key)
$compatibleThemesField.Items.Contains($theme.ID.ToString()) -eq $false
}
if ($incorrectDeviceMapping.Count -gt 0) {
$result.Result = [Result]::Error
$result.Message = "Some themes used for mapping are not compatible with current site. Please check themes mapping for following devices: $($incorrectDeviceMapping -join ',')"
return $result
}
return $result
}
},
@{
Title = "Site definitions conflicts";
Description = "Checks whether current site definitions have any conflicts with other sites";
Version = @{
From = 1500;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SettingsItem
Import-Function Get-SxaSiteDefinitions
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.Items.Item]$settingsItem = Get-SettingsItem $SiteItem
$siteDefinitions = $settingsItem.Axes.GetDescendants() | ? { $_.TemplateID -eq "{EDA823FC-BC7E-4EF6-B498-CD09EC6FDAEF}" } | Wrap-Item | % { $_."SiteName" }
$sites = Get-SxaSiteDefinitions | ? { $siteDefinitions.Contains($_.Name) } | ? { $_.State -eq "Conflict" }
if ($sites.Count -gt 0) {
$result.Result = [Result]::Error
$result.Message = $sites[0].Conflict
return $result
}
return $result
}
},
@{
Title = "Error Handling - 404";
Description = "Checks whether current site has 404 page configured";
Version = @{
From = 1000;
To = "*";
};
Dependency = @("{8F9355F1-F6AC-49A1-8465-0B905E3E8CAF}");
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SettingsItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$id = [Sitecore.XA.Feature.ErrorHandling.Templates+_ErrorHandling+Fields]::Error404Page
[Sitecore.Data.Items.Item]$settingsItem = Get-SettingsItem $SiteItem
[Sitecore.Data.Fields.InternalLinkField]$field = $settingsItem.Fields[$id]
if ($field.TargetItem -eq $null) {
$result.Result = [Result]::Warning
$result.Message = "Error page for 404 code (Page Not Found) is not configured"
return $result
}
return $result
}
},
@{
Title = "Site name";
Description = "Validates site name. Site names cannot contain control characters, spaces (' ') semicolons, or commas";
Version = @{
From = 1000;
To = "*";
};
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SettingsItem
Import-Function Get-SxaSiteDefinitions
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.Items.Item]$settingsItem = Get-SettingsItem $SiteItem
$siteDefinitions = $settingsItem.Axes.GetDescendants() | ? { $_.TemplateID -eq "{EDA823FC-BC7E-4EF6-B498-CD09EC6FDAEF}" } | Wrap-Item
$current = Get-CurrentSxaVersion
if ($current -ge 1500) {
$siteNames = $siteDefinitions | % { $_."SiteName" }
}
else {
$siteNames = $siteDefinitions | % { $_.Name }
}
[string[]]$invaludNames = $siteNames | ? {
[regex]::Match($_, "^[a-zA-z0-9]*$").Success -eq $false
}
if ($invaludNames.Count -gt 0) {
$result.Result = [Result]::Error
$invaludNames = $invaludNames | % { "'$($_)'" }
$result.Message = "There are site definition items with incorrect site names: $($invaludNames -join ', ')"
return $result
}
return $result
}
},
@{
Title = "Error Handling - 500";
Description = "Checks whether current site has 500 page configured";
Version = @{
From = 1000;
To = "*";
};
Dependency = @("{8F9355F1-F6AC-49A1-8465-0B905E3E8CAF}");
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
Import-Function Get-SettingsItem
[ValidationResult]$result = New-ResultObject
[Sitecore.Data.ID]$id = [Sitecore.XA.Feature.ErrorHandling.Templates+_ErrorHandling+Fields]::Error500Page
[Sitecore.Data.Items.Item]$settingsItem = Get-SettingsItem $SiteItem
[Sitecore.Data.Fields.InternalLinkField]$field = $settingsItem.Fields[$id]
if ($field.TargetItem -eq $null) {
$result.Result = [Result]::Warning
$result.Message = "Error page for 500 code (Server Error Page) is not configured"
return $result
}
$sitesWithoutStaticHTML = $settingsItem.Axes.GetDescendants() | `
? { $_.TemplateID -eq "{EDA823FC-BC7E-4EF6-B498-CD09EC6FDAEF}" } | Wrap-Item | `
% { $_."SiteName" } | `
? { (Test-Path ([Sitecore.IO.FileUtil]::MapPath("/ErrorPages/$($_).html"))) -eq $false }
if ($sitesWithoutStaticHTML.Count -gt 0) {
$result.Result = [Result]::Error
$result.Message = "There are sites without static HTML error page: $($sitesWithoutStaticHTML -join ', ')"
return $result
}
return $result
}
},
@{
Title = "Maps Provider key";
Description = "If there is any use of Maps rendering, it checks whether maps provider key has been configured";
Version = @{
From = 1000;
To = "*";
};
Dependency = @("{4EE33975-DB00-455E-9F9C-2CB78C892C79}");
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[ValidationResult]$result = New-ResultObject
$mapsRenderingID = "{4DD74227-4504-4102-A802-76241F372B9E}"
$rendering = $SiteItem.Database.GetItem($mapsRenderingID)
$siteLongID = $SiteItem.Paths.LongID
$mapsRenderingUsages = [Sitecore.Globals]::LinkDatabase.GetItemReferrers($rendering, $false) | `
? { ($_.SourceFieldID -eq [Sitecore.FieldIDs]::LayoutField) -or ($_.SourceFieldID -eq [Sitecore.FieldIDs]::FinalLayoutField) } | `
? { $_.TargetDatabaseName -eq $rendering.Database.Name } | `
% { $rendering.Database.GetItem($_.SourceItemID) } | `
? { $_ -ne $null } | `
? { $_.Paths.LongID.StartsWith($siteLongID) }
$instance = [Sitecore.DependencyInjection.ServiceLocator]::ServiceProvider
$mapsProvider = $instance.GetType().GetMethod('GetService').Invoke($instance, [Sitecore.XA.Foundation.Geospatial.Services.IMapsProvider])
$key = $mapsProvider.GetMapsKey($SiteItem)
if ([string]::IsNullOrWhiteSpace($key) -eq $true) {
if ($mapsRenderingUsages.Count -gt 0) {
$result.Result = [Result]::Error
$result.Message = "Found $($mapsRenderingUsages.Count) useages of Maps rendering in selected site but Maps Provider key is empty."
$mapsRenderingUsages | % { Write-Log "[SXA.HealthCheck][Maps Provider key] $($_.Paths.Path)" }
}
else {
$result.Result = [Result]::Warning
$result.Message = "Maps Provider key is empty. If you are not going to use Maps rendering that's fine."
}
return $result
}
return $result
}
},
@{
Title = "SXA Best practices - unused data sources";
Description = "Checks whether there are unused data sources present in your site";
Version = @{
From = 1800;
To = "*";
};
Dependency = @("{4EE33975-DB00-455E-9F9C-2CB78C892C79}");
Script = {
param(
[Sitecore.Data.Items.Item]$SiteItem
)
[ValidationResult]$result = New-ResultObject
Import-Function CleanDataFolder
function Get-RelativeDatasourcePath {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0 )]
[Item]$Item
)
process {
Import-Function Get-PresentationDetails
Write-Verbose "Cmdlet Get-RelativeDatasourcePath - Process"
$presentation = Get-PresentationDetails $item
$definition = [Sitecore.Layouts.LayoutDefinition]::Parse($presentation)
$definition.Devices | % {
$_.Renderings | ? { $_.Datasource -ne $null } | ? {
$_.Datasource.StartsWith([Sitecore.XA.Foundation.LocalDatasources.Constants]::LocalPrefix) -or $_.Datasource.StartsWith([Sitecore.XA.Foundation.LocalDatasources.Constants]::PageRelativePrefix)
} | % {
$_.Datasource.Replace([Sitecore.XA.Foundation.LocalDatasources.Constants]::LocalPrefix, "").Replace([Sitecore.XA.Foundation.LocalDatasources.Constants]::PageRelativePrefix, "")
}
}
}
}
$item = $SiteItem.Axes.GetDescendants() | ? { $_.TemplateID -eq "{1C82E550-EBCD-4E5D-8ABD-D50D0809541E}" } | Wrap-Item
$unusedDatasources = $item | % {
$item = $_.Parent
$dataFolder = $_
[Item[]]$dataSources = Get-NestedDatasource $dataFolder
$dataSourcesPaths = Get-RelativeDatasourcePath $item
$dataSourcesIds = Get-DataSourcesIdsFromLayout $item
foreach ($datasource in $dataSources) {
$usedAsPageRelative = IsDataSourceUsedAsPageRelative $datasource $dataSourcesPaths
$usedAsGlobal = IsDataSourceUsedAsGlobal $datasource
$usedAsGlobalOnCurrentPage = IsDataSourceUsedAsGlobalOnCurrentPage $datasource $dataSourcesIds
if ($usedAsPageRelative -or $usedAsGlobal -or $usedAsGlobalOnCurrentPage) {
}
else {
Write-Log "[SXA.HealthCheck][Unused data sources] Following data source is probably unused and could be recycled: $($datasource.Paths.Path)"
$datasource
}
}
}
if ($unusedDatasources.Count -gt 0) {
$result.Result = [Result]::Warning
$result.Message = "Found unused datasources ($($unusedDatasources.Count)). Open SPE log file to learn more"
}
return $result
}
},
@{
Title = "SXA Best practices - custom items under SXA nodes";
Description = "Checks whether there are additional or modified files under SXA nodes";
Version = @{
From = 1000;
To = "*";
};
Script = {
$excludedItems = @("{B0979E0D-16D4-46CC-9D7A-88895FEA2165}" , "{F78EC6BE-D9BA-4595-B740-E801ACDB0459}")
$excludedTemplates = @("{B43AB8D5-E123-42DD-8042-DE869CC98C4F}")
$rootsWildcard = @("/sitecore/templates/",
"/sitecore/system/Settings",
"/sitecore/layout/Renderings",
"/sitecore/layout/Placeholder",
"/sitecore/layout/Layouts",
"/sitecore/media library",
"/sitecore/templates/Branches")
$rootsPaths = @("/sitecore/system/Modules/PowerShell/Script Library/SXA",
"/sitecore/system/Modules/PowerShell/Script Library/JSS SXA",
"/sitecore/media library/Themes/Wireframe#-#deprecated",
"/sitecore/media library/Themes/Wireframe",
"/sitecore/media library/Base Themes/Analytics",
"/sitecore/media library/Base Themes/Bing Maps JS Connector",
"/sitecore/media library/Base Themes/Google Maps JS Connector",
"/sitecore/media library/Base Themes/Grid Theme",
"/sitecore/media library/Base Themes/Json",
"/sitecore/media library/Base Themes/Main Theme",
"/sitecore/media library/Base Themes/Maps",
"/sitecore/media library/Base Themes/Meta Partial Design Theme",
"/sitecore/media library/Base Themes/SearchTheme",
"/sitecore/media library/Base Themes/StickyNotes",
"/sitecore/media library/Base Themes/Variants",
"/sitecore/media library/Base Themes/XA API",
"/sitecore/media library/Base Themes/Core Libraries",
"/sitecore/media library/Base Themes/Editing Theme",
"/sitecore/media library/Base Themes/Horizon Editing Theme",
"/sitecore/media library/Base Themes/Editing Components",
"/sitecore/media library/Base Themes/Composite Theme",
"/sitecore/media library/Base Themes/Resolve Conflicts",
"/sitecore/media library/Base Themes/Components Theme"
)
function Get-UpdatedItems {
param (
[string]$root,
[string]$updated,
[Switch]$Wildcard
)
if ($Wildcard) {
$query = "fast:$root/*/Experience Accelerator//*[@__Updated != '$updated%']"
}
else {
$query = "fast:$root//*[@__Updated != '$updated%']"
}
Get-Item -Path master: -Query $query
}
function Test-NotExcludedTemplate {
param (
[Sitecore.Data.Items.Item]$Item
)
!$excludedTemplates.Contains($Item.TemplateID.ToString())
}
function Test-NotExcludedItem {
param (
[Sitecore.Data.Items.Item]$Item
)
!$excludedItems.Contains($Item.ID.ToString())
}
function Get-UpdatedDate {
$initialItem = Get-Item -Path '/sitecore/system/Settings/Foundation/Experience Accelerator/Upgrade/Initial'
$initialItem."__Updated".ToString("yyyyMMdd")
}
function Get-ModifiedSXAItems {
$updated = Get-UpdatedDate
$rootsWildcard | % { Get-UpdatedItems $_ $updated -Wildcard } | ? { Test-NotExcludedItem $_ } | ? { Test-NotExcludedTemplate $_ }
$rootsPaths | % { Get-UpdatedItems $_ $updated } | ? { Test-NotExcludedTemplate $_ }
}
[ValidationResult]$result = New-ResultObject
$items = Get-ModifiedSXAItems
if ($items.length -ne 0) {
$result.Result = [Result]::Error
$result.Message = "Found custom/modified items under SXA nodes ($($items.Count)). Open SPE log file to learn more"
$items | % {
Write-Log "[SXA.HealthCheck][Custom items under SXA nodes] The following item was probably updated/added after package installation $($_.Paths.Path)"
}
}
else {
$result.Result = [Result]::OK
}
$result
}
}
$siteItem = Get-Item .
[Sitecore.Data.ID]$siteTemplateID = [Sitecore.XA.Foundation.Multisite.Templates+Site]::ID
if ([Sitecore.Data.Managers.TemplateManager]::GetTemplate($siteItem).InheritsFrom($siteTemplateID) -eq $false) {
Show-Alert "Please select a SXA site`n`nCurrent item: '$($siteItem.Paths.Path)'`nis not a SXA site item"
return
}
$TenantItem = Get-TenantItem $SiteItem
[Sitecore.Data.ID]$id = [Sitecore.XA.Foundation.Scaffolding.Templates+_Modules+Fields]::Modules
[Sitecore.Data.Fields.MultilistField]$sitesModulesField = $SiteItem.Fields[$id]
[Sitecore.Data.Fields.MultilistField]$tenantModulesField = $TenantItem.Fields[$id]
Write-Host "Validating site: $($siteItem.Paths.Path)" -ForegroundColor Cyan
# Icon mapping
$modeMapping = @{}
$modeMapping[[Result]::Warning] = "\Images\warning.png"
$modeMapping[[Result]::Error] = "\Images\error.png"
$modeMapping[[Result]::OK] = "\Images\check.png"
$steps | `
? { Test-ValidVersion $_ } | `
? { Test-Dependency $_ $sitesModulesField $tenantModulesField } | `
% {
[ValidationStep]$step = $_
Write-Host "`nValidation step: $($step.Title)" -ForegroundColor Cyan
[ValidationResult]$result = Invoke-Command -Script $step.Script -Args $siteItem
$step.ValidationResult = $result
if ($result.Result -eq [Result]::Error) {
Write-Host $result.Message -ForegroundColor Red
}
if ($result.Result -eq [Result]::Warning) {
Write-Host $result.Message -ForegroundColor Yellow
}
if ($result.Result -eq [Result]::OK) {
Write-Host $result.Message -ForegroundColor Green
}
$step
} | Show-ListView `
-PageSize 25 `
-Property `
@{Label = "Title"; Expression = { $_.Title } },
@{Label = "Icon"; Expression = { $modeMapping[$_.ValidationResult.Result] } },
@{Label = "Description"; Expression = { $_.Description } },
@{Label = "Message"; Expression = { $_.ValidationResult.Message } }