This is another script, PowerShell Sitecore Role Configurator, that was based on the one from Michael West, but has several enhancements and modifications designed for improved CI-build support and simpler integration into systems like Bamboo, Octopus and TeamCity.
Like the script from Michael West, PowerShell Sitecore Role Configurator takes the Sitecore-provided "Config Enable/Disable Spreadsheet" as a input, but it also includes a tool for testing/debugging the spreadsheet to help you find and fix any inconsistencies that would otherwise break your configuration script.
There are three files that primarily make up PowerShell Sitecore Role Configurator:
I have copied the current version of each file below, for your convenience.
Invoke-SitecoreRoleConfigurator.ps1
This is the main configuration script. You would call this script directly or from your CI-build tool of choice, in order to configure your Sitecore instance.
function Invoke-SitecoreRoleConfigurator {
Param(
[Parameter(Mandatory=$True)] [string] $ApplicationFolderPath,
[Parameter(Mandatory=$True)] [string] $RoleColumn,
[Parameter(Mandatory=$False)] [string] $CsvSettingsFilePath = ".\ConfigurationCsv.Settings.xml",
[Parameter(Mandatory=$False)] [string[]] $ExcludedSearchProviders = @(),
[Parameter(Mandatory=$False)] [string] $CsvFilePath,
[Parameter(Mandatory=$False)] [string] $FileNameColumn,
[Parameter(Mandatory=$False)] [string] $FilePathColumn,
[Parameter(Mandatory=$False)] [string] $DefaultExtensionColumn,
[Parameter(Mandatory=$False)] [string] $SearchProviderColumn,
[Parameter(Mandatory=$False)] [switch] $DryRun
)
$ErrorActionPreference = "Stop";
$VerbosePreference = "Silentlycontinue"
try {
# make sure that the settings file exists
if (-not (Test-Path -Path $CsvSettingsFilePath -PathType Leaf)) {
throw [System.IO.FileNotFoundException] "Settings file '$CsvSettingsFilePath' suppied for parameter 'CsvSettingsFilePath' was not found. Settings file is required for script execution."
}
# get the xml
[xml]$settings = Get-Content -Path $CsvSettingsFilePath
# returns the value, if not null, or else the default value
function Get-ValueOrDefault {
Param([string] $Value, [string] $Default)
if (!$Value) { return $Default } else { return $Value }
}
# apply default values from the XML settings, where needed
$CsvFilePath = Get-ValueOrDefault $CsvFilePath $settings.Parameters.CsvFilePath;
$FileNameColumn = Get-ValueOrDefault $FileNameColumn $settings.Parameters.FileNameColumnHeader
$FilePathColumn = Get-ValueOrDefault $FilePathColumn $settings.Parameters.FilePathColumnHeader
$DefaultExtensionColumn = Get-ValueOrDefault $DefaultExtensionColumn $settings.Parameters.DefaultExtensionColumnHeader
$SearchProviderColumn = Get-ValueOrDefault $SearchProviderColumn $settings.Parameters.SearchProviderColumnHeader
# trim values in excluded search providers
$ExcludedSearchProviders = $ExcludedSearchProviders | ForEach-Object { $_.Trim() }
# performs enabling/disabling of file by changing extension
function Rename-ConfigFile {
Param(
[Parameter(Mandatory=$True)] [string] $ExistingName,
[Parameter(Mandatory=$True)] [string] $TargetName,
[Parameter(Mandatory=$False)] [string] $ContainerPath
)
# if a container path was supplied then join the path to the file names
if ($ContainerPath) {
$ExistingName = Join-Path -Path $ContainerPath -ChildPath $ExistingName
$TargetName = Join-Path -Path $ContainerPath -ChildPath $TargetName
}
if(-not (Test-Path -Path $ExistingName)) {
Write-Host "Skipping $ExistingName because the path does not exist."
continue
}
# don't apply changes if this is DryRun mode
if (-not $DryRun) {
Move-Item -Path $ExistingName -Destination $TargetName
}
}
# disables the file by changing the extension
function Rename-DisableConfigFile {
Param(
[Parameter(Mandatory=$True)] [string] $ExistingName,
[Parameter(Mandatory=$True)] [string] $ContainerPath
)
# change the extension the file
$targetName = $fileName + ".disabled";
# perform the renaming
Rename-ConfigFile -ExistingName $ExistingName -TargetName $targetName -ContainerPath $ContainerPath
Write-Host "`tFile successfully renamed to: $targetName"
}
# enables the file by changing the extension
function Rename-EnableConfigFile {
Param(
[Parameter(Mandatory=$True)] [string] $ExistingName,
[Parameter(Mandatory=$True)] [string] $DefaultExtension,
[Parameter(Mandatory=$True)] [string] $ContainerPath
)
# remove the default extension
$targetName = $ExistingName.Substring(0, $ExistingName.Length - $DefaultExtension.Length);
# don't add '.config' if it's already there, e.g. if the file was originally 'Foo.config.disabled'
if (!$targetName.EndsWith(".config")) {
$targetName += ".config"
}
Rename-ConfigFile -ExistingName $ExistingName -TargetName $targetName -ContainerPath $ContainerPath
}
# import and parse the CSV
$csvTable = Import-Csv -Path $CsvFilePath
# loop through each row and enable/disable the file based on the given settings
foreach($csvTableRow in $csvTable) {
# get the full path to the config file's parent directory
$configPath = Join-Path -Path $ApplicationFolderPath -ChildPath $csvTableRow.$FilePathColumn.Trim()
$fileName = $csvTableRow.$FileNameColumn.Trim()
$defaultExtension = ".$($csvTableRow.$DefaultExtensionColumn)".Trim()
# enable, disable or skip based on the given role
switch($csvTableRow.$RoleColumn.Trim()) {
"Enable" {
Write-Host "Enable: $fileName"
# before we enable the config, make sure that it is not for an excluded search provider
if ($ExcludedSearchProviders -contains $csvTableRow.$SearchProviderColumn.Trim()) {
if ($defaultExtension -eq ".config") {
Write-Host "`tDisabling file '$fileName'. File is for an excluded search provider."
# disable the file
Rename-DisableConfigFile -ExistingName $fileName -ContainerPath $configPath
}
Write-Host "`tSkipping file '$fileName'. File is for an excluded search provider."
} else {
# there is an issue with the CSV - we could probably work around it, but better to have someone look at it
if (!$fileName.EndsWith($defaultExtension)) {
throw [System.Exception] "File '$fileName' does not have the expected extension '$defaultExtension'."
# file must have default extension - if it's not yet enabled then enable it
} elseif ($defaultExtension -ne ".config") {
Write-Host "`tRenaming $fileName to enable it"
Rename-EnableConfigFile -ExistingName $fileName -DefaultExtension $defaultExtension -ContainerPath $configPath
} else {
Write-Host "`tSkipping '$fileName' as it is already enabled"
}
}
}
"Disable" {
Write-Host "Disable: $fileName"
# there is an issue with the CSV - we could probably work around it, but better to have someone look at it
if (!$fileName.EndsWith($defaultExtension)) {
throw [System.Exception] "File '$fileName' does not have the expected extension '$defaultExtension'."
# if the file is enabled then disable it (we don't care about 'example' files, since they're already disabled)
} elseif ($defaultExtension -eq ".config") {
Write-Host "`tRenaming $fileName to disable it"
# disable the file
Rename-DisableConfigFile -ExistingName $fileName -ContainerPath $configPath
} else {
Write-Host "`tSkipping '$fileName' as it is already disabled"
}
}
default {
}
}
}
} catch {
Write-Host "ERROR: An error was encountered and script execution was terminated. Details below:"
$ErrorMessage = $_.Exception | Format-List -force
Write-Output $ErrorMessage
# if we are running in DryRun mode then we don't want to close the window
if (-not $DryRun) {
exit(1)
}
}
}
ConfiguationCsv.Settings.xml
This settings file is used for storing and sharing the information about the Sitecore-provided spreadsheet that the configuration script needs in order to correctly process the file and configure your instance(s). The file can be added to your repo and saved for repeated use. Each setting can also be overridden via invocation arguments of the configuration script.
<?xml version="1.0"?>
<!-- PARAMETERS
Defines settings to be used by the role configurator script and the
included testing tool -->
<Parameters>
<!-- CSV FILE Path
Path to the .CSV file converted from Sitecore's Excel file that
should be used for configuring the base Sitecore instance
Note: the original Excel file downloaded from Sitecore should
be converted to CSV and any extranous rows or content
that does not belong to the table data should be removed
(e.g. introductory titles or content, blank rows above
table, etc.) -->
<CsvFilePath>Config_Enable-Disable_Sitecore_8.1_upd3.csv</CsvFilePath>
<!-- ROLE COLUMN HEADERS
Defines the names of each column in the CSV that represents
the settings for a role -->
<RoleColumnHeaders>
<RoleColumnHeader>Content Delivery (CD)</RoleColumnHeader>
<RoleColumnHeader>Content Management (CM)</RoleColumnHeader>
<RoleColumnHeader>Processing</RoleColumnHeader>
<RoleColumnHeader>CM + Processing</RoleColumnHeader>
<RoleColumnHeader>Reporting</RoleColumnHeader>
</RoleColumnHeaders>
<!-- FILE NAME COLUMN HEADER
The name of the column in the CSV that contains the config
file name -->
<FileNameColumnHeader>Config file name</FileNameColumnHeader>
<!-- FILE PATH COLUMN HEADER
The name of the column in the CSV that contains the config
file's directory path -->
<FilePathColumnHeader>File path</FilePathColumnHeader>
<!-- DEFAULT EXTENSION COLUMN HEADER
The name of the column in the CSV that contains the config
file's default extension (config, disabled, example) -->
<DefaultExtensionColumnHeader>Config type</DefaultExtensionColumnHeader>
<!-- SEARCH PROVIDER COLUMN HEADER
The name of the column in the CSV that contains the search
provider that the config file should be included for -->
<SearchProviderColumnHeader>Search Provider Used</SearchProviderColumnHeader>
</Parameters>
Test-ConfigurationCsv.ps1
This is the configuration testing tool, which helps you to identify bugs/inconsistencies made by Sitecore in their provided configuration spreadsheet. This tool calls the configuration script in dryrun
mode, meaning that the script runs through all of the logic but no changes are actually made.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$False)] [string] $CsvSettingsFilePath = ".\ConfigurationCsv.Settings.xml",
[Parameter(Mandatory=$False)] [string] $ConfiguratorScriptFilePath = ".\Invoke-SitecoreRoleConfigurator.ps1"
)
# stop execution on all errors
$ErrorActionPreference = "Stop";
$VerbosePreference = "Silentlycontinue"
Write-Host "`r`nCONFIGURATION CSV TESTING TOOL`r`n`r`n"
Write-Host "To use this tool, ensure that you have configured the relevant settings in the $CsvSettingsFilePath file. The test will run once for each of the Roles that are added in the settings file. If any errors are encountered, resolve them in the CSV file and re-run the tool.`r`n"
Write-Host "Note that the most common error occurs when a 'Config Type' and 'Config File Name' in the CSV does not match up for a particular file (i.e. the file is of type 'disabled' but its name ends in '.config' or '.example'). For these issues, find the referenced file in the unmodified Sitecore source and update the CSV according to what you find.`r`n"
Write-Host "This tool runs in DryRun mode, only. No actual file-system operations will be performed`r`n`r`n"
Read-Host "Press [ENTER] to execute the tool"
# get the xml
[xml]$settings = Get-Content -Path $CsvSettingsFilePath
Write-Host "Executing tests..."
if (-not (Test-Path -Path $ConfiguratorScriptFilePath -PathType Leaf)) {
throw [System.IO.FileNotFoundException] "File '$ConfiguratorScriptFilePath' specified for parameter 'ConfiguratorScriptFilePath' was not found. This file is required and should be the file containing the Invoke-SitecoreRoleConfigurator commandlet."
}
# dot-source the script containing the Invoke-SitecoreRoleConfigurator commandlet so that we can call it
. $ConfiguratorScriptFilePath
# run the test for each role defined in the settings,
foreach ($role in $settings.Parameters.RoleColumnHeaders.RoleColumnHeader) {
# invoke with the DryRun flag to ensure that no changes are actually made; ApplicationFolderPath can be fake since we are running in DryRun mode (no changes will actually be made)
Invoke-SitecoreRoleConfigurator -ApplicationFolderPath "C:\fake" -RoleColumn "$role" -CsvSettingsFilePath "$CsvSettingsFilePath" -DryRun
}
# script will stop execution on all errors, so if we get here then no errors were encountered
Write-Host "`r`nTEST COMPLETED SUCCESSFULLY!`r`n"