Add new functions for credential handling, node lookup, and context-aware parameter overrides; update module version to 1.2.0

This commit is contained in:
Torsten Brendgen
2026-08-18 22:45:05 +02:00
parent 4b67c74ac0
commit 5a07cded4e
10 changed files with 251 additions and 13 deletions
@@ -18,6 +18,10 @@ function Assert-ConfigurationDataParameterType {
$TypeName = ([string](Get-ConfigurationDataMapValue -Map $Definition -Key "Type")).ToLowerInvariant()
if(Test-ConfigurationDataExpression -Value $Value){
return
}
switch($TypeName){
"string" {
if(Test-ConfigurationDataSecretReference -Value $Value){
@@ -0,0 +1,26 @@
function ConvertTo-ConfigurationDataDomainCredential {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[System.Management.Automation.PSCredential]
$Credential,
[Parameter(Mandatory=$true)]
[string]
$Domain
)
if([string]::IsNullOrWhiteSpace($Domain)){
throw "Credential domain must not be empty."
}
$UserName = [string]$Credential.UserName
if($UserName.Contains("\") -or $UserName.Contains("@")){
return $Credential
}
return [System.Management.Automation.PSCredential]::new(
"$Domain\$UserName",
$Credential.Password
)
}
@@ -35,6 +35,71 @@ function Invoke-ConfigurationDataExpressionFunction {
throw "Function [$Name] expects 1 or 2 arguments, but received [$($Arguments.Count)]."
}
"parentkey" {
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 0
$Path = @($Context.CurrentPath)
if($Path.Count -lt 2){
throw "Function [$Name] requires the expression to be nested inside a parent map."
}
return [string]$Path[$Path.Count - 2]
}
"credentialwithdomain" {
Assert-ConfigurationDataExpressionArgumentCount -Name $Name -Arguments $Arguments -Count 2
if(-not ($Arguments[0] -is [System.Management.Automation.PSCredential])){
throw "Function [$Name] expects a PSCredential as first argument."
}
return ConvertTo-ConfigurationDataDomainCredential -Credential ([System.Management.Automation.PSCredential]$Arguments[0]) -Domain ([string]$Arguments[1])
}
"firstnodenamewhere" {
if($Arguments.Count -ne 1 -and $Arguments.Count -ne 2){
throw "Function [$Name] expects 1 or 2 arguments, but received [$($Arguments.Count)]."
}
$PropertyName = [string]$Arguments[0]
if([string]::IsNullOrWhiteSpace($PropertyName)){
throw "Function [$Name] requires a non-empty node property name."
}
$ExpectedValue = $true
if($Arguments.Count -eq 2){
$ExpectedValue = $Arguments[1]
}
$AllNodes = $null
if($Context.ConfigurationData.ContainsKey("AllNodes")){
$AllNodes = $Context.ConfigurationData.AllNodes
}elseif($Context.ConfigurationData.ContainsKey("Resources") -and
$Context.ConfigurationData.Resources -is [System.Collections.IDictionary] -and
$Context.ConfigurationData.Resources.ContainsKey("AllNodes")){
$AllNodes = $Context.ConfigurationData.Resources.AllNodes
}
foreach($Node in @($AllNodes)){
if($null -eq $Node -or -not ($Node -is [System.Collections.IDictionary])){
continue
}
if(-not $Node.ContainsKey($PropertyName)){
continue
}
if($Node[$PropertyName] -ne $ExpectedValue){
continue
}
if(-not $Node.ContainsKey("NodeName") -or [string]::IsNullOrWhiteSpace([string]$Node.NodeName)){
throw "Function [$Name] matched a node by [$PropertyName], but the node does not define [NodeName]."
}
return [string]$Node.NodeName
}
return $null
}
"concat" {
return (@($Arguments) | ForEach-Object { [string]$_ }) -join ""
}
@@ -40,7 +40,11 @@ function New-ConfigurationDataDummySecretValue {
$UserNameLeaf = "Credential"
}
$UserName = "DUMMY\$UserNameLeaf"
if($null -ne $Reference -and (Test-ConfigurationDataMapContainsKey -Map $Reference -Key "Domain")){
$UserName = $UserNameLeaf
}else{
$UserName = "DUMMY\$UserNameLeaf"
}
}
switch($ExpectedType.ToLowerInvariant()){
@@ -14,6 +14,7 @@ function New-ConfigurationDataResolutionContext {
ResolvingVariables = @{}
ReferenceCache = @{}
ResolvingReferences = @{}
CurrentPath = @()
}
if($ConfigurationData.ContainsKey("Parameters") -and $null -ne $ConfigurationData.Parameters){
@@ -15,6 +15,7 @@ function Resolve-ConfigurationDataParameterSecrets {
)
$ResolvedConfigurationData = $ConfigurationData.Clone()
$Context = New-ConfigurationDataResolutionContext -ConfigurationData $ResolvedConfigurationData
if($ResolvedConfigurationData.ContainsKey("Parameters")){
$ResolvedConfigurationData.Parameters = $ResolvedConfigurationData.Parameters.Clone()
@@ -36,10 +37,19 @@ function Resolve-ConfigurationDataParameterSecrets {
$ExpectedType = $TypeName.ToLowerInvariant()
foreach($ValueKey in @("Value", "DefaultValue")){
if((Test-ConfigurationDataMapContainsKey -Map $Definition -Key $ValueKey) -and (Test-ConfigurationDataSecretReference -Value $Definition[$ValueKey])){
$SecretReference = $Definition[$ValueKey]
if($UseDummySecrets){
$Definition[$ValueKey] = New-ConfigurationDataDummySecretValue -ExpectedType $ExpectedType -Reference $Definition[$ValueKey] -ParameterName $Parameter.Name
$Definition[$ValueKey] = New-ConfigurationDataDummySecretValue -ExpectedType $ExpectedType -Reference $SecretReference -ParameterName $Parameter.Name
}else{
$Definition[$ValueKey] = Resolve-ConfigurationDataSecretReference -Reference $Definition[$ValueKey] -ExpectedType $ExpectedType -ProviderSettings $ProviderSettings
$Definition[$ValueKey] = Resolve-ConfigurationDataSecretReference -Reference $SecretReference -ExpectedType $ExpectedType -ProviderSettings $ProviderSettings -Context $Context
}
if($ExpectedType -eq "credential" -and
$UseDummySecrets -and
(Test-ConfigurationDataMapContainsKey -Map $SecretReference -Key "Domain")){
$Domain = Get-ConfigurationDataMapValue -Map $SecretReference -Key "Domain"
$Domain = Resolve-ConfigurationDataValue -Value $Domain -Context $Context
$Definition[$ValueKey] = ConvertTo-ConfigurationDataDomainCredential -Credential $Definition[$ValueKey] -Domain ([string]$Domain)
}
}
}
@@ -12,7 +12,11 @@ function Resolve-ConfigurationDataSecretReference {
[Parameter(Mandatory=$false)]
[hashtable]
$ProviderSettings = @{}
$ProviderSettings = @{},
[Parameter(Mandatory=$false)]
[AllowNull()]
$Context = $null
)
$Provider = [string](Get-ConfigurationDataMapValue -Map $Reference -Key "Provider")
@@ -31,5 +35,20 @@ function Resolve-ConfigurationDataSecretReference {
$CurrentProviderSettings = $ProviderSettings[$ProviderDefinition.Name]
}
return & $ProviderDefinition.Resolver -Reference $Reference -ExpectedType $ExpectedType -ProviderSettings $CurrentProviderSettings
$SecretValue = & $ProviderDefinition.Resolver -Reference $Reference -ExpectedType $ExpectedType -ProviderSettings $CurrentProviderSettings
if($ExpectedType.ToLowerInvariant() -eq "credential" -and (Test-ConfigurationDataMapContainsKey -Map $Reference -Key "Domain")){
if(-not ($SecretValue -is [System.Management.Automation.PSCredential])){
throw "Secret reference [$($Reference.Name)] defines [Domain], but the resolved value is not a PSCredential."
}
$Domain = Get-ConfigurationDataMapValue -Map $Reference -Key "Domain"
if($null -ne $Context){
$Domain = Resolve-ConfigurationDataValue -Value $Domain -Context $Context
}
$SecretValue = ConvertTo-ConfigurationDataDomainCredential -Credential $SecretValue -Domain ([string]$Domain)
}
return $SecretValue
}
+15 -6
View File
@@ -5,7 +5,10 @@ function Resolve-ConfigurationDataValue {
$Value,
[Parameter(Mandatory=$true)]
$Context
$Context,
[object[]]
$Path = @()
)
if($null -eq $Value){
@@ -18,7 +21,7 @@ function Resolve-ConfigurationDataValue {
if($Entry.Name -eq "Sealed"){
continue
}
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context -Path (@($Path) + @($Entry.Name))
}
return $Resolved
}
@@ -29,21 +32,27 @@ function Resolve-ConfigurationDataValue {
if($Entry.Name -eq "Sealed"){
continue
}
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context
$Resolved[$Entry.Name] = Resolve-ConfigurationDataValue -Value $Entry.Value -Context $Context -Path (@($Path) + @($Entry.Name))
}
return $Resolved
}
if($Value -is [System.Array] -and $Value -isnot [string]){
$Resolved = @()
foreach($Item in $Value){
$Resolved += ,(Resolve-ConfigurationDataValue -Value $Item -Context $Context)
for($Index = 0; $Index -lt $Value.Count; $Index++){
$Resolved += ,(Resolve-ConfigurationDataValue -Value $Value[$Index] -Context $Context -Path (@($Path) + @($Index)))
}
return ,$Resolved
}
if($Value -is [string] -and (Test-ConfigurationDataExpression -Value $Value)){
return Resolve-ConfigurationDataExpression -Expression $Value -Context $Context
$PreviousPath = @($Context.CurrentPath)
$Context.CurrentPath = @($Path)
try {
return Resolve-ConfigurationDataExpression -Expression $Value -Context $Context
} finally {
$Context.CurrentPath = $PreviousPath
}
}
return $Value