Enhance configuration data validation and add new utility functions
- Added validation for empty values in Assert-ConfigurationDataParameter. - Introduced Assert-ConfigurationDataSecretReference for secret reference validation. - Implemented Test-ConfigurationDataExpressionParentheses to validate expression syntax. - Added Test-ConfigurationDataMissingReferenceError to check for missing parameter or variable definitions. - Updated Invoke-ConfigurationDataExpression to handle new validation logic. - Revised Readme.md to reflect changes in secret reference handling.
This commit is contained in:
@@ -42,6 +42,10 @@ function Assert-ConfigurationDataParameter {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((Test-ConfigurationDataValueIsEmpty -Value $Value) -and (-not $Required)){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Assert-ConfigurationDataParameterType -Name $Name -Definition $Definition -Value $Value
|
Assert-ConfigurationDataParameterType -Name $Name -Definition $Definition -Value $Value
|
||||||
Assert-ConfigurationDataParameterAllowedValue -Name $Name -Definition $Definition -Value $Value
|
Assert-ConfigurationDataParameterAllowedValue -Name $Name -Definition $Definition -Value $Value
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,15 @@ function Assert-ConfigurationDataParameterType {
|
|||||||
if(($Value -isnot [string]) -and ($Value -isnot [System.Security.SecureString]) -and (-not (Test-ConfigurationDataMap -Value $Value))){
|
if(($Value -isnot [string]) -and ($Value -isnot [System.Security.SecureString]) -and (-not (Test-ConfigurationDataMap -Value $Value))){
|
||||||
throw "Parameter [$Name] expects type [secureString], but received [$($Value.GetType().Name)]."
|
throw "Parameter [$Name] expects type [secureString], but received [$($Value.GetType().Name)]."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert-ConfigurationDataSecretReference -Name $Name -TypeName "securestring" -Value $Value
|
||||||
}
|
}
|
||||||
"credential" {
|
"credential" {
|
||||||
if(($Value -isnot [System.Management.Automation.PSCredential]) -and (-not (Test-ConfigurationDataMap -Value $Value))){
|
if(($Value -isnot [System.Management.Automation.PSCredential]) -and (-not (Test-ConfigurationDataMap -Value $Value))){
|
||||||
throw "Parameter [$Name] expects type [credential], but received [$($Value.GetType().Name)]."
|
throw "Parameter [$Name] expects type [credential], but received [$($Value.GetType().Name)]."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert-ConfigurationDataSecretReference -Name $Name -TypeName "credential" -Value $Value
|
||||||
}
|
}
|
||||||
default {
|
default {
|
||||||
throw "Parameter [$Name] uses unsupported type [$TypeName]."
|
throw "Parameter [$Name] uses unsupported type [$TypeName]."
|
||||||
|
|||||||
45
Private/Assert-ConfigurationDataSecretReference.ps1
Normal file
45
Private/Assert-ConfigurationDataSecretReference.ps1
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
function Assert-ConfigurationDataSecretReference {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateSet("credential", "securestring")]
|
||||||
|
[string]
|
||||||
|
$TypeName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$Value
|
||||||
|
)
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataMap -Value $Value)){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataMapContainsKey -Map $Value -Key "Provider")){
|
||||||
|
throw "Parameter [$Name] uses type [$TypeName] and a secret reference, but [Provider] is not defined."
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataMapContainsKey -Map $Value -Key "Name")){
|
||||||
|
throw "Parameter [$Name] uses type [$TypeName] and a secret reference, but [Name] is not defined."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Provider = [string](Get-ConfigurationDataMapValue -Map $Value -Key "Provider")
|
||||||
|
if([string]::IsNullOrWhiteSpace($Provider)){
|
||||||
|
throw "Parameter [$Name] secret reference [Provider] must not be empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
$SecretName = [string](Get-ConfigurationDataMapValue -Map $Value -Key "Name")
|
||||||
|
if([string]::IsNullOrWhiteSpace($SecretName)){
|
||||||
|
throw "Parameter [$Name] secret reference [Name] must not be empty."
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($Provider.ToLowerInvariant()){
|
||||||
|
"keepass" { return }
|
||||||
|
default {
|
||||||
|
throw "Parameter [$Name] uses unsupported secret provider [$Provider]."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,12 +23,40 @@ function Invoke-ConfigurationDataExpression {
|
|||||||
return [bool]::Parse($Expression)
|
return [bool]::Parse($Expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(-not (Test-ConfigurationDataExpressionParentheses -Expression $Expression)){
|
||||||
|
throw "Invalid configuration data expression [$Expression]."
|
||||||
|
}
|
||||||
|
|
||||||
if($Expression -notmatch "^([A-Za-z][A-Za-z0-9]*)\((.*)\)$"){
|
if($Expression -notmatch "^([A-Za-z][A-Za-z0-9]*)\((.*)\)$"){
|
||||||
throw "Invalid configuration data expression [$Expression]."
|
throw "Invalid configuration data expression [$Expression]."
|
||||||
}
|
}
|
||||||
|
|
||||||
$FunctionName = $Matches[1]
|
$FunctionName = $Matches[1]
|
||||||
$ArgumentText = $Matches[2]
|
$ArgumentText = $Matches[2]
|
||||||
|
|
||||||
|
if($FunctionName -ieq "coalesce"){
|
||||||
|
$RawArguments = @(Split-ConfigurationDataExpressionArguments -ArgumentText $ArgumentText)
|
||||||
|
Assert-ConfigurationDataExpressionMinimumArgumentCount -Name $FunctionName -Arguments $RawArguments -Count 1
|
||||||
|
|
||||||
|
foreach($Argument in $RawArguments){
|
||||||
|
try {
|
||||||
|
$Value = Invoke-ConfigurationDataExpressionArgument -Argument $Argument -Context $Context
|
||||||
|
if(-not (Test-ConfigurationDataValueIsEmpty -Value $Value)){
|
||||||
|
return $Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
if(Test-ConfigurationDataMissingReferenceError -ErrorRecord $_){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
$Arguments = @()
|
$Arguments = @()
|
||||||
foreach($Argument in @(Split-ConfigurationDataExpressionArguments -ArgumentText $ArgumentText)){
|
foreach($Argument in @(Split-ConfigurationDataExpressionArguments -ArgumentText $ArgumentText)){
|
||||||
$Arguments += ,(Invoke-ConfigurationDataExpressionArgument -Argument $Argument -Context $Context)
|
$Arguments += ,(Invoke-ConfigurationDataExpressionArgument -Argument $Argument -Context $Context)
|
||||||
|
|||||||
39
Private/Test-ConfigurationDataExpressionParentheses.ps1
Normal file
39
Private/Test-ConfigurationDataExpressionParentheses.ps1
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
function Test-ConfigurationDataExpressionParentheses {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[AllowNull()]
|
||||||
|
[string]
|
||||||
|
$Expression
|
||||||
|
)
|
||||||
|
|
||||||
|
if([string]::IsNullOrWhiteSpace($Expression)){
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$Depth = 0
|
||||||
|
$InString = $false
|
||||||
|
|
||||||
|
for($Index = 0; $Index -lt $Expression.Length; $Index++){
|
||||||
|
$Character = $Expression[$Index]
|
||||||
|
|
||||||
|
if($Character -eq "'"){
|
||||||
|
$InString = -not $InString
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InString){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Character -eq "("){
|
||||||
|
$Depth++
|
||||||
|
}elseif($Character -eq ")"){
|
||||||
|
$Depth--
|
||||||
|
if($Depth -lt 0){
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Depth -eq 0 -and -not $InString
|
||||||
|
}
|
||||||
11
Private/Test-ConfigurationDataMissingReferenceError.ps1
Normal file
11
Private/Test-ConfigurationDataMissingReferenceError.ps1
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
function Test-ConfigurationDataMissingReferenceError {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[System.Management.Automation.ErrorRecord]
|
||||||
|
$ErrorRecord
|
||||||
|
)
|
||||||
|
|
||||||
|
$Message = $ErrorRecord.Exception.Message
|
||||||
|
return $Message -match "^(Parameter|Variable) \[.+\] is not defined\.$"
|
||||||
|
}
|
||||||
16
Readme.md
16
Readme.md
@@ -103,7 +103,9 @@ FarmPassphrase = @{
|
|||||||
Required = $true
|
Required = $true
|
||||||
Sensitive = $true
|
Sensitive = $true
|
||||||
Value = @{
|
Value = @{
|
||||||
SecretName = 'SharePointFarmPassphrase'
|
Provider = 'KeePass'
|
||||||
|
Vault = 'BGW'
|
||||||
|
Name = 'SharePoint/FarmPassphrase'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +114,21 @@ SetupCredential = @{
|
|||||||
Required = $true
|
Required = $true
|
||||||
Sensitive = $true
|
Sensitive = $true
|
||||||
Value = @{
|
Value = @{
|
||||||
CredentialName = 'SharePointSetup'
|
Provider = 'KeePass'
|
||||||
|
Vault = 'BGW'
|
||||||
|
Name = 'SharePoint/SetupAccount'
|
||||||
|
UserName = 'BGW\SVC_SHP_SETUP'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Secret references are validated by `Resolve-DSCConfigurationData`, but they are resolved by `Resolve-DSCConfigurationSecrets` before the normal data resolve step:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$withSecrets = Resolve-DSCConfigurationSecrets -ConfigurationData $merged
|
||||||
|
$resolved = Resolve-DSCConfigurationData -ConfigurationData $withSecrets
|
||||||
|
```
|
||||||
|
|
||||||
Array values can be restricted item by item:
|
Array values can be restricted item by item:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
|
|||||||
Reference in New Issue
Block a user