Technical articles on AI agents, Azure, .NET, architecture, and EV charging systems from Sydney.

Category: Architecture & Leadership

Solution architecture, software design, engineering leadership, and Microsoft 365 / Power Platform

How to Generate Sitemap XML in Sitecore Using PowerShell

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:

  1. Sitecore PowerShell Extensions (SPE) is installed.
  2. You can access PowerShell ISE within the Sitecore admin area (/sitecore/shell/Applications/PowerShell/PowerShellIse).
  3. 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.

Resolving the “Certificate Chain Was Issued by an Authority That Is Not Trusted” Error During Sitecore Installation on Windows 11

When installing Sitecore on Windows 11, you might encounter the following error:

A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)

This issue arises due to a recent security enforcement rolled out by Microsoft. Windows 11 now requires SQL Server connections to use encrypted connections by default. Some of the PowerShell scripts used during the Sitecore installation process are not configured to handle this change, resulting in the above error.

In this blog post, we’ll dive into the root cause of the issue and walk you through the steps to resolve it.


Understanding the Root Cause

The error is triggered because the PowerShell scripts used in the Sitecore installation attempt to connect to the SQL Server without explicitly trusting the server’s SSL certificate. With the new security enforcement, connections to the SQL Server default to encryption, but without a trusted certificate, the connection fails.

This is particularly relevant when using self-signed certificates or development environments where the SQL Server’s certificate authority is not inherently trusted.

How to Fix the Error

The solution is to explicitly configure the Sitecore installation scripts to trust the SQL Server’s certificate by setting the TrustServerCertificate variable to true. This needs to be done in two specific JSON files used during the installation process:

  1. sitecore-xp0.json
  2. xconnect-xp0.json

Steps to Resolve

  1. Locate the JSON Files:
    • Navigate to the folder where you extracted the Sitecore installation files.
    • Open the ConfigurationFiles directory (or equivalent, depending on your setup).
    • Find the sitecore-xp0.json and xconnect-xp0.json files.
  2. Modify the JSON Files:
    • Open sitecore-xp0.json in a text editor (e.g., Visual Studio Code or Notepad++).
    • Look for [variable('Sql.Credential')] in the JSON structure.
    • Add the following key-value pair:"TrustServerCertificate": true
    • Example:
"CreateShardApplicationDatabaseServerLoginInvokeSqlCmd": {
    "Description": "Create Collection Shard Database Server Login.",
    "Type": "InvokeSqlcmd",
    "Params": {
        "ServerInstance": "[parameter('SqlServer')]",
        "Credential": "[variable('Sql.Credential')]",
        "TrustServerCertificate": true,
        "InputFile": "[variable('Sharding.SqlCmd.Path.CreateShardApplicationDatabaseServerLogin')]",
        "Variable": [
            "[concat('UserName=',variable('SqlCollection.User'))]",
            "[concat('Password=',variable('SqlCollection.Password'))]"
        ]
    },
    "Skip": "[or(parameter('SkipDatabaseInstallation'),parameter('Update'))]"
},
"CreateShardManagerApplicationDatabaseUserInvokeSqlCmd": {
    "Description": "Create Collection Shard Manager Database User.",
    "Type": "InvokeSqlcmd",
    "Params": {
        "ServerInstance": "[parameter('SqlServer')]",
        "Credential": "[variable('Sql.Credential')]",
        "TrustServerCertificate": true,
        "Database": "[variable('Sql.Database.ShardMapManager')]",
        "InputFile": "[variable('Sharding.SqlCmd.Path.CreateShardManagerApplicationDatabaseUser')]",
        "Variable": [
            "[concat('UserName=',variable('SqlCollection.User'))]",
            "[concat('Password=',variable('SqlCollection.Password'))]"
        ]
    },
    "Skip": "[or(parameter('SkipDatabaseInstallation'),parameter('Update'))]"
}
  • Repeat the same modification for the xconnect-xp0.json file.
  • Save and Retry Installation:
    • Save both JSON files after making the changes.
  • Re-run the Sitecore installation PowerShell script.

    Additional Notes

    • Security Considerations: Setting TrustServerCertificate to true is a quick fix for development environments. However, for production environments, it’s recommended to install a certificate from a trusted Certificate Authority (CA) on the SQL Server to ensure secure and trusted communication.
    • Error Still Persists?: Double-check the JSON modifications and ensure the SQL Server is accessible from your machine. If issues persist, verify firewall settings and SQL Server configuration.

    Conclusion

    The “Certificate chain was issued by an authority that is not trusted” error during Sitecore installation is a direct result of Microsoft’s enhanced security measures in Windows 11. By updating the Sitecore configuration files to include the TrustServerCertificate setting, you can bypass this error and complete the installation successfully.

    For a smoother experience in production environments, consider implementing a properly signed SSL certificate for your SQL Server.

    If you’ve encountered similar issues or have additional tips, feel free to share them in the comments below!

    How Fear Based Leaders Destroy Employee Morale and Performance

    Fear is a powerful emotion that can motivate us to act or paralyze us from taking action. In the workplace, some leaders may use fear as a tool to influence their employees’ attitudes, values, or behaviors. However, this approach can have negative consequences for both the leaders and their teams. In this article, we will explore how fear-based leadership can destroy employee morale and performance, and what leaders can do instead to create a culture of psychological safety and empowerment.

    I have learned of some instances where, upon receiving a resignation letter from an employee in my previous organization, the manager tried to dissuade them from leaving by saying “Don’t resign or else you will regret it” and citing examples of former employees who faced difficulties in their new jobs. I find this to be a very unprofessional and unethical tactic by the manager. A true leader would be supportive of their team member’s career aspirations and wish them well for their future endeavors. They would also recognize that the employee might have the potential to start their own successful business someday or be a successful leader.

    What is fear-based leadership?

    Fear-based leadership is a style of management that relies on threats, punishments, intimidation, or coercion to achieve desired outcomes. Fear-based leaders may use various tactics to instill fear in their employees, such as:

    • Setting unrealistic expectations and deadlines
    • Micromanaging and controlling every aspect of work
    • Criticizing and blaming employees for mistakes
    • Withholding praise and recognition
    • Creating a competitive and hostile work environment
    • Ignoring or dismissing employees’ opinions and feedback
    • Threatening employees with job loss, demotion, or pay cuts

    Fear-based leaders may believe that fear is an effective motivator that can drive performance and productivity. They may also think that fear can help them maintain authority and control over their teams. However, research shows that fear-based leadership has many negative effects on both individuals and organizations.

    The effects of fear-based leadership

    Fear-based leadership can have detrimental impacts on employee morale and performance in various ways:

    • It demoralizes people: Fear-based leadership creates a power imbalance that erodes trust,
      respect, and dignity among employees. Employees may feel insecure, anxious, depressed,
      or hopeless about their work situation. They may also lose their sense of purpose and meaning in their work.
    • It creates a breeding ground for resentment: Some people may react with anger, frustration, or defiance to fear-based leadership. They may resent their leader for treating them unfairly or disrespectfully. They may also harbor negative feelings toward their colleagues who comply with or support the leader’s actions.
    • It impedes communication: Fear-based leadership discourages open and honest communication among employees.
      Employees may be afraid to speak up or share their ideas for fear of being ridiculed or punished by their leader. They may also avoid giving feedback or asking for help from their peers for fear of being seen as weak or incompetent. This leads to poor collaboration and information sharing within teams.
    • It inhibits innovation: Fear-based leadership stifles creativity and learning among employees. Employees may be reluctant to try new things or experiment with different solutions for fear of making mistakes or failing. They may also resist change or feedback for fear of losing their status quo or comfort zone. This hinders innovation and improvement within organizations.
    • It reduces engagement: Fear-based leadership lowers employee engagement levels. Employees may feel detached from their work goals and outcomes. They may also feel less motivated to perform well or go beyond expectations. They may only do the minimum required work to avoid negative consequences from their leader. This affects productivity and quality within organizations.

    What leaders can do instead

    Instead of using fear as a motivational tool for employees, leaders should create a culture of psychological safety
    and empowerment within organizations. Psychological safety is “a shared belief held by members of a team that the team is safe for interpersonal risk taking”.

    It means that employees feel comfortable expressing themselves without fearing negative repercussions from others.

    Empowerment is “the process of enhancing feelings of self-efficacy among organizational members through identification with organizational goals”. It means that employees feel confident in their abilities and have autonomy over their work decisions.

    Leaders who foster psychological safety and empowerment among employees can benefit from:

    • Higher trust: Employees trust their leaders who treat them with respect, care, and fairness.
      They also trust each other who support them, listen to them, and collaborate with them. Trust enhances teamwork,
      cooperation, and loyalty within organizations.
    • Higher morale: Employees feel valued, appreciated, and recognized by their leaders who praise them, reward them,

    Power Apps – Mount a SQL Server table as an entity in Dataverse

    Business Case: We have a need where we have an existing database from a legacy app and we really enjoyed how easy and fast it is to use Power Apps (Model Driven app) to access entities in dataverse. So can we use mount an external table to Dataverse and the answer is yes, it is possible and it is straight forward

    Add a SQL Server Connection in Power Apps – “Authentication Type : SQL Server Authentication” for this POC. But I think the best practice is to use Service Principal (Azure AD Application)

    On your SQL Server side (in my case i am using Azure), you need to whitelist the Power Platform IP Addresses – You can get the list of IP Addresses from here – Managed connectors outbound IP addresses

    On the Power Apps – Go to Tables and Select New Table then select “New table from external data

    Select the connection – SQL Server that we created before and then select the SQL Server table that you want to mount

    Once all done, now you can see all the records in SQL server as virtual entity in your dataverse

    Process of Improving Software Quality

    I would like to share my working experience at VMWare, in this last 1 year we have been improving a lot in our software development process

    Last year, We had much much higher regression rate and it’s all back to the battle against developers and QA. We as developer always try to make our self look right and always feel confident that we are taking the right approach and there is no flaw in our code.

    Once the build is started and installed, then QA start raising bugs to us and this process of back and forth is really not efficient and causing the software released to be delayed, frustrated developers and frustrated QA and it affects the whole thing

    So how do we improve the quality

    1. Code Review

    -We are using Review Board to do code review before we check in the code and not after. We need to get “Review Passed” by other developer before we can check in (we use post-review command line with the changeset number to post the review)

    -We need to write down our “Unit Testing” (e.g login to admin, press button A then it shows ABC) in our review

    *We don’t use TFS but TFS has its own code review, but if you want to use Review Board for TFS then you can read awesome article here

    2. User Acceptance Criteria

    -This is a simple things that we never thought before, what we are doing now is to sit to have a developer and QA to sit together and draft the test cases for a task that the developer is going to do

    -Important, we don’t start the coding first. By doing this, the developer can think about their solution carefully before writing the code and look from the broader perspective

    3. Unit testing

    when you have your code base flexible or modular then you can start writing unit test first before start writing the code. So you write the code to pass that unit testing criteria – TDD (Test Driven Development)

    -When I say the code base is flexible or modular means that it is possible for you to inject your unit testing with some fake data/implementation

    4. Developer need to be pride with its own code

    We as the developer need to put pride in the code, we need to be able to explain of what your code does to other developer

    -Developer need to be able to explain why your coding/solution approach is better than other coding/solution approach

    -Always think maintainability, make sure you are not over engineered the solution and make sure the code is easy to understand and maintained. Make sure the code can be extensible easily in the future by other developer

    -Always think scalability, how scalable is your solution when the system is growing larger

    -Don’t forget to put comment in your code because it will help a lot for other developers

    Conclusion

    This all will take longer to start doing this, but once you and the team get used to this process then you will see the better quality of software and less frustration for the developers and QA. It will be faster at the end of the day because of less bounce back from the QA team to the developer and it results on more productivity for both teams.

    It’s not a simple process but one keyword that you need to keep in mind “Believe” that this process will work

    Powered by WordPress & Theme by Anders Norén