diff --git a/Merge-DSCConfigurationData.psd1 b/Merge-DSCConfigurationData.psd1 index 21b94fb..88b0677 100644 --- a/Merge-DSCConfigurationData.psd1 +++ b/Merge-DSCConfigurationData.psd1 @@ -1,6 +1,6 @@ @{ RootModule = "Merge-DSCConfigurationData.psm1" - ModuleVersion = "1.0.2" + ModuleVersion = "1.1.0" GUID = "c1c7e70d-9049-4eaa-a3c9-44a424c35ef5" Author = "Torsten Brendgen" Copyright = "(c) Torsten Brendgen. All rights reserved." diff --git a/Private/Test-ConfigurationDataNodeSealed.ps1 b/Private/Test-ConfigurationDataNodeSealed.ps1 new file mode 100644 index 0000000..08190d5 --- /dev/null +++ b/Private/Test-ConfigurationDataNodeSealed.ps1 @@ -0,0 +1,14 @@ +function Test-ConfigurationDataNodeSealed { + [CmdletBinding()] + Param( + [Parameter(Mandatory=$true)] + [System.Collections.IDictionary] + $Node + ) + + if(-not (Test-ConfigurationDataDictionaryKey -Dictionary $Node -Key "Sealed")){ + return $false + } + + return [System.Management.Automation.LanguagePrimitives]::ConvertTo($Node["Sealed"], [bool]) +} diff --git a/Public/Merge-DSCConfigurationData.ps1 b/Public/Merge-DSCConfigurationData.ps1 index edcea57..d89480c 100644 --- a/Public/Merge-DSCConfigurationData.ps1 +++ b/Public/Merge-DSCConfigurationData.ps1 @@ -20,7 +20,11 @@ function Merge-DSCConfigurationData { [Parameter(Mandatory=$false, ParameterSetName="Path")] [switch] - $PassThru + $PassThru, + + [Parameter(Mandatory=$false, ParameterSetName="Data")] + [string] + $MergePath = '$' ) begin { @@ -37,6 +41,10 @@ function Merge-DSCConfigurationData { $Output = $Deployment } + if((Test-ConfigurationDataNodeSealed -Node $Template) -and $Deployment.Count -gt 0){ + throw "Configuration data path [$MergePath] is sealed and cannot be modified." + } + foreach($Property in $Template.GetEnumerator()){ if($Property.Name -eq "Metadata"){ Write-Verbose "Skipping metadata block during configuration data merge" @@ -47,7 +55,7 @@ function Merge-DSCConfigurationData { Write-Verbose "Key [$($Property.Name)] is a Dictionary" if(Test-ConfigurationDataDictionaryKey -Dictionary $Deployment -Key $Property.Name){ Write-Verbose "Key [$($Property.Name)] is present in Deployment Data" - $Output[$Property.Name] = Merge-DSCConfigurationData -Template $Template[$Property.Name] -Deployment $Deployment[$Property.Name] -Output $Output[$Property.Name] + $Output[$Property.Name] = Merge-DSCConfigurationData -Template $Template[$Property.Name] -Deployment $Deployment[$Property.Name] -Output $Output[$Property.Name] -MergePath "$MergePath.$($Property.Name)" }else{ Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data" $Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template[$Property.Name])) @@ -89,7 +97,7 @@ function Merge-DSCConfigurationData { if($MatchingDeploymentItems.Count -gt 0){ foreach($DeploymentItem in $MatchingDeploymentItems){ $OutputItem = @($Output[$Property.Name] | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $DeploymentItem -KeyNames $SearchKeyNames })[0] - Merge-DSCConfigurationData -Template $TemplateItem.Value -Deployment $DeploymentItem -Output $OutputItem | Out-Null + Merge-DSCConfigurationData -Template $TemplateItem.Value -Deployment $DeploymentItem -Output $OutputItem -MergePath "$MergePath.$($Property.Name)[$(Format-ConfigurationDataMergeKey -Item $DeploymentItem -KeyNames $SearchKeyNames)]" | Out-Null } }else{ if($TemplateItem.IsWildcard){ diff --git a/Tests/Extends.Tests.ps1 b/Tests/Extends.Tests.ps1 index abd5a2d..2959af6 100644 --- a/Tests/Extends.Tests.ps1 +++ b/Tests/Extends.Tests.ps1 @@ -347,4 +347,63 @@ Describe 'Merge-DSCConfigurationData Extends' { $Validation.IsStale | Should Be $true @($Validation.Issues | Where-Object { $_.Code -eq 'SourceChanged' }).Count | Should Be 1 } + + It 'prevents overriding a sealed parameter definition' { + $Template = @{ + Parameters = @{ + DomainNetBIOS = @{ + Type = 'string' + Value = 'CONTOSO' + Sealed = $true + } + } + } + + $Deployment = @{ + Parameters = @{ + DomainNetBIOS = @{ + Value = 'OTHER' + } + } + } + + { Merge-DSCConfigurationData -Template $Template -Deployment $Deployment } | Should Throw + } + + It 'prevents adding values below a sealed resource tree' { + $Template = @{ + Resources = @{ + NonNodeData = @{ + Services = @{ + SharePoint = @{ + Farm = @{ + ManagedAccounts = @{ + Sealed = $true + FarmAccount = "[parameters('FarmCredential')]" + } + } + } + } + } + } + } + + $Deployment = @{ + Resources = @{ + NonNodeData = @{ + Services = @{ + SharePoint = @{ + Farm = @{ + ManagedAccounts = @{ + SearchAccount = "[parameters('SearchCredential')]" + } + } + } + } + } + } + } + + { Merge-DSCConfigurationData -Template $Template -Deployment $Deployment } | Should Throw + } }