$script:ModuleRoot = Split-Path -Path $PSScriptRoot -Parent Import-Module (Join-Path -Path $script:ModuleRoot -ChildPath "Resolve-DSCConfigurationData.psd1") -Force Describe "Resolve-DSCConfigurationData" { It "resolves parameters using Value before DefaultValue" { $ConfigurationData = @{ Parameters = @{ Name = @{ DefaultValue = "Default" Value = "Deployment" } } Resources = @{ Value = "[parameters('Name')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Value | Should Be "Deployment" } It "allows parameter values listed in AllowedValues" { $ConfigurationData = @{ Parameters = @{ Stage = @{ Value = "Test" AllowedValues = @( "Install", "Test", "Release" ) } } Resources = @{ Stage = "[parameters('Stage')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Stage | Should Be "Test" } It "validates DefaultValue against AllowedValues when Value is not set" { $ConfigurationData = @{ Parameters = @{ Stage = @{ DefaultValue = "Release" AllowedValues = @( "Install", "Test", "Release" ) } } Resources = @{ Stage = "[parameters('Stage')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Stage | Should Be "Release" } It "throws when a parameter value is not listed in AllowedValues" { $ConfigurationData = @{ Parameters = @{ Stage = @{ Value = "Production" AllowedValues = @( "Install", "Test", "Release" ) } } Resources = @{ Stage = "[parameters('Stage')]" } } { Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData } | Should Throw } It "validates required parameters" { $ConfigurationData = @{ Parameters = @{ DatabasePrefix = @{ Type = "string" Required = $true } } } { Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData } | Should Throw } It "validates parameter length constraints" { $ConfigurationData = @{ Parameters = @{ DatabasePrefix = @{ Value = "S" MinLength = 2 MaxLength = 10 } } } { Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData } | Should Throw } It "validates parameter patterns" { $ConfigurationData = @{ Parameters = @{ DatabasePrefix = @{ Value = "Share Point" Pattern = "^[A-Za-z][A-Za-z0-9_-]*$" } } } { Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData } | Should Throw } It "supports localized deprecated parameter messages" { $ConfigurationData = @{ Parameters = @{ OldDatabasePrefix = @{ Value = "SharePoint" Deprecated = @{ Message = @{ "de-DE" = "Der Parameter [OldDatabasePrefix] ist veraltet. Verwende [DatabasePrefix]." "en-US" = "Parameter [OldDatabasePrefix] is deprecated. Use [DatabasePrefix]." } } } } Resources = @{ Value = "[parameters('OldDatabasePrefix')]" } } $Warnings = @() $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData -WarningVariable Warnings 3>$null $Result.Resources.Value | Should Be "SharePoint" $Warnings.Count | Should Be 1 ([string]$Warnings[0]) | Should Match "OldDatabasePrefix" } It "resolves variables that reference parameters" { $ConfigurationData = @{ Parameters = @{ Prefix = @{ Value = "SharePoint" } } Variables = @{ ConfigDbName = "[concat(parameters('Prefix'), '_Farm_Config')]" } Resources = @{ DatabaseName = "[variables('ConfigDbName')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Variables.ConfigDbName | Should Be "SharePoint_Farm_Config" $Result.Resources.DatabaseName | Should Be "SharePoint_Farm_Config" } It "resolves nested functions" { $ConfigurationData = @{ Parameters = @{ Prefix = @{ Value = "sharepoint" } } Resources = @{ Name = "[concat(toUpper(parameters('Prefix')), '_Services')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Name | Should Be "SHAREPOINT_Services" } It "resolves string helper functions" { $ConfigurationData = @{ Resources = @{ Lower = "[toLower('BGW-LAN')]" Upper = "[toUpper('bgw-lan')]" First = "[firstIndexOf('a', 'b', 'c')]" Last = "[lastIndexOf('a', 'b', 'c')]" Index = "[indexOf('BGW', 1)]" Substring = "[substring('SharePoint', 5, 5)]" Replace = "[replace('BGW-LAN', '-', '_')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Lower | Should Be "bgw-lan" $Result.Resources.Upper | Should Be "BGW-LAN" $Result.Resources.First | Should Be "a" $Result.Resources.Last | Should Be "c" $Result.Resources.Index | Should Be "G" $Result.Resources.Substring | Should Be "Point" $Result.Resources.Replace | Should Be "BGW_LAN" } It "resolves formatting, fallback, and conditional functions" { $ConfigurationData = @{ Parameters = @{ DatabasePrefix = @{ Value = "SharePoint" } DomainLabel = @{ Value = "LAN" } Stage = @{ Value = "Test" } OptionalValue = @{ Value = "" } } Resources = @{ Formatted = "[format('{0}_{1}_{2}', parameters('DatabasePrefix'), parameters('DomainLabel'), parameters('Stage'))]" Fallback = "[coalesce(parameters('OptionalValue'), 'DefaultValue')]" Conditional = "[if(equals(parameters('Stage'), 'Test'), 'TST', 'PRD')]" NotEquals = "[notEquals(parameters('Stage'), 'Prod')]" AndValue = "[and(equals(parameters('Stage'), 'Test'), not(empty(parameters('DatabasePrefix'))))]" OrValue = "[or(equals(parameters('Stage'), 'Prod'), equals(parameters('Stage'), 'Test'))]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Formatted | Should Be "SharePoint_LAN_Test" $Result.Resources.Fallback | Should Be "DefaultValue" $Result.Resources.Conditional | Should Be "TST" $Result.Resources.NotEquals | Should Be $true $Result.Resources.AndValue | Should Be $true $Result.Resources.OrValue | Should Be $true } It "resolves collection and string inspection functions" { $ConfigurationData = @{ Parameters = @{ DomainFQDN = @{ Value = "bgw-online.de" } } Resources = @{ Split = "[split(parameters('DomainFQDN'), '.')]" Joined = "[join(split(parameters('DomainFQDN'), '.'), '_')]" JoinedNotEmpty = "[joinNotEmpty('_', 'SharePoint', '', 'LAN', 'Test', '', 'Services')]" Take = "[join(take(split(parameters('DomainFQDN'), '.'), 1), '_')]" Skip = "[join(skip(split(parameters('DomainFQDN'), '.'), 1), '_')]" First = "[first(split(parameters('DomainFQDN'), '.'))]" Last = "[last(split(parameters('DomainFQDN'), '.'))]" Unique = "[join(unique(split('SP.SP.SQL', '.')), '_')]" Sort = "[join(sort(split('SQL.SP.APP', '.')), '_')]" ContainsString = "[contains(parameters('DomainFQDN'), 'online')]" ContainsArray = "[contains(split(parameters('DomainFQDN'), '.'), 'de')]" StartsWith = "[startsWith(parameters('DomainFQDN'), 'bgw')]" EndsWith = "[endsWith(parameters('DomainFQDN'), 'DE')]" Length = "[length(split(parameters('DomainFQDN'), '.'))]" Empty = "[empty('')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Split[0] | Should Be "bgw-online" $Result.Resources.Split[1] | Should Be "de" $Result.Resources.Joined | Should Be "bgw-online_de" $Result.Resources.JoinedNotEmpty | Should Be "SharePoint_LAN_Test_Services" $Result.Resources.Take | Should Be "bgw-online" $Result.Resources.Skip | Should Be "de" $Result.Resources.First | Should Be "bgw-online" $Result.Resources.Last | Should Be "de" $Result.Resources.Unique | Should Be "SP_SQL" $Result.Resources.Sort | Should Be "APP_SP_SQL" $Result.Resources.ContainsString | Should Be $true $Result.Resources.ContainsArray | Should Be $true $Result.Resources.StartsWith | Should Be $true $Result.Resources.EndsWith | Should Be $true $Result.Resources.Length | Should Be 2 $Result.Resources.Empty | Should Be $true } It "resolves trim and padding functions" { $ConfigurationData = @{ Resources = @{ Trim = "[trim(' SharePoint ')]" TrimStart = "[trimStart(' SharePoint')]" TrimEnd = "[trimEnd('SharePoint ')]" PadLeft = "[padLeft('1', 2, '0')]" PadRight = "[padRight('SP', 4, '0')]" DefaultIfEmpty = "[defaultIfEmpty('', 'SharePoint')]" Sanitized = "[sanitizeName(' SharePoint LAN/Test DB ')]" Normalized = "[normalizeSeparator('__SharePoint___LAN_Test__', '_')]" Prefix = "[prefixIfNotEmpty('LAN', 'BGW-')]" EmptyPrefix = "[prefixIfNotEmpty('', 'BGW-')]" Suffix = "[suffixIfNotEmpty('SharePoint', '_DB')]" EmptySuffix = "[suffixIfNotEmpty('', '_DB')]" } } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.Resources.Trim | Should Be "SharePoint" $Result.Resources.TrimStart | Should Be "SharePoint" $Result.Resources.TrimEnd | Should Be "SharePoint" $Result.Resources.PadLeft | Should Be "01" $Result.Resources.PadRight | Should Be "SP00" $Result.Resources.DefaultIfEmpty | Should Be "SharePoint" $Result.Resources.Sanitized | Should Be "SharePoint_LAN_Test_DB" $Result.Resources.Normalized | Should Be "SharePoint_LAN_Test" $Result.Resources.Prefix | Should Be "BGW-LAN" $Result.Resources.EmptyPrefix | Should Be "" $Result.Resources.Suffix | Should Be "SharePoint_DB" $Result.Resources.EmptySuffix | Should Be "" } It "resolves values inside arrays recursively" { $ConfigurationData = @{ Parameters = @{ NodeName = @{ Value = "SP01" } } AllNodes = @( @{ NodeName = "[parameters('NodeName')]" } ) } $Result = Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData $Result.AllNodes[0].NodeName | Should Be "SP01" } It "throws for circular variables" { $ConfigurationData = @{ Variables = @{ A = "[variables('B')]" B = "[variables('A')]" } Resources = @{ Value = "[variables('A')]" } } { Resolve-DSCConfigurationData -ConfigurationData $ConfigurationData } | Should Throw } }