An issue that crops up fairly often in web agency work is that you have to work on code for older versions of Sitecore. Most of the time this is fine, but sometimes in between the Sitecore version getting released and you doing this work, stuff changes in Windows that makes this setup harder than it should be... This has been a challenge recently as some of my fellow developers now have Windows 11 on their laptops, and they're having to work on Sitecore 10.2 projects. And out of the box, SIF or SIA won't install in that scenario these days. Having had to help a couple of people with these issues recently, I figured it might be worth automating the fixes with some Powershell, so it's easier in the future. And maybe that automation might help you?
So if you try to install Sitecore 10.2 on a fresh Windows 11 machine, what goes wrong out of the box, and how can you fix it?
It will all appear to go well until the start of the "install Sitecore" phase, and then it will fail with an error like this:
Cannot validate argument on parameter 'Path'. The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: The term 'C:\Program Files\iis\Microsoft Web Deploy V3\msdeploy.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
This issue is well known enough that it has its own Sitecore Support bulletin, and revolves around the depreciation of the Web Platform Installer as the way to add some extensions to IIS. Silently, the prerequisites phase of the install process will fail to add the WebDeploy and URL Rewrite tools that Sitecore requires, due to changes in how Microsoft supplies these.
The support article suggests adding these manually - but automation is the way. So what needs changing in the SIF data file for the prerequisites to make that work? Well this file already downloads and installs some MSI files, so repeating those patterns looks like the way forward. The pattern is:
The json for a variable for where to find the WebDeploy MSI looks like:
"WebDeploy": { "Type": "String", "Description": "Download path for WebDeploy", "DefaultValue": "https://download.microsoft.com/download/b/d/8/bd882ec4-12e0-481a-9b32-0fae8e3c0b78/webdeploy_amd64_en-US.msi" }
So the first step is to add that to the
Prerequisites.json
file. And that means loading the data into an object:
$json = Get-Content "Prerequsites.json" -Raw | ConvertFrom-Json
And then it can add a new object to the
Parameters
element.
$json.Parameters | Add-Member -MemberType NoteProperty -Name "WebDeploy" -Value ([PSCustomObject]@{ Type = 'String' Description = 'Download path for WebDeploy' DefaultValue = 'https://download.microsoft.com/download/b/d/8/bd882ec4-12e0-481a-9b32-0fae8e3c0b78/webdeploy_amd64_en-US.msi' })
Adding the variable is similar, but it goes to the
Variables
bit of the data, and it's simpler as it's just an "name / value" entry:
$json.Variables | Add-Member -MemberType NoteProperty -Name "WebDeploy.Download" -Value ("[JoinPath(variable('Temp.Location'),'webdeploy_amd64_en-US.msi')]")
The next bit is to add some data to do the download and install. But there are already steps here for doing that for these tools via the Web Platform Installer. (That's what's become broken in Windows 11) Removing those can be accomplished by deleting bits of the
Tasks
element of the data:
$json.Tasks.PSObject.Properties.Remove("DownloadWebPlatformInstaller") $json.Tasks.PSObject.Properties.Remove("InstallWebPlatformInstaller") $json.Tasks.PSObject.Properties.Remove("InstallWebDeploy3.6") $json.Tasks.PSObject.Properties.Remove("InstallURLRewrite2")
And then the code can add in an element to do the download. That's easiest to break it two steps though because it needs a parent element with a child object for the parameters:
$json.Tasks | Add-Member -MemberType NoteProperty -Name "DownloadWebDeploy" -Value ([PSCustomObject]@{ Type = 'DownloadFile' }) $json.Tasks.DownloadWebDeploy | Add-Member -MemberType NoteProperty -Name "Params" -Value ([PSCustomObject]@{ SourceUri = "[parameter('WebDeploy')]" DestinationPath = "[variable('WebDeploy.Download')]" })
And once that download has completed the install can be done with a
StartProcess
task to run the MSI to do the install:
$json.Tasks | Add-Member -MemberType NoteProperty -Name "InstallWebDeploy" -Value ([PSCustomObject]@{ Type = 'StartProcess' }) $json.Tasks.InstallWebDeploy | Add-Member -MemberType NoteProperty -Name "Params" -Value ([PSCustomObject]@{ FilePath = "[variable('WebDeploy.Download')]" ArgumentList = "[variable('InstallArgs')]" Wait = $true })
The process for the URL Rewrite module is the same, but with a different URL to download from. And once both of those processes are added into the file, the changed data can be saved back to disk:
$json | ConvertTo-Json -Depth 10 | Out-File "Prerequisites.json" -Encoding default
Once the install-Sitecore phase gets a bit further you hit a second issue when the SIF scripts try to connect to your database server:
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 is an issue caused by newer versions of SQL Server using a self-signed certificate to encrypt their connections - and that certificate not being trusted by the client code by default. Both Stack Overflow and our friends at Fishtank have commented on this issue.
But it's fixed fairly simply - you add a
TrustServerCertificate
field set to
true
to each database connection config, and the SQL client code will ignore the self-signed certificate.
And there are five places in the 10.2 install which require this to be added:
sitecore-xp0.json
has one instance under the
AddSqlDatabasesToElasticPool
taskxconnect-xp0.json
has five instances under the
AddSqlDatabasesToElasticPool
,
CreateShardApplicationDatabaseServerLoginInvokeSqlCmd
,
CreateShardManagerApplicationDatabaseUserInvokeSqlCmd
,
CreateShard0ApplicationDatabaseUserInvokeSqlCmd
,
CreateShard1ApplicationDatabaseUserInvokeSqlCmd
, tasksThe same business about loading and saving the data is involved here, but adding that extra parameter for the
AddSqlDatabasesToElasticPool
requires something like:
$json.Tasks.AddSqlDatabasesToElasticPool.Params | Add-Member -MemberType NoteProperty -Name "TrustServerCertificate" -Value ($true)
And that can be repeated across the two files and various instances. You have to remember to target the right element of the json under the
Tasks
element each time though.
So those bits of code can be tidied up and put together into a single script which can be run before starting the prerequisites part of a SIF or SIA install on Windows 11. It seemed sensible to break this up into three functions - one for each of the files that get changed. The complete script is available in this gist. So the process is:
I guess this approach can be tweaked to help with any issues in other versions too if necessary, but that's a job for another day...
↑ Back to top