Version 1.0.0 Release #1

Merged
Torsten merged 7 commits from dev into main 2026-04-21 13:52:34 +00:00
14 changed files with 493 additions and 321 deletions
Showing only changes of commit e10ab48bb4 - Show all commits

View File

@@ -1,327 +1,15 @@
function Merge-ConfigurationData { $ModuleRoot = $PSScriptRoot
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[System.Collections.Hashtable]
$Template,
[Parameter(Mandatory=$true)]
[System.Collections.Hashtable]
$Deployment,
[Parameter(Mandatory=$false)]
[System.Collections.Hashtable]
$Output
)
if($Output -eq $null){
$Output = $Deployment
}
foreach($Property in $Template.GetEnumerator()){ if([String]::IsNullOrWhiteSpace($ModuleRoot)){
if($Property.Value -is [System.Collections.Hashtable]){ throw "This compatibility loader must be dot-sourced from a file path. Use Import-Module './Merge-DSCConfigurationData.psd1' for module usage."
Write-Verbose "Key [$($Property.Name)] is a Hashtable"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Key [$($Property.Name)] is present in Deployment Data"
$Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name)
}else{
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
}
}elseif($Property.Value -is [System.Collections.Specialized.OrderedDictionary]){
Write-Verbose "Key [$($Property.Name)] is a Ordered Dictionary"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Key [$($Property.Name)] is present in Deployment Data"
$Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name)
}else{
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
}
}elseif($Property.Value -is [System.Array]){
Write-Verbose "$($Property.Name) is ein Array"
Write-Verbose "Total Items in Template Array [$($Property.Value.Count)]"
Write-Verbose "Total Items in Deployment Array [$($Deployment.$($Property.Name).Count)]"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Array is defined in Deployment"
$TemplateItems = for($i=0;$i -lt $Property.Value.Count; $i++){
$SearchKeyNames = @(Get-ConfigurationDataArrayMergeKeyNames -ArrayName $Property.Name -Item $Property.Value[$i])
[PSCustomObject]@{
Value = $Property.Value[$i]
SearchKeyNames = $SearchKeyNames
IsWildcard = Test-ConfigurationDataItemWildcard -Item $Property.Value[$i] -KeyNames $SearchKeyNames
}
}
$TemplateItems = @($TemplateItems | Where-Object { -not $_.IsWildcard }) + @($TemplateItems | Where-Object { $_.IsWildcard })
foreach($TemplateItem in $TemplateItems){
$SearchKeyNames = @($TemplateItem.SearchKeyNames)
if($SearchKeyNames.Count -eq 0){
Write-Verbose "No matching name key found for item in [$($Property.Name)]"
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
continue
}
if($TemplateItem.IsWildcard){
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemHasKeys -Item $_ -KeyNames $SearchKeyNames })
}else{
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $TemplateItem.Value -KeyNames $SearchKeyNames })
}
if($MatchingDeploymentItems.Count -gt 0){
foreach($DeploymentItem in $MatchingDeploymentItems){
$OutputItem = @($Output.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $DeploymentItem -KeyNames $SearchKeyNames })[0]
Merge-ConfigurationData -Template $TemplateItem.Value -Deployment $DeploymentItem -Output $OutputItem | Out-Null
}
}else{
if($TemplateItem.IsWildcard){
Write-Verbose "Wildcard item [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] in [$($Property.Name)] matched no deployment items"
}else{
Write-Verbose "Pair [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] not present"
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
}
}
}
}else{
Write-Verbose "Array is not defined in Deployment"
$Output.$($Property.Name) = Copy-ConfigurationDataValue -Value $Template.$($Property.Name)
}
}else{
Write-Verbose "$($Property.Name) is a String or Integer Value"
if($null -eq $Deployment.$($Property.Name)){
$Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template.($Property.Name)))
}elseif($Deployment.$($Property.Name) -ne $Property.Value){
}
}
}
return $Output
} }
function Copy-ConfigurationDataValue { $PrivatePath = Join-Path -Path $ModuleRoot -ChildPath "Private"
[CmdletBinding()] $PublicPath = Join-Path -Path $ModuleRoot -ChildPath "Public"
Param(
[AllowNull()]
$Value
)
if($null -eq $Value){ $Private = @(Get-ChildItem -Path $PrivatePath -Filter "*.ps1" -File -ErrorAction Stop | Sort-Object -Property FullName)
return $null $Public = @(Get-ChildItem -Path $PublicPath -Filter "*.ps1" -File -ErrorAction Stop | Sort-Object -Property FullName)
}
if($Value -is [System.Collections.Specialized.OrderedDictionary]){ foreach($File in @($Private + $Public)){
$Copy = [ordered]@{} . $File.FullName
foreach($Entry in $Value.GetEnumerator()){
$Copy[$Entry.Name] = Copy-ConfigurationDataValue -Value $Entry.Value
}
return $Copy
}
if($Value -is [System.Collections.Hashtable]){
$Copy = @{}
foreach($Entry in $Value.GetEnumerator()){
$Copy[$Entry.Name] = Copy-ConfigurationDataValue -Value $Entry.Value
}
return $Copy
}
if($Value -is [System.Array]){
$Copy = @()
foreach($Item in $Value){
$Copy += ,(Copy-ConfigurationDataValue -Value $Item)
}
return ,$Copy
}
return $Value
}
function Get-ConfigurationDataArraySearchItem {
[CmdletBinding()]
Param(
[AllowNull()]
$Item
)
if($null -eq $Item){
return $null
}
if(-not (
($Item -is [System.Collections.Hashtable]) -or
($Item -is [System.Collections.Specialized.OrderedDictionary])
)){
return $null
}
return @(
$Item.GetEnumerator() |
Where-Object { ($_.Value -is [String]) -and ($_.Name -like "*Name") } |
Select-Object -First 1
)[0]
}
function Get-ConfigurationDataArrayMergeKeyNames {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[String]
$ArrayName,
[AllowNull()]
$Item
)
$MergeKeyMap = @{
Instances = @('Name')
ConfigurationOptions = @('OptionName')
AdditionalScripts = @('ScriptName')
Templates = @('TemplateName')
AllNodes = @('NodeName')
Registry = @('Key','ValueName')
}
if($MergeKeyMap.ContainsKey($ArrayName)){
return $MergeKeyMap[$ArrayName]
}
$SearchItem = Get-ConfigurationDataArraySearchItem -Item $Item
if($null -ne $SearchItem){
return @($SearchItem.Name)
}
return @()
}
function Test-ConfigurationDataItemContainsKey {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String]
$KeyName
)
if($null -eq $Item){
return $false
}
if($Item -is [System.Collections.IDictionary]){
return $Item.Contains($KeyName)
}
return $null -ne $Item.PSObject.Properties[$KeyName]
}
function Get-ConfigurationDataItemValue {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String]
$KeyName
)
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyName)){
return $null
}
if($Item -is [System.Collections.IDictionary]){
return $Item[$KeyName]
}
return $Item.$KeyName
}
function Test-ConfigurationDataItemHasKeys {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
foreach($KeyName in $KeyNames){
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyName)){
return $false
}
}
return $true
}
function Test-ConfigurationDataItemKeyMatch {
[CmdletBinding()]
Param(
[AllowNull()]
$Left,
[AllowNull()]
$Right,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
if($KeyNames.Count -eq 0){
return $false
}
foreach($KeyName in $KeyNames){
if(-not (Test-ConfigurationDataItemContainsKey -Item $Left -KeyName $KeyName)){
return $false
}
if(-not (Test-ConfigurationDataItemContainsKey -Item $Right -KeyName $KeyName)){
return $false
}
if((Get-ConfigurationDataItemValue -Item $Left -KeyName $KeyName) -ne (Get-ConfigurationDataItemValue -Item $Right -KeyName $KeyName)){
return $false
}
}
return $true
}
function Test-ConfigurationDataItemWildcard {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
if($KeyNames.Count -ne 1){
return $false
}
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyNames[0])){
return $false
}
return (Get-ConfigurationDataItemValue -Item $Item -KeyName $KeyNames[0]) -eq "*"
}
function Format-ConfigurationDataMergeKey {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
$Pairs = foreach($KeyName in $KeyNames){
"$KeyName=$(Get-ConfigurationDataItemValue -Item $Item -KeyName $KeyName)"
}
return ($Pairs -join ", ")
} }

View File

@@ -0,0 +1,24 @@
@{
RootModule = "Merge-DSCConfigurationData.psm1"
ModuleVersion = "0.1.0"
GUID = "c1c7e70d-9049-4eaa-a3c9-44a424c35ef5"
Author = "Torsten Brendgen"
Copyright = "(c) Torsten Brendgen. All rights reserved."
Description = "Merges DSC configuration data from templates and deployment data."
PowerShellVersion = "5.1"
FunctionsToExport = @(
"Merge-ConfigurationData"
)
CmdletsToExport = @()
VariablesToExport = @()
AliasesToExport = @()
PrivateData = @{
PSData = @{
Tags = @(
"DSC",
"ConfigurationData"
)
ReleaseNotes = "Initial module layout."
}
}
}

View File

@@ -0,0 +1,13 @@
$PrivatePath = Join-Path -Path $PSScriptRoot -ChildPath "Private"
$PublicPath = Join-Path -Path $PSScriptRoot -ChildPath "Public"
$Private = @(Get-ChildItem -Path $PrivatePath -Filter "*.ps1" -File -ErrorAction Stop | Sort-Object -Property FullName)
$Public = @(Get-ChildItem -Path $PublicPath -Filter "*.ps1" -File -ErrorAction Stop | Sort-Object -Property FullName)
foreach($File in @($Private + $Public)){
. $File.FullName
}
Export-ModuleMember -Function @(
"Merge-ConfigurationData"
)

View File

@@ -0,0 +1,37 @@
function Copy-ConfigurationDataValue {
[CmdletBinding()]
Param(
[AllowNull()]
$Value
)
if($null -eq $Value){
return $null
}
if($Value -is [System.Collections.Specialized.OrderedDictionary]){
$Copy = [ordered]@{}
foreach($Entry in $Value.GetEnumerator()){
$Copy[$Entry.Name] = Copy-ConfigurationDataValue -Value $Entry.Value
}
return $Copy
}
if($Value -is [System.Collections.Hashtable]){
$Copy = @{}
foreach($Entry in $Value.GetEnumerator()){
$Copy[$Entry.Name] = Copy-ConfigurationDataValue -Value $Entry.Value
}
return $Copy
}
if($Value -is [System.Array]){
$Copy = @()
foreach($Item in $Value){
$Copy += ,(Copy-ConfigurationDataValue -Value $Item)
}
return ,$Copy
}
return $Value
}

View File

@@ -0,0 +1,16 @@
function Format-ConfigurationDataMergeKey {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
$Pairs = foreach($KeyName in $KeyNames){
"$KeyName=$(Get-ConfigurationDataItemValue -Item $Item -KeyName $KeyName)"
}
return ($Pairs -join ", ")
}

View File

@@ -0,0 +1,30 @@
function Get-ConfigurationDataArrayMergeKeyNames {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[String]
$ArrayName,
[AllowNull()]
$Item
)
$MergeKeyMap = @{
Instances = @("Name")
ConfigurationOptions = @("OptionName")
AdditionalScripts = @("ScriptName")
Templates = @("TemplateName")
AllNodes = @("NodeName")
Registry = @("Key","ValueName")
}
if($MergeKeyMap.ContainsKey($ArrayName)){
return $MergeKeyMap[$ArrayName]
}
$SearchItem = Get-ConfigurationDataArraySearchItem -Item $Item
if($null -ne $SearchItem){
return @($SearchItem.Name)
}
return @()
}

View File

@@ -0,0 +1,24 @@
function Get-ConfigurationDataArraySearchItem {
[CmdletBinding()]
Param(
[AllowNull()]
$Item
)
if($null -eq $Item){
return $null
}
if(-not (
($Item -is [System.Collections.Hashtable]) -or
($Item -is [System.Collections.Specialized.OrderedDictionary])
)){
return $null
}
return @(
$Item.GetEnumerator() |
Where-Object { ($_.Value -is [String]) -and ($_.Name -like "*Name") } |
Select-Object -First 1
)[0]
}

View File

@@ -0,0 +1,20 @@
function Get-ConfigurationDataItemValue {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String]
$KeyName
)
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyName)){
return $null
}
if($Item -is [System.Collections.IDictionary]){
return $Item[$KeyName]
}
return $Item.$KeyName
}

View File

@@ -0,0 +1,20 @@
function Test-ConfigurationDataItemContainsKey {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String]
$KeyName
)
if($null -eq $Item){
return $false
}
if($Item -is [System.Collections.IDictionary]){
return $Item.Contains($KeyName)
}
return $null -ne $Item.PSObject.Properties[$KeyName]
}

View File

@@ -0,0 +1,18 @@
function Test-ConfigurationDataItemHasKeys {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
foreach($KeyName in $KeyNames){
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyName)){
return $false
}
}
return $true
}

View File

@@ -0,0 +1,32 @@
function Test-ConfigurationDataItemKeyMatch {
[CmdletBinding()]
Param(
[AllowNull()]
$Left,
[AllowNull()]
$Right,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
if($KeyNames.Count -eq 0){
return $false
}
foreach($KeyName in $KeyNames){
if(-not (Test-ConfigurationDataItemContainsKey -Item $Left -KeyName $KeyName)){
return $false
}
if(-not (Test-ConfigurationDataItemContainsKey -Item $Right -KeyName $KeyName)){
return $false
}
if((Get-ConfigurationDataItemValue -Item $Left -KeyName $KeyName) -ne (Get-ConfigurationDataItemValue -Item $Right -KeyName $KeyName)){
return $false
}
}
return $true
}

View File

@@ -0,0 +1,20 @@
function Test-ConfigurationDataItemWildcard {
[CmdletBinding()]
Param(
[AllowNull()]
$Item,
[Parameter(Mandatory=$true)]
[String[]]
$KeyNames
)
if($KeyNames.Count -ne 1){
return $false
}
if(-not (Test-ConfigurationDataItemContainsKey -Item $Item -KeyName $KeyNames[0])){
return $false
}
return (Get-ConfigurationDataItemValue -Item $Item -KeyName $KeyNames[0]) -eq "*"
}

View File

@@ -0,0 +1,98 @@
function Merge-ConfigurationData {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[System.Collections.Hashtable]
$Template,
[Parameter(Mandatory=$true)]
[System.Collections.Hashtable]
$Deployment,
[Parameter(Mandatory=$false)]
[System.Collections.Hashtable]
$Output
)
if($Output -eq $null){
$Output = $Deployment
}
foreach($Property in $Template.GetEnumerator()){
if($Property.Value -is [System.Collections.Hashtable]){
Write-Verbose "Key [$($Property.Name)] is a Hashtable"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Key [$($Property.Name)] is present in Deployment Data"
$Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name)
}else{
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
}
}elseif($Property.Value -is [System.Collections.Specialized.OrderedDictionary]){
Write-Verbose "Key [$($Property.Name)] is a Ordered Dictionary"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Key [$($Property.Name)] is present in Deployment Data"
$Output.($Property.Name) = Merge-ConfigurationData -Template $Template.$($Property.Name) -Deployment $Deployment.$($Property.Name) -Output $Output.$($Property.Name)
}else{
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
}
}elseif($Property.Value -is [System.Array]){
Write-Verbose "$($Property.Name) is ein Array"
Write-Verbose "Total Items in Template Array [$($Property.Value.Count)]"
Write-Verbose "Total Items in Deployment Array [$($Deployment.$($Property.Name).Count)]"
if($null -ne $Deployment.$($Property.Name)){
Write-Verbose "Array is defined in Deployment"
$TemplateItems = for($i=0;$i -lt $Property.Value.Count; $i++){
$SearchKeyNames = @(Get-ConfigurationDataArrayMergeKeyNames -ArrayName $Property.Name -Item $Property.Value[$i])
[PSCustomObject]@{
Value = $Property.Value[$i]
SearchKeyNames = $SearchKeyNames
IsWildcard = Test-ConfigurationDataItemWildcard -Item $Property.Value[$i] -KeyNames $SearchKeyNames
}
}
$TemplateItems = @($TemplateItems | Where-Object { -not $_.IsWildcard }) + @($TemplateItems | Where-Object { $_.IsWildcard })
foreach($TemplateItem in $TemplateItems){
$SearchKeyNames = @($TemplateItem.SearchKeyNames)
if($SearchKeyNames.Count -eq 0){
Write-Verbose "No matching name key found for item in [$($Property.Name)]"
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
continue
}
if($TemplateItem.IsWildcard){
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemHasKeys -Item $_ -KeyNames $SearchKeyNames })
}else{
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $TemplateItem.Value -KeyNames $SearchKeyNames })
}
if($MatchingDeploymentItems.Count -gt 0){
foreach($DeploymentItem in $MatchingDeploymentItems){
$OutputItem = @($Output.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $DeploymentItem -KeyNames $SearchKeyNames })[0]
Merge-ConfigurationData -Template $TemplateItem.Value -Deployment $DeploymentItem -Output $OutputItem | Out-Null
}
}else{
if($TemplateItem.IsWildcard){
Write-Verbose "Wildcard item [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] in [$($Property.Name)] matched no deployment items"
}else{
Write-Verbose "Pair [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] not present"
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
}
}
}
}else{
Write-Verbose "Array is not defined in Deployment"
$Output.$($Property.Name) = Copy-ConfigurationDataValue -Value $Template.$($Property.Name)
}
}else{
Write-Verbose "$($Property.Name) is a String or Integer Value"
if($null -eq $Deployment.$($Property.Name)){
$Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template.($Property.Name)))
}elseif($Deployment.$($Property.Name) -ne $Property.Value){
}
}
}
return $Output
}

View File

@@ -0,0 +1,132 @@
$script:ModuleRoot = Split-Path -Parent $PSScriptRoot
$script:SampleRoot = Join-Path -Path $script:ModuleRoot -ChildPath ".sample"
Import-Module (Join-Path -Path $script:ModuleRoot -ChildPath "Merge-DSCConfigurationData.psd1") -Force
Describe "Merge-ConfigurationData" {
It "merges wildcard instance templates into all deployment instances" {
$Template = Import-PowerShellDataFile (Join-Path -Path $script:SampleRoot -ChildPath "Template.psd1")
$Deployment = Import-PowerShellDataFile (Join-Path -Path $script:SampleRoot -ChildPath "Deployment.psd1")
$Result = Merge-ConfigurationData -Template $Template -Deployment $Deployment
$Instances = @($Result.NonNodeData.Services.SQLServer.Instances)
$Instances.Count | Should Be 2
($Instances.Name -contains "*") | Should Be $false
foreach($Name in @("MSSQLSERVER", "MSSQLSERVERTEST")){
$Instance = $Instances | Where-Object { $_.Name -eq $Name }
$Instance | Should Not BeNullOrEmpty
$Instance.Features | Should Be "SQLENGINE,FULLTEXT"
$Instance.ConfigurationOptions.Count | Should Be 4
$Instance.AdditionalScripts.Count | Should Be 6
$Instance.Memory | Should Not BeNullOrEmpty
$Instance.Directories | Should Not BeNullOrEmpty
}
}
It "does not merge an exact instance template into another instance name" {
$Template = @{
NonNodeData = @{
Services = @{
SQLServer = @{
Instances = @(
@{
Name = "MSSQLSERVER"
Marker = "exact-only"
}
)
}
}
}
}
$Deployment = @{
NonNodeData = @{
Services = @{
SQLServer = @{
Instances = @(
@{ Name = "MSSQLSERVER" },
@{ Name = "MSSQLSERVERTEST" }
)
}
}
}
}
$Result = Merge-ConfigurationData -Template $Template -Deployment $Deployment
$Instances = @($Result.NonNodeData.Services.SQLServer.Instances)
($Instances | Where-Object { $_.Name -eq "MSSQLSERVER" }).Marker | Should Be "exact-only"
($Instances | Where-Object { $_.Name -eq "MSSQLSERVERTEST" }).Marker | Should BeNullOrEmpty
}
It "uses the name-key fallback for unknown arrays" {
$Template = @{
Databases = @(
@{
DatabaseName = "AppDb"
RecoveryModel = "Full"
}
)
}
$Deployment = @{
Databases = @(
@{
DatabaseName = "AppDb"
Owner = "dbo"
},
@{
DatabaseName = "LogDb"
Owner = "dbo"
}
)
}
$Result = Merge-ConfigurationData -Template $Template -Deployment $Deployment
$Databases = @($Result.Databases)
($Databases | Where-Object { $_.DatabaseName -eq "AppDb" }).RecoveryModel | Should Be "Full"
($Databases | Where-Object { $_.DatabaseName -eq "LogDb" }).RecoveryModel | Should BeNullOrEmpty
}
It "uses Key and ValueName together for registry array merges" {
$Template = @{
Basic = @{
Registry = @(
@{
Key = "K1"
ValueName = "Enabled"
Default = "Template-K1"
},
@{
Key = "K2"
ValueName = "Enabled"
Default = "Template-K2"
}
)
}
}
$Deployment = @{
Basic = @{
Registry = @(
@{
Key = "K1"
ValueName = "Enabled"
ValueData = "Deployment-K1"
}
)
}
}
$Result = Merge-ConfigurationData -Template $Template -Deployment $Deployment
$Registry = @($Result.Basic.Registry)
($Registry | Where-Object { $_.Key -eq "K1" }).Default | Should Be "Template-K1"
($Registry | Where-Object { $_.Key -eq "K1" }).ValueData | Should Be "Deployment-K1"
($Registry | Where-Object { $_.Key -eq "K2" }).Default | Should Be "Template-K2"
}
}