If you manage a multi-site Sitecore environment, you’ve probably encountered the need to create sitemap.xml files for search engines like Google and Bing. While you can build this with C# code or third-party modules, an easier, zero-deployment approach is to use the Sitecore PowerShell Extensions (SPE) module.
In this guide, you’ll learn how to generate a Sitemap XML for multiple websites directly from the Sitecore admin interface using PowerShell. This approach is ideal for teams that do not have access to deploy code to content delivery (CD) servers or for situations where the original source code is missing.
Why Generate Sitemap XML Using PowerShell
Using Sitecore PowerShell to generate sitemap files provides several advantages:
- No code deployment required; everything runs in the Content Management (CM) environment.
- Supports multiple sites within one instance (multi-tenant setup).
- Full control over URL structure, output path, and file naming.
- Quick and repeatable; can be run on-demand or scheduled.
- Produces search engine-friendly XML that complies with sitemaps.org.
PrerequisitesBefore running the script, ensure the following:
- Sitecore PowerShell Extensions (SPE) is installed.
- You can access PowerShell ISE within the Sitecore admin area (
/sitecore/shell/Applications/PowerShell/PowerShellIse). - The IIS App Pool user has write permissions to the folder where the sitemap XML will be saved.
The PowerShell Script
Below is the complete script that generates a combined sitemap.xml for multiple sites in your Sitecore instance.
# =======================================
# Sitecore Unified Sitemap Generator
# Combines multiple sites into one sitemap.xml
# =======================================
# Define all site configurations
$sites = @(
@{
RootPath = "master:/sitecore/content/sample-website/Home"
Domain = "https://www.sample-website.com"
},
@{
RootPath = "master:/sitecore/content/another-site/Home"
Domain = "https://www.another-site.com"
}
)
# Output path for the combined sitemap
$outputPath = "D:\WebApplications\sitecore\sitemap_combined.xml"
# Configure LinkManager options
$linkOptions = New-Object Sitecore.Links.UrlOptions
$linkOptions.AlwaysIncludeServerUrl = $false
$linkOptions.AddAspxExtension = $false
$linkOptions.LanguageEmbedding = "Never"
Write-Host "Starting unified sitemap generation..."
# Initialize XML document
$sitemap = New-Object System.Xml.XmlDocument
$urlset = $sitemap.CreateElement("urlset")
$urlset.SetAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9")
$sitemap.AppendChild($urlset) | Out-Null
# Function to traverse and append items
function Add-ItemToSitemap($item, $domain) {
if ($item -ne $null -and $item.TemplateName -ne "Folder" -and $item.Fields["__Renderings"]) {
# Generate relative URL
$relativeUrl = [Sitecore.Links.LinkManager]::GetItemUrl($item, $linkOptions)
# Strip CM hostname if present
if ($relativeUrl -match "https?://[^/]+(/.*)") {
$relativeUrl = $Matches[1]
}
# Build full CD URL
if ($relativeUrl.StartsWith("/")) {
$fullUrl = "$domain$relativeUrl"
} else {
$fullUrl = "$domain/$relativeUrl"
}
# Build <url> element
$urlElement = $sitemap.CreateElement("url")
$loc = $sitemap.CreateElement("loc")
$loc.InnerText = $fullUrl
$urlElement.AppendChild($loc) | Out-Null
$lastmod = $sitemap.CreateElement("lastmod")
$lastmod.InnerText = $item.Statistics.Updated.ToString("yyyy-MM-dd")
$urlElement.AppendChild($lastmod) | Out-Null
$urlset.AppendChild($urlElement) | Out-Null
}
foreach ($child in $item.Children) {
Add-ItemToSitemap $child $domain
}
}
# Iterate over each site and add its URLs
foreach ($site in $sites) {
Write-Host "`n--------------------------------------------"
Write-Host "Processing site: $($site.Domain)"
Write-Host "Root path: $($site.RootPath)"
Write-Host "--------------------------------------------`n"
$rootItem = Get-Item -Path $site.RootPath
if ($null -eq $rootItem) {
Write-Error "Root item not found: $($site.RootPath)"
continue
}
Add-ItemToSitemap $rootItem $site.Domain
}
# Save combined sitemap
$sitemap.Save($outputPath)
Write-Host "`nUnified sitemap generated successfully."
Write-Host "Output path: $outputPath"
How the Script Works
1. Site Configuration
The $sites array defines multiple websites (root paths and their public domains). You can add as many entries as your Sitecore instance hosts.
$sites = @(
@{ RootPath = "master:/sitecore/content/sample-website/Home"; Domain = "https://www.sample-website.com" }
)
2. LinkManager Options
The script configures Sitecore’s LinkManager to generate clean, relative URLs without .aspx extensions or CM hostnames.
3. Recursive Traversal
The function Add-ItemToSitemap recursively loops through all Sitecore items under each root path and includes items that have renderings (actual pages).
4. URL Normalization
The script ensures that all URLs point to the content delivery (CD) domain, not the internal CM hostname, even though the script is executed in the CM environment.
5. XML Output
All URLs from all configured sites are merged into a single XML structure under <urlset> and saved to the defined $outputPath.
Example Output
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.sample-website.com/about-us</loc>
<lastmod>2025-11-06</lastmod>
</url>
<url>
<loc>https://www.another-site.com/blog/latest-article</loc>
<lastmod>2025-11-06</lastmod>
</url>
</urlset>
This sitemap can be submitted directly to Google Search Console, Bing Webmaster Tools, or any search crawler for indexing.
Summary
This PowerShell-based sitemap generator provides a simple, flexible, and deployment-free solution for Sitecore developers and administrators. It can be easily adapted for:
- Single or multi-site Sitecore instances
- Multilingual site structures
- Automated nightly tasks using Sitecore’s Task Scheduler
By using this approach, you can maintain full control over how search engines crawl your websites without requiring code changes or deployments.
Leave a Reply