initial Commit
This commit is contained in:
363
.tests/Resolve-DSCConfigurationData.Tests.ps1
Normal file
363
.tests/Resolve-DSCConfigurationData.Tests.ps1
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
$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
|
||||||
|
}
|
||||||
|
}
|
||||||
20
Private/Assert-ConfigurationDataExpressionArgumentCount.ps1
Normal file
20
Private/Assert-ConfigurationDataExpressionArgumentCount.ps1
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
function Assert-ConfigurationDataExpressionArgumentCount {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
[object[]]
|
||||||
|
$Arguments,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[int]
|
||||||
|
$Count
|
||||||
|
)
|
||||||
|
|
||||||
|
if(@($Arguments).Count -ne $Count){
|
||||||
|
throw "Function [$Name] expects [$Count] argument(s), but received [$(@($Arguments).Count)]."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
function Assert-ConfigurationDataExpressionMinimumArgumentCount {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
[object[]]
|
||||||
|
$Arguments,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[int]
|
||||||
|
$Count
|
||||||
|
)
|
||||||
|
|
||||||
|
if(@($Arguments).Count -lt $Count){
|
||||||
|
throw "Function [$Name] expects at least [$Count] argument(s), but received [$(@($Arguments).Count)]."
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Private/Assert-ConfigurationDataParameter.ps1
Normal file
67
Private/Assert-ConfigurationDataParameter.ps1
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
function Assert-ConfigurationDataParameter {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Definition,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
$Value,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[bool]
|
||||||
|
$HasValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Definition -Key "Deprecated"){
|
||||||
|
$Deprecated = Get-ConfigurationDataMapValue -Map $Definition -Key "Deprecated"
|
||||||
|
$Message = "Parameter [$Name] is deprecated."
|
||||||
|
|
||||||
|
if((Test-ConfigurationDataMap -Value $Deprecated) -and (Test-ConfigurationDataMapContainsKey -Map $Deprecated -Key "Message")){
|
||||||
|
$Message = Resolve-ConfigurationDataLocalizedText -Value (Get-ConfigurationDataMapValue -Map $Deprecated -Key "Message") -DefaultValue $Message
|
||||||
|
}elseif($Deprecated -is [string] -and -not [string]::IsNullOrWhiteSpace($Deprecated)){
|
||||||
|
$Message = $Deprecated
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Warning $Message
|
||||||
|
}
|
||||||
|
|
||||||
|
$Required = $false
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Definition -Key "Required"){
|
||||||
|
$Required = [bool](Get-ConfigurationDataMapValue -Map $Definition -Key "Required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Required -and ((-not $HasValue) -or (Test-ConfigurationDataValueIsEmpty -Value $Value))){
|
||||||
|
throw "Parameter [$Name] is required."
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not $HasValue -or $null -eq $Value){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert-ConfigurationDataParameterAllowedValue -Name $Name -Definition $Definition -Value $Value
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Definition -Key "MinLength"){
|
||||||
|
$MinLength = [int](Get-ConfigurationDataMapValue -Map $Definition -Key "MinLength")
|
||||||
|
if(([string]$Value).Length -lt $MinLength){
|
||||||
|
throw "Parameter [$Name] value length [$(([string]$Value).Length)] is less than MinLength [$MinLength]."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Definition -Key "MaxLength"){
|
||||||
|
$MaxLength = [int](Get-ConfigurationDataMapValue -Map $Definition -Key "MaxLength")
|
||||||
|
if(([string]$Value).Length -gt $MaxLength){
|
||||||
|
throw "Parameter [$Name] value length [$(([string]$Value).Length)] is greater than MaxLength [$MaxLength]."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Definition -Key "Pattern"){
|
||||||
|
$Pattern = [string](Get-ConfigurationDataMapValue -Map $Definition -Key "Pattern")
|
||||||
|
if(([string]$Value) -notmatch $Pattern){
|
||||||
|
throw "Parameter [$Name] value [$Value] does not match pattern [$Pattern]."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
Private/Assert-ConfigurationDataParameterAllowedValue.ps1
Normal file
27
Private/Assert-ConfigurationDataParameterAllowedValue.ps1
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
function Assert-ConfigurationDataParameterAllowedValue {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Definition,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataMapContainsKey -Map $Definition -Key "AllowedValues")){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$AllowedValues = @(Get-ConfigurationDataMapValue -Map $Definition -Key "AllowedValues")
|
||||||
|
if($AllowedValues.Count -eq 0){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if($AllowedValues -notcontains $Value){
|
||||||
|
throw "Parameter [$Name] value [$Value] is not allowed. Allowed values are: $($AllowedValues -join ', ')."
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Private/ConvertTo-ConfigurationDataExpressionBoolean.ps1
Normal file
33
Private/ConvertTo-ConfigurationDataExpressionBoolean.ps1
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
function ConvertTo-ConfigurationDataExpressionBoolean {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [bool]){
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [int]){
|
||||||
|
return $Value -ne 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [string]){
|
||||||
|
if($Value -match "^(?i:true|false)$"){
|
||||||
|
return [bool]::Parse($Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Value.Length -gt 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [System.Array]){
|
||||||
|
return @($Value).Count -gt 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return [bool]$Value
|
||||||
|
}
|
||||||
19
Private/ConvertTo-ConfigurationDataSafeName.ps1
Normal file
19
Private/ConvertTo-ConfigurationDataSafeName.ps1
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
function ConvertTo-ConfigurationDataSafeName {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$Value,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Separator
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
$SafeName = [regex]::Replace($Value.Trim(), "[^A-Za-z0-9_-]+", $Separator)
|
||||||
|
return Normalize-ConfigurationDataSeparator -Value $SafeName -Separator $Separator
|
||||||
|
}
|
||||||
13
Private/Get-ConfigurationDataMapValue.ps1
Normal file
13
Private/Get-ConfigurationDataMapValue.ps1
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
function Get-ConfigurationDataMapValue {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Map,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Key
|
||||||
|
)
|
||||||
|
|
||||||
|
return $Map[$Key]
|
||||||
|
}
|
||||||
38
Private/Invoke-ConfigurationDataExpression.ps1
Normal file
38
Private/Invoke-ConfigurationDataExpression.ps1
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
function Invoke-ConfigurationDataExpression {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Expression,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
$Expression = $Expression.Trim()
|
||||||
|
|
||||||
|
if($Expression -match "^'(.*)'$"){
|
||||||
|
return $Matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Expression -match "^-?\d+$"){
|
||||||
|
return [int]$Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Expression -match "^(?i:true|false)$"){
|
||||||
|
return [bool]::Parse($Expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Expression -notmatch "^([A-Za-z][A-Za-z0-9]*)\((.*)\)$"){
|
||||||
|
throw "Invalid configuration data expression [$Expression]."
|
||||||
|
}
|
||||||
|
|
||||||
|
$FunctionName = $Matches[1]
|
||||||
|
$ArgumentText = $Matches[2]
|
||||||
|
$Arguments = @()
|
||||||
|
foreach($Argument in @(Split-ConfigurationDataExpressionArguments -ArgumentText $ArgumentText)){
|
||||||
|
$Arguments += ,(Invoke-ConfigurationDataExpressionArgument -Argument $Argument -Context $Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Invoke-ConfigurationDataExpressionFunction -Name $FunctionName -Arguments $Arguments -Context $Context
|
||||||
|
}
|
||||||
35
Private/Invoke-ConfigurationDataExpressionArgument.ps1
Normal file
35
Private/Invoke-ConfigurationDataExpressionArgument.ps1
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
function Invoke-ConfigurationDataExpressionArgument {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$Argument,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Argument){
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$Argument = $Argument.Trim()
|
||||||
|
|
||||||
|
if($Argument -match "^'(.*)'$"){
|
||||||
|
return $Matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Argument -match "^-?\d+$"){
|
||||||
|
return [int]$Argument
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Argument -match "^(?i:true|false)$"){
|
||||||
|
return [bool]::Parse($Argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Argument -match "^[A-Za-z][A-Za-z0-9]*\(.*\)$"){
|
||||||
|
return Invoke-ConfigurationDataExpression -Expression $Argument -Context $Context
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Argument
|
||||||
|
}
|
||||||
279
Private/Invoke-ConfigurationDataExpressionFunction.ps1
Normal file
279
Private/Invoke-ConfigurationDataExpressionFunction.ps1
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
function Invoke-ConfigurationDataExpressionFunction {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
[object[]]
|
||||||
|
$Arguments,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
$FunctionName = $Name.ToLowerInvariant()
|
||||||
|
|
||||||
|
switch($FunctionName){
|
||||||
|
"parameters" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return Resolve-ConfigurationDataParameter -Name ([string]$Arguments[0]) -Context $Context
|
||||||
|
}
|
||||||
|
"variables" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return Resolve-ConfigurationDataVariable -Name ([string]$Arguments[0]) -Context $Context
|
||||||
|
}
|
||||||
|
"concat" {
|
||||||
|
return (@($Arguments) | ForEach-Object { [string]$_ }) -join ""
|
||||||
|
}
|
||||||
|
"format" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return [string]::Format([string]$Arguments[0], @($Arguments | Select-Object -Skip 1))
|
||||||
|
}
|
||||||
|
"coalesce" {
|
||||||
|
foreach($Argument in @($Arguments)){
|
||||||
|
if($null -ne $Argument -and [string]$Argument -ne ""){
|
||||||
|
return $Argument
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
"defaultifempty" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
if(Test-ConfigurationDataValueIsEmpty -Value $Arguments[0]){
|
||||||
|
return $Arguments[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Arguments[0]
|
||||||
|
}
|
||||||
|
"if" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 3
|
||||||
|
if(ConvertTo-ConfigurationDataExpressionBoolean -Value $Arguments[0]){
|
||||||
|
return $Arguments[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Arguments[2]
|
||||||
|
}
|
||||||
|
"equals" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return $Arguments[0] -eq $Arguments[1]
|
||||||
|
}
|
||||||
|
"notequals" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return $Arguments[0] -ne $Arguments[1]
|
||||||
|
}
|
||||||
|
"and" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
foreach($Argument in @($Arguments)){
|
||||||
|
if(-not (ConvertTo-ConfigurationDataExpressionBoolean -Value $Argument)){
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
"or" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
foreach($Argument in @($Arguments)){
|
||||||
|
if(ConvertTo-ConfigurationDataExpressionBoolean -Value $Argument){
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
"not" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return -not (ConvertTo-ConfigurationDataExpressionBoolean -Value $Arguments[0])
|
||||||
|
}
|
||||||
|
"tolower" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ([string]$Arguments[0]).ToLowerInvariant()
|
||||||
|
}
|
||||||
|
"toupper" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ([string]$Arguments[0]).ToUpperInvariant()
|
||||||
|
}
|
||||||
|
"firstindexof" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return $Arguments[0]
|
||||||
|
}
|
||||||
|
"lastindexof" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return $Arguments[$Arguments.Count - 1]
|
||||||
|
}
|
||||||
|
"indexof" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ([string]$Arguments[0])[([int]$Arguments[1])].ToString()
|
||||||
|
}
|
||||||
|
"substring" {
|
||||||
|
if($Arguments.Count -eq 2){
|
||||||
|
return ([string]$Arguments[0]).Substring([int]$Arguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Arguments.Count -eq 3){
|
||||||
|
return ([string]$Arguments[0]).Substring([int]$Arguments[1], [int]$Arguments[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Function [$Name] expects 2 or 3 arguments, but received [$($Arguments.Count)]."
|
||||||
|
}
|
||||||
|
"replace" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 3
|
||||||
|
return ([string]$Arguments[0]).Replace([string]$Arguments[1], [string]$Arguments[2])
|
||||||
|
}
|
||||||
|
"sanitizeName" {
|
||||||
|
if($Arguments.Count -eq 1){
|
||||||
|
return ConvertTo-ConfigurationDataSafeName -Value ([string]$Arguments[0]) -Separator "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Arguments.Count -eq 2){
|
||||||
|
return ConvertTo-ConfigurationDataSafeName -Value ([string]$Arguments[0]) -Separator ([string]$Arguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Function [$Name] expects 1 or 2 arguments, but received [$($Arguments.Count)]."
|
||||||
|
}
|
||||||
|
"normalizeseparator" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return Normalize-ConfigurationDataSeparator -Value ([string]$Arguments[0]) -Separator ([string]$Arguments[1])
|
||||||
|
}
|
||||||
|
"prefixifnotempty" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
if(Test-ConfigurationDataValueIsEmpty -Value $Arguments[0]){
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return ([string]$Arguments[1]) + ([string]$Arguments[0])
|
||||||
|
}
|
||||||
|
"suffixifnotempty" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
if(Test-ConfigurationDataValueIsEmpty -Value $Arguments[0]){
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return ([string]$Arguments[0]) + ([string]$Arguments[1])
|
||||||
|
}
|
||||||
|
"contains" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
if($Arguments[0] -is [System.Array] -and $Arguments[0] -isnot [string]){
|
||||||
|
return @($Arguments[0]) -contains $Arguments[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ([string]$Arguments[0]).Contains([string]$Arguments[1])
|
||||||
|
}
|
||||||
|
"startswith" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ([string]$Arguments[0]).StartsWith([string]$Arguments[1], [System.StringComparison]::OrdinalIgnoreCase)
|
||||||
|
}
|
||||||
|
"endswith" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ([string]$Arguments[0]).EndsWith([string]$Arguments[1], [System.StringComparison]::OrdinalIgnoreCase)
|
||||||
|
}
|
||||||
|
"split" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ,(([string]$Arguments[0]).Split([string[]]@([string]$Arguments[1]), [System.StringSplitOptions]::None))
|
||||||
|
}
|
||||||
|
"join" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return (@($Arguments[0]) | ForEach-Object { [string]$_ }) -join ([string]$Arguments[1])
|
||||||
|
}
|
||||||
|
"joinnotempty" {
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
$Separator = [string]$Arguments[0]
|
||||||
|
$Items = @()
|
||||||
|
|
||||||
|
foreach($Argument in @($Arguments | Select-Object -Skip 1)){
|
||||||
|
foreach($Item in @($Argument)){
|
||||||
|
if($null -ne $Item -and -not [string]::IsNullOrWhiteSpace([string]$Item)){
|
||||||
|
$Items += [string]$Item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Items -join $Separator
|
||||||
|
}
|
||||||
|
"take" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ,(@($Arguments[0]) | Select-Object -First ([int]$Arguments[1]))
|
||||||
|
}
|
||||||
|
"skip" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
|
||||||
|
return ,(@($Arguments[0]) | Select-Object -Skip ([int]$Arguments[1]))
|
||||||
|
}
|
||||||
|
"first" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return @($Arguments[0])[0]
|
||||||
|
}
|
||||||
|
"last" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
$Items = @($Arguments[0])
|
||||||
|
return $Items[$Items.Count - 1]
|
||||||
|
}
|
||||||
|
"unique" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ,(@($Arguments[0]) | Select-Object -Unique)
|
||||||
|
}
|
||||||
|
"sort" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ,(@($Arguments[0]) | Sort-Object)
|
||||||
|
}
|
||||||
|
"trim" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ([string]$Arguments[0]).Trim()
|
||||||
|
}
|
||||||
|
"trimstart" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ([string]$Arguments[0]).TrimStart()
|
||||||
|
}
|
||||||
|
"trimend" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
return ([string]$Arguments[0]).TrimEnd()
|
||||||
|
}
|
||||||
|
"padleft" {
|
||||||
|
if($Arguments.Count -eq 2){
|
||||||
|
return ([string]$Arguments[0]).PadLeft([int]$Arguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Arguments.Count -eq 3){
|
||||||
|
return ([string]$Arguments[0]).PadLeft([int]$Arguments[1], ([string]$Arguments[2])[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Function [$Name] expects 2 or 3 arguments, but received [$($Arguments.Count)]."
|
||||||
|
}
|
||||||
|
"padright" {
|
||||||
|
if($Arguments.Count -eq 2){
|
||||||
|
return ([string]$Arguments[0]).PadRight([int]$Arguments[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Arguments.Count -eq 3){
|
||||||
|
return ([string]$Arguments[0]).PadRight([int]$Arguments[1], ([string]$Arguments[2])[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "Function [$Name] expects 2 or 3 arguments, but received [$($Arguments.Count)]."
|
||||||
|
}
|
||||||
|
"length" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
if($Arguments[0] -is [System.Array] -and $Arguments[0] -isnot [string]){
|
||||||
|
return @($Arguments[0]).Count
|
||||||
|
}
|
||||||
|
|
||||||
|
return ([string]$Arguments[0]).Length
|
||||||
|
}
|
||||||
|
"empty" {
|
||||||
|
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 1
|
||||||
|
if($null -eq $Arguments[0]){
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Arguments[0] -is [System.Array] -and $Arguments[0] -isnot [string]){
|
||||||
|
return @($Arguments[0]).Count -eq 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return [string]$Arguments[0] -eq ""
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
throw "Unsupported configuration data expression function [$Name]."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
Private/New-ConfigurationDataResolutionContext.ps1
Normal file
44
Private/New-ConfigurationDataResolutionContext.ps1
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
function New-ConfigurationDataResolutionContext {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[System.Collections.Hashtable]
|
||||||
|
$ConfigurationData
|
||||||
|
)
|
||||||
|
|
||||||
|
$Context = [PSCustomObject]@{
|
||||||
|
Parameters = @{}
|
||||||
|
Variables = @{}
|
||||||
|
VariableDefinitions = @{}
|
||||||
|
ResolvingVariables = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($ConfigurationData.ContainsKey("Parameters") -and $null -ne $ConfigurationData.Parameters){
|
||||||
|
foreach($Entry in $ConfigurationData.Parameters.GetEnumerator()){
|
||||||
|
$Definition = $Entry.Value
|
||||||
|
|
||||||
|
$HasExplicitValue = (Test-ConfigurationDataMap -Value $Definition) -and (Test-ConfigurationDataMapContainsKey -Map $Definition -Key "Value")
|
||||||
|
$HasDefaultValue = (Test-ConfigurationDataMap -Value $Definition) -and (Test-ConfigurationDataMapContainsKey -Map $Definition -Key "DefaultValue")
|
||||||
|
|
||||||
|
if($HasExplicitValue){
|
||||||
|
$Context.Parameters[$Entry.Name] = Get-ConfigurationDataMapValue -Map $Definition -Key "Value"
|
||||||
|
}elseif($HasDefaultValue){
|
||||||
|
$Context.Parameters[$Entry.Name] = Get-ConfigurationDataMapValue -Map $Definition -Key "DefaultValue"
|
||||||
|
}else{
|
||||||
|
$Context.Parameters[$Entry.Name] = $Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataMap -Value $Definition){
|
||||||
|
Assert-ConfigurationDataParameter -Name $Entry.Name -Definition $Definition -Value $Context.Parameters[$Entry.Name] -HasValue:($HasExplicitValue -or $HasDefaultValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($ConfigurationData.ContainsKey("Variables") -and $null -ne $ConfigurationData.Variables){
|
||||||
|
foreach($Entry in $ConfigurationData.Variables.GetEnumerator()){
|
||||||
|
$Context.VariableDefinitions[$Entry.Name] = $Entry.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Context
|
||||||
|
}
|
||||||
26
Private/Normalize-ConfigurationDataSeparator.ps1
Normal file
26
Private/Normalize-ConfigurationDataSeparator.ps1
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
function Normalize-ConfigurationDataSeparator {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$Value,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Separator
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if([string]::IsNullOrEmpty($Separator)){
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
|
|
||||||
|
$EscapedSeparator = [regex]::Escape($Separator)
|
||||||
|
$Normalized = [regex]::Replace($Value, "($EscapedSeparator){2,}", $Separator)
|
||||||
|
$Normalized = $Normalized.Trim()
|
||||||
|
$Normalized = [regex]::Replace($Normalized, "^$EscapedSeparator|$EscapedSeparator$", "")
|
||||||
|
return $Normalized
|
||||||
|
}
|
||||||
16
Private/Resolve-ConfigurationDataExpression.ps1
Normal file
16
Private/Resolve-ConfigurationDataExpression.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
function Resolve-ConfigurationDataExpression {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Expression,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
$Body = $Expression.Trim()
|
||||||
|
$Body = $Body.Substring(1, $Body.Length - 2).Trim()
|
||||||
|
|
||||||
|
return Invoke-ConfigurationDataExpression -Expression $Body -Context $Context
|
||||||
|
}
|
||||||
50
Private/Resolve-ConfigurationDataLocalizedText.ps1
Normal file
50
Private/Resolve-ConfigurationDataLocalizedText.ps1
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
function Resolve-ConfigurationDataLocalizedText {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
$Value,
|
||||||
|
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$DefaultValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return $DefaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [string]){
|
||||||
|
if([string]::IsNullOrWhiteSpace($Value)){
|
||||||
|
return $DefaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataMap -Value $Value)){
|
||||||
|
return [string]$Value
|
||||||
|
}
|
||||||
|
|
||||||
|
$CultureNames = @(
|
||||||
|
[System.Globalization.CultureInfo]::CurrentUICulture.Name,
|
||||||
|
[System.Globalization.CultureInfo]::CurrentCulture.Name,
|
||||||
|
"en-US",
|
||||||
|
"de-DE",
|
||||||
|
"en",
|
||||||
|
"de"
|
||||||
|
) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -Unique
|
||||||
|
|
||||||
|
foreach($CultureName in $CultureNames){
|
||||||
|
if(Test-ConfigurationDataMapContainsKey -Map $Value -Key $CultureName){
|
||||||
|
return [string](Get-ConfigurationDataMapValue -Map $Value -Key $CultureName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($Entry in $Value.GetEnumerator()){
|
||||||
|
if($null -ne $Entry.Value -and -not [string]::IsNullOrWhiteSpace([string]$Entry.Value)){
|
||||||
|
return [string]$Entry.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $DefaultValue
|
||||||
|
}
|
||||||
17
Private/Resolve-ConfigurationDataParameter.ps1
Normal file
17
Private/Resolve-ConfigurationDataParameter.ps1
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
function Resolve-ConfigurationDataParameter {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
if(-not $Context.Parameters.ContainsKey($Name)){
|
||||||
|
throw "Parameter [$Name] is not defined."
|
||||||
|
}
|
||||||
|
|
||||||
|
return Resolve-ConfigurationDataValue -Value $Context.Parameters[$Name] -Context $Context
|
||||||
|
}
|
||||||
44
Private/Resolve-ConfigurationDataValue.ps1
Normal file
44
Private/Resolve-ConfigurationDataValue.ps1
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
function Resolve-ConfigurationDataValue {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
$Value,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [System.Collections.Specialized.OrderedDictionary]){
|
||||||
|
$Resolved = [ordered]@{}
|
||||||
|
foreach($Entry in $Value.GetEnumerator()){
|
||||||
|
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context
|
||||||
|
}
|
||||||
|
return $Resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [System.Collections.Hashtable]){
|
||||||
|
$Resolved = @{}
|
||||||
|
foreach($Entry in $Value.GetEnumerator()){
|
||||||
|
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context
|
||||||
|
}
|
||||||
|
return $Resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [System.Array] -and $Value -isnot [string]){
|
||||||
|
$Resolved = @()
|
||||||
|
foreach($Item in $Value){
|
||||||
|
$Resolved += ,(Resolve-ConfigurationDataValue -Value $Item -Context $Context)
|
||||||
|
}
|
||||||
|
return ,$Resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [string] -and (Test-ConfigurationDataExpression -Value $Value)){
|
||||||
|
return Resolve-ConfigurationDataExpression -Expression $Value -Context $Context
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
32
Private/Resolve-ConfigurationDataVariable.ps1
Normal file
32
Private/Resolve-ConfigurationDataVariable.ps1
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
function Resolve-ConfigurationDataVariable {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Context
|
||||||
|
)
|
||||||
|
|
||||||
|
if($Context.Variables.ContainsKey($Name)){
|
||||||
|
return $Context.Variables[$Name]
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not $Context.VariableDefinitions.ContainsKey($Name)){
|
||||||
|
throw "Variable [$Name] is not defined."
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Context.ResolvingVariables.ContainsKey($Name)){
|
||||||
|
throw "Circular variable reference detected for variable [$Name]."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Context.ResolvingVariables[$Name] = $true
|
||||||
|
try {
|
||||||
|
$Resolved = Resolve-ConfigurationDataValue -Value $Context.VariableDefinitions[$Name] -Context $Context
|
||||||
|
$Context.Variables[$Name] = $Resolved
|
||||||
|
return $Resolved
|
||||||
|
} finally {
|
||||||
|
$Context.ResolvingVariables.Remove($Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
47
Private/Split-ConfigurationDataExpressionArguments.ps1
Normal file
47
Private/Split-ConfigurationDataExpressionArguments.ps1
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
function Split-ConfigurationDataExpressionArguments {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$ArgumentText
|
||||||
|
)
|
||||||
|
|
||||||
|
if([string]::IsNullOrWhiteSpace($ArgumentText)){
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
|
||||||
|
$Arguments = @()
|
||||||
|
$Current = New-Object -TypeName System.Text.StringBuilder
|
||||||
|
$Depth = 0
|
||||||
|
$InString = $false
|
||||||
|
|
||||||
|
for($Index = 0; $Index -lt $ArgumentText.Length; $Index++){
|
||||||
|
$Character = $ArgumentText[$Index]
|
||||||
|
|
||||||
|
if($Character -eq "'"){
|
||||||
|
[void]$Current.Append($Character)
|
||||||
|
$InString = -not $InString
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not $InString){
|
||||||
|
if($Character -eq "("){
|
||||||
|
$Depth++
|
||||||
|
}elseif($Character -eq ")"){
|
||||||
|
$Depth--
|
||||||
|
}elseif($Character -eq "," -and $Depth -eq 0){
|
||||||
|
$Arguments += $Current.ToString().Trim()
|
||||||
|
[void]$Current.Clear()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[void]$Current.Append($Character)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Current.Length -gt 0){
|
||||||
|
$Arguments += $Current.ToString().Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Arguments
|
||||||
|
}
|
||||||
15
Private/Test-ConfigurationDataExpression.ps1
Normal file
15
Private/Test-ConfigurationDataExpression.ps1
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
function Test-ConfigurationDataExpression {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
if([string]::IsNullOrWhiteSpace($Value)){
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$Trimmed = $Value.Trim()
|
||||||
|
return $Trimmed.StartsWith("[") -and $Trimmed.EndsWith("]")
|
||||||
|
}
|
||||||
9
Private/Test-ConfigurationDataMap.ps1
Normal file
9
Private/Test-ConfigurationDataMap.ps1
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
function Test-ConfigurationDataMap {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
return ($Value -is [System.Collections.Hashtable]) -or ($Value -is [System.Collections.Specialized.OrderedDictionary])
|
||||||
|
}
|
||||||
21
Private/Test-ConfigurationDataMapContainsKey.ps1
Normal file
21
Private/Test-ConfigurationDataMapContainsKey.ps1
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
function Test-ConfigurationDataMapContainsKey {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Map,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Key
|
||||||
|
)
|
||||||
|
|
||||||
|
if($Map -is [System.Collections.Hashtable]){
|
||||||
|
return $Map.ContainsKey($Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Map -is [System.Collections.Specialized.OrderedDictionary]){
|
||||||
|
return $Map.Contains($Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return $false
|
||||||
|
}
|
||||||
21
Private/Test-ConfigurationDataValueIsEmpty.ps1
Normal file
21
Private/Test-ConfigurationDataValueIsEmpty.ps1
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
function Test-ConfigurationDataValueIsEmpty {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
if($null -eq $Value){
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [string]){
|
||||||
|
return [string]::IsNullOrWhiteSpace($Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Value -is [System.Array]){
|
||||||
|
return @($Value).Count -eq 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return $false
|
||||||
|
}
|
||||||
13
Public/Resolve-DSCConfigurationData.ps1
Normal file
13
Public/Resolve-DSCConfigurationData.ps1
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
function Resolve-DSCConfigurationData {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
|
||||||
|
[System.Collections.Hashtable]
|
||||||
|
$ConfigurationData
|
||||||
|
)
|
||||||
|
|
||||||
|
process {
|
||||||
|
$Context = New-ConfigurationDataResolutionContext -ConfigurationData $ConfigurationData
|
||||||
|
return Resolve-ConfigurationDataValue -Value $ConfigurationData -Context $Context
|
||||||
|
}
|
||||||
|
}
|
||||||
396
Readme.md
Normal file
396
Readme.md
Normal file
@@ -0,0 +1,396 @@
|
|||||||
|
# Resolve-DSCConfigurationData
|
||||||
|
|
||||||
|
`Resolve-DSCConfigurationData` resolves parameter, variable, and expression references in DSC configuration data.
|
||||||
|
|
||||||
|
Typical flow:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$merged = Merge-DSCConfigurationData -Template $service -Deployment $environment
|
||||||
|
$resolved = Resolve-DSCConfigurationData -ConfigurationData $merged
|
||||||
|
```
|
||||||
|
|
||||||
|
Expressions use an ARM-like syntax:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[parameters('DatabasePrefix')]"
|
||||||
|
"[variables('ServiceDbPrefix')]"
|
||||||
|
"[concat(parameters('DatabasePrefix'), '_', parameters('ServiceDatabaseSegment'))]"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameter Example
|
||||||
|
|
||||||
|
This block shows all currently supported parameter properties.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
@{
|
||||||
|
Parameters = @{
|
||||||
|
DatabasePrefix = @{
|
||||||
|
Type = 'string'
|
||||||
|
|
||||||
|
# Optional explicit value. If Value is present, it wins over DefaultValue.
|
||||||
|
Value = 'SharePoint'
|
||||||
|
|
||||||
|
# Used when Value is not present.
|
||||||
|
DefaultValue = 'SharePoint'
|
||||||
|
|
||||||
|
# If true, Value or DefaultValue must be present and not empty.
|
||||||
|
Required = $true
|
||||||
|
|
||||||
|
# Optional fixed set of valid values.
|
||||||
|
AllowedValues = @(
|
||||||
|
'SharePoint',
|
||||||
|
'ProjectServer',
|
||||||
|
'Search'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Optional string length validation.
|
||||||
|
MinLength = 2
|
||||||
|
MaxLength = 32
|
||||||
|
|
||||||
|
# Optional regex validation.
|
||||||
|
Pattern = '^[A-Za-z][A-Za-z0-9_-]*$'
|
||||||
|
|
||||||
|
# Metadata for later reporting/output tooling. The resolver does not mask values yet.
|
||||||
|
Sensitive = $false
|
||||||
|
|
||||||
|
# Emits a warning when the parameter is present.
|
||||||
|
Deprecated = @{
|
||||||
|
Message = @{
|
||||||
|
'de-DE' = 'Der Parameter [DatabasePrefix] ist veraltet. Verwende [SharePointDatabasePrefix].'
|
||||||
|
'en-US' = 'Parameter [DatabasePrefix] is deprecated. Use [SharePointDatabasePrefix].'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Metadata = @{
|
||||||
|
Description = @{
|
||||||
|
'de-DE' = 'Praefix fuer alle von der SharePoint-Farm angelegten Datenbanken.'
|
||||||
|
'en-US' = 'Prefix for all databases created by the SharePoint farm.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- `Value` wins over `DefaultValue`.
|
||||||
|
- `Required`, `AllowedValues`, `MinLength`, `MaxLength`, and `Pattern` are validated by the resolver.
|
||||||
|
- `Sensitive` is currently metadata only.
|
||||||
|
- `Deprecated.Message` can be a string or a localized hashtable.
|
||||||
|
- Optional string parameters can allow empty values with a pattern like `'^$|^[A-Za-z][A-Za-z0-9_-]*$'`.
|
||||||
|
|
||||||
|
## Variable Example
|
||||||
|
|
||||||
|
Variables may reference parameters and other variables. Nested variable references are supported. Circular references are rejected.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
@{
|
||||||
|
Parameters = @{
|
||||||
|
DatabasePrefix = @{
|
||||||
|
Type = 'string'
|
||||||
|
DefaultValue = 'SharePoint'
|
||||||
|
}
|
||||||
|
DomainLabel = @{
|
||||||
|
Type = 'string'
|
||||||
|
Value = 'LAN'
|
||||||
|
}
|
||||||
|
Landscape = @{
|
||||||
|
Type = 'string'
|
||||||
|
Value = 'Test'
|
||||||
|
AllowedValues = @(
|
||||||
|
'Prod',
|
||||||
|
'Test'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ServiceDatabaseSegment = @{
|
||||||
|
Type = 'string'
|
||||||
|
DefaultValue = 'Services'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Variables = @{
|
||||||
|
StageCode = "[if(equals(parameters('Landscape'), 'Test'), 'TST', 'PRD')]"
|
||||||
|
DatabasePrefix = "[joinNotEmpty('_', parameters('DatabasePrefix'), parameters('DomainLabel'), variables('StageCode'))]"
|
||||||
|
ServiceDbPrefix = "[joinNotEmpty('_', variables('DatabasePrefix'), parameters('ServiceDatabaseSegment'))]"
|
||||||
|
ConfigDbName = "[joinNotEmpty('_', variables('DatabasePrefix'), 'Farm_Config')]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
|
||||||
|
```text
|
||||||
|
StageCode : TST
|
||||||
|
DatabasePrefix : SharePoint_LAN_TST
|
||||||
|
ServiceDbPrefix : SharePoint_LAN_TST_Services
|
||||||
|
ConfigDbName : SharePoint_LAN_TST_Farm_Config
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[parameters('DatabasePrefix')]"
|
||||||
|
"[variables('ServiceDbPrefix')]"
|
||||||
|
```
|
||||||
|
|
||||||
|
`parameters(name)` returns the effective parameter value. `Value` is used before `DefaultValue`.
|
||||||
|
|
||||||
|
`variables(name)` resolves another variable. Variables may reference other variables.
|
||||||
|
|
||||||
|
### String Composition
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[concat('SharePoint', '_', 'Services')]"
|
||||||
|
# SharePoint_Services
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[format('{0}_{1}_{2}', parameters('DatabasePrefix'), parameters('DomainLabel'), parameters('Landscape'))]"
|
||||||
|
# SharePoint_LAN_Test
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[joinNotEmpty('_', parameters('DatabasePrefix'), parameters('DomainLabel'), '', 'Services')]"
|
||||||
|
# SharePoint_LAN_Services
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[defaultIfEmpty(parameters('DatabasePrefix'), 'SharePoint')]"
|
||||||
|
# SharePoint, when DatabasePrefix is empty
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[coalesce(parameters('CustomPrefix'), parameters('DatabasePrefix'), 'SharePoint')]"
|
||||||
|
# First non-empty value
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditions And Boolean Logic
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[if(equals(parameters('Landscape'), 'Test'), 'TST', 'PRD')]"
|
||||||
|
# TST
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[equals(parameters('Landscape'), 'Test')]"
|
||||||
|
"[notEquals(parameters('Landscape'), 'Prod')]"
|
||||||
|
"[and(equals(parameters('Landscape'), 'Test'), not(empty(parameters('DatabasePrefix'))))]"
|
||||||
|
"[or(equals(parameters('Landscape'), 'Prod'), equals(parameters('Landscape'), 'Test'))]"
|
||||||
|
"[not(empty(parameters('DatabasePrefix')))]"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Case And Text
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[toLower('BGW-LAN')]"
|
||||||
|
# bgw-lan
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[toUpper('bgw-lan')]"
|
||||||
|
# BGW-LAN
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[trim(' SharePoint ')]"
|
||||||
|
"[trimStart(' SharePoint')]"
|
||||||
|
"[trimEnd('SharePoint ')]"
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[replace('BGW-LAN', '-', '_')]"
|
||||||
|
# BGW_LAN
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[substring('SharePoint', 5, 5)]"
|
||||||
|
# Point
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[indexOf('BGW', 1)]"
|
||||||
|
# G
|
||||||
|
```
|
||||||
|
|
||||||
|
`firstIndexOf` and `lastIndexOf` return the first or last function argument:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[firstIndexOf('a', 'b', 'c')]"
|
||||||
|
# a
|
||||||
|
|
||||||
|
"[lastIndexOf('a', 'b', 'c')]"
|
||||||
|
# c
|
||||||
|
```
|
||||||
|
|
||||||
|
### Name Cleanup
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[sanitizeName(' SharePoint LAN/Test DB ')]"
|
||||||
|
# SharePoint_LAN_Test_DB
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[sanitizeName(' SharePoint LAN/Test DB ', '-')]"
|
||||||
|
# SharePoint-LAN-Test-DB
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[normalizeSeparator('__SharePoint___LAN_Test__', '_')]"
|
||||||
|
# SharePoint_LAN_Test
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[prefixIfNotEmpty('LAN', 'BGW-')]"
|
||||||
|
# BGW-LAN
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[suffixIfNotEmpty('SharePoint', '_DB')]"
|
||||||
|
# SharePoint_DB
|
||||||
|
```
|
||||||
|
|
||||||
|
### Collections
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[split(parameters('DomainFQDN'), '.')]"
|
||||||
|
# @('bgw-online', 'de')
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[join(split(parameters('DomainFQDN'), '.'), '_')]"
|
||||||
|
# bgw-online_de
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[first(split(parameters('DomainFQDN'), '.'))]"
|
||||||
|
# bgw-online
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[last(split(parameters('DomainFQDN'), '.'))]"
|
||||||
|
# de
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[take(split(parameters('DomainFQDN'), '.'), 1)]"
|
||||||
|
# @('bgw-online')
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[skip(split(parameters('DomainFQDN'), '.'), 1)]"
|
||||||
|
# @('de')
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[unique(split('SP.SP.SQL', '.'))]"
|
||||||
|
# @('SP', 'SQL')
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[sort(split('SQL.SP.APP', '.'))]"
|
||||||
|
# @('APP', 'SP', 'SQL')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Inspection
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[contains(parameters('DomainFQDN'), 'online')]"
|
||||||
|
# True
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[contains(split(parameters('DomainFQDN'), '.'), 'de')]"
|
||||||
|
# True
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[startsWith(parameters('DomainFQDN'), 'bgw')]"
|
||||||
|
# True
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[endsWith(parameters('DomainFQDN'), 'de')]"
|
||||||
|
# True
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[length(split(parameters('DomainFQDN'), '.'))]"
|
||||||
|
# 2
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[empty(parameters('OptionalValue'))]"
|
||||||
|
# True, when OptionalValue is empty
|
||||||
|
```
|
||||||
|
|
||||||
|
### Padding
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[padLeft('1', 2, '0')]"
|
||||||
|
# 01
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
"[padRight('SP', 4, '0')]"
|
||||||
|
# SP00
|
||||||
|
```
|
||||||
|
|
||||||
|
## Full Function List
|
||||||
|
|
||||||
|
- `parameters(name)`
|
||||||
|
- `variables(name)`
|
||||||
|
- `concat(value1, value2, ...)`
|
||||||
|
- `format(formatString, value1, value2, ...)`
|
||||||
|
- `coalesce(value1, value2, ...)`
|
||||||
|
- `defaultIfEmpty(value, defaultValue)`
|
||||||
|
- `if(condition, trueValue, falseValue)`
|
||||||
|
- `equals(left, right)`
|
||||||
|
- `notEquals(left, right)`
|
||||||
|
- `and(value1, value2, ...)`
|
||||||
|
- `or(value1, value2, ...)`
|
||||||
|
- `not(value)`
|
||||||
|
- `toLower(value)`
|
||||||
|
- `toUpper(value)`
|
||||||
|
- `firstIndexOf(value1, value2, ...)`
|
||||||
|
- `lastIndexOf(value1, value2, ...)`
|
||||||
|
- `indexOf(value, index)`
|
||||||
|
- `substring(value, startIndex)`
|
||||||
|
- `substring(value, startIndex, length)`
|
||||||
|
- `replace(value, oldValue, newValue)`
|
||||||
|
- `sanitizeName(value)`
|
||||||
|
- `sanitizeName(value, separator)`
|
||||||
|
- `normalizeSeparator(value, separator)`
|
||||||
|
- `prefixIfNotEmpty(value, prefix)`
|
||||||
|
- `suffixIfNotEmpty(value, suffix)`
|
||||||
|
- `contains(value, search)`
|
||||||
|
- `startsWith(value, search)`
|
||||||
|
- `endsWith(value, search)`
|
||||||
|
- `split(value, separator)`
|
||||||
|
- `join(array, separator)`
|
||||||
|
- `joinNotEmpty(separator, value1, value2, ...)`
|
||||||
|
- `take(array, count)`
|
||||||
|
- `skip(array, count)`
|
||||||
|
- `first(array)`
|
||||||
|
- `last(array)`
|
||||||
|
- `unique(array)`
|
||||||
|
- `sort(array)`
|
||||||
|
- `trim(value)`
|
||||||
|
- `trimStart(value)`
|
||||||
|
- `trimEnd(value)`
|
||||||
|
- `padLeft(value, totalWidth)`
|
||||||
|
- `padLeft(value, totalWidth, paddingCharacter)`
|
||||||
|
- `padRight(value, totalWidth)`
|
||||||
|
- `padRight(value, totalWidth, paddingCharacter)`
|
||||||
|
- `length(value)`
|
||||||
|
- `empty(value)`
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Run the tests:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Invoke-Pester -Script '.\PowerShell\Resolve-DSCConfigurationData\.tests\Resolve-DSCConfigurationData.Tests.ps1'
|
||||||
|
```
|
||||||
24
Resolve-DSCConfigurationData.psd1
Normal file
24
Resolve-DSCConfigurationData.psd1
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
@{
|
||||||
|
RootModule = "Resolve-DSCConfigurationData.psm1"
|
||||||
|
ModuleVersion = "1.0.0"
|
||||||
|
GUID = "1d6ba0d4-93d5-4b0f-94c7-bf10a30fe0e8"
|
||||||
|
Author = "Torsten Brendgen"
|
||||||
|
Copyright = "(c) Torsten Brendgen. All rights reserved."
|
||||||
|
Description = "Resolves parameters, variables, and expressions in DSC configuration data."
|
||||||
|
PowerShellVersion = "5.1"
|
||||||
|
FunctionsToExport = @(
|
||||||
|
"Resolve-DSCConfigurationData"
|
||||||
|
)
|
||||||
|
CmdletsToExport = @()
|
||||||
|
VariablesToExport = @()
|
||||||
|
AliasesToExport = @()
|
||||||
|
PrivateData = @{
|
||||||
|
PSData = @{
|
||||||
|
Tags = @(
|
||||||
|
"DSC",
|
||||||
|
"ConfigurationData"
|
||||||
|
)
|
||||||
|
ReleaseNotes = "Initial module layout."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Resolve-DSCConfigurationData.psm1
Normal file
13
Resolve-DSCConfigurationData.psm1
Normal 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 @(
|
||||||
|
"Resolve-DSCConfigurationData"
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user