Merge pull request 'dev' (#2) from dev into main
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
@@ -1,13 +1,15 @@
|
|||||||
@{
|
@{
|
||||||
RootModule = "Merge-DSCConfigurationData.psm1"
|
RootModule = "Merge-DSCConfigurationData.psm1"
|
||||||
ModuleVersion = "1.0.0"
|
ModuleVersion = "1.0.1"
|
||||||
GUID = "c1c7e70d-9049-4eaa-a3c9-44a424c35ef5"
|
GUID = "c1c7e70d-9049-4eaa-a3c9-44a424c35ef5"
|
||||||
Author = "Torsten Brendgen"
|
Author = "Torsten Brendgen"
|
||||||
Copyright = "(c) Torsten Brendgen. All rights reserved."
|
Copyright = "(c) Torsten Brendgen. All rights reserved."
|
||||||
Description = "Merges DSC configuration data from templates and deployment data."
|
Description = "Merges DSC configuration data from templates and deployment data."
|
||||||
PowerShellVersion = "5.1"
|
PowerShellVersion = "5.1"
|
||||||
FunctionsToExport = @(
|
FunctionsToExport = @(
|
||||||
"Merge-DSCConfigurationData"
|
"Merge-DSCConfigurationData",
|
||||||
|
"Export-PowerShellDataFile",
|
||||||
|
"New-DSCConfigurationDataDeployment"
|
||||||
)
|
)
|
||||||
CmdletsToExport = @()
|
CmdletsToExport = @()
|
||||||
VariablesToExport = @()
|
VariablesToExport = @()
|
||||||
|
|||||||
@@ -9,5 +9,7 @@ foreach($File in @($Private + $Public)){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Export-ModuleMember -Function @(
|
Export-ModuleMember -Function @(
|
||||||
"Merge-DSCConfigurationData"
|
"Merge-DSCConfigurationData",
|
||||||
|
"Export-PowerShellDataFile",
|
||||||
|
"New-DSCConfigurationDataDeployment"
|
||||||
)
|
)
|
||||||
|
|||||||
29
Private/ConvertTo-ConfigurationDataRelativePath.ps1
Normal file
29
Private/ConvertTo-ConfigurationDataRelativePath.ps1
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
function ConvertTo-ConfigurationDataRelativePath {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$BasePath
|
||||||
|
)
|
||||||
|
|
||||||
|
$ResolvedPath = Repair-ConfigurationDataPathEncoding -Path $Path
|
||||||
|
$ResolvedBasePath = Repair-ConfigurationDataPathEncoding -Path $BasePath
|
||||||
|
|
||||||
|
try {
|
||||||
|
$PathUri = [System.Uri]::new((Resolve-Path -LiteralPath $ResolvedPath).ProviderPath)
|
||||||
|
$BaseUriPath = [System.IO.Path]::GetFullPath($ResolvedBasePath)
|
||||||
|
if(-not $BaseUriPath.EndsWith([System.IO.Path]::DirectorySeparatorChar)){
|
||||||
|
$BaseUriPath += [System.IO.Path]::DirectorySeparatorChar
|
||||||
|
}
|
||||||
|
|
||||||
|
$BaseUri = [System.Uri]::new($BaseUriPath)
|
||||||
|
return [System.Uri]::UnescapeDataString($BaseUri.MakeRelativeUri($PathUri).ToString()).Replace('/', [System.IO.Path]::DirectorySeparatorChar)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return $ResolvedPath
|
||||||
|
}
|
||||||
|
}
|
||||||
64
Private/ConvertTo-PowerShellDataFileText.ps1
Normal file
64
Private/ConvertTo-PowerShellDataFileText.ps1
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
function ConvertTo-PowerShellDataFileText {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[AllowNull()]
|
||||||
|
$InputObject,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[int]
|
||||||
|
$Indent = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
$IndentText = " " * $Indent
|
||||||
|
$ChildIndent = $Indent + 4
|
||||||
|
$ChildIndentText = " " * $ChildIndent
|
||||||
|
|
||||||
|
if($null -eq $InputObject){
|
||||||
|
return '$null'
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InputObject -is [bool]){
|
||||||
|
if($InputObject){
|
||||||
|
return '$true'
|
||||||
|
}
|
||||||
|
|
||||||
|
return '$false'
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InputObject -is [int] -or $InputObject -is [long] -or $InputObject -is [decimal] -or $InputObject -is [double]){
|
||||||
|
return ([string]$InputObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InputObject -is [string]){
|
||||||
|
return "'$($InputObject.Replace("'", "''"))'"
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InputObject -is [System.Collections.IDictionary]){
|
||||||
|
$Lines = @("@{")
|
||||||
|
foreach($Key in $InputObject.Keys){
|
||||||
|
$KeyText = "'$(([string]$Key).Replace("'", "''"))'"
|
||||||
|
$ValueText = ConvertTo-PowerShellDataFileText -InputObject $InputObject[$Key] -Indent $ChildIndent
|
||||||
|
$Lines += "$ChildIndentText$KeyText = $ValueText"
|
||||||
|
}
|
||||||
|
$Lines += "$IndentText}"
|
||||||
|
return ($Lines -join [Environment]::NewLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
if($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]){
|
||||||
|
$Items = @($InputObject)
|
||||||
|
if($Items.Count -eq 0){
|
||||||
|
return '@()'
|
||||||
|
}
|
||||||
|
|
||||||
|
$Lines = @("@(")
|
||||||
|
foreach($Item in $Items){
|
||||||
|
$ValueText = ConvertTo-PowerShellDataFileText -InputObject $Item -Indent $ChildIndent
|
||||||
|
$Lines += "$ChildIndentText$ValueText"
|
||||||
|
}
|
||||||
|
$Lines += "$IndentText)"
|
||||||
|
return ($Lines -join [Environment]::NewLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return "'$(([string]$InputObject).Replace("'", "''"))'"
|
||||||
|
}
|
||||||
22
Private/Get-ConfigurationDataDictionaryValue.ps1
Normal file
22
Private/Get-ConfigurationDataDictionaryValue.ps1
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
function Get-ConfigurationDataDictionaryValue {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$Dictionary,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Key,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[AllowNull()]
|
||||||
|
$DefaultValue = $null
|
||||||
|
)
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataDictionaryKey -Dictionary $Dictionary -Key $Key){
|
||||||
|
return $Dictionary[$Key]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $DefaultValue
|
||||||
|
}
|
||||||
31
Private/Get-ConfigurationDataTemplateExtends.ps1
Normal file
31
Private/Get-ConfigurationDataTemplateExtends.ps1
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
function Get-ConfigurationDataTemplateExtends {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$ConfigurationData
|
||||||
|
)
|
||||||
|
|
||||||
|
$Extends = $null
|
||||||
|
|
||||||
|
if(Test-ConfigurationDataDictionaryKey -Dictionary $ConfigurationData -Key "Metadata"){
|
||||||
|
$Metadata = Get-ConfigurationDataDictionaryValue -Dictionary $ConfigurationData -Key "Metadata"
|
||||||
|
if($Metadata -is [System.Collections.IDictionary] -and (Test-ConfigurationDataDictionaryKey -Dictionary $Metadata -Key "Extends")){
|
||||||
|
$Extends = Get-ConfigurationDataDictionaryValue -Dictionary $Metadata -Key "Extends"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($null -eq $Extends -and (Test-ConfigurationDataDictionaryKey -Dictionary $ConfigurationData -Key "Extends")){
|
||||||
|
$Extends = Get-ConfigurationDataDictionaryValue -Dictionary $ConfigurationData -Key "Extends"
|
||||||
|
}
|
||||||
|
|
||||||
|
if($null -eq $Extends){
|
||||||
|
return @()
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Extends -is [System.Array] -and $Extends -isnot [string]){
|
||||||
|
return @($Extends)
|
||||||
|
}
|
||||||
|
|
||||||
|
return @($Extends)
|
||||||
|
}
|
||||||
42
Private/Get-ConfigurationDataTemplateMergeFile.ps1
Normal file
42
Private/Get-ConfigurationDataTemplateMergeFile.ps1
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
function Get-ConfigurationDataTemplateMergeFile {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[hashtable]
|
||||||
|
$Visited = @{}
|
||||||
|
)
|
||||||
|
|
||||||
|
$ResolvedPath = Resolve-ConfigurationDataTemplatePath -Path $Path
|
||||||
|
|
||||||
|
if($Visited.ContainsKey($ResolvedPath)){
|
||||||
|
$Chain = @($Visited.Keys + $ResolvedPath) -join " -> "
|
||||||
|
throw "Circular configuration data template inheritance detected: $Chain"
|
||||||
|
}
|
||||||
|
|
||||||
|
$Visited[$ResolvedPath] = $true
|
||||||
|
|
||||||
|
$ConfigurationData = Import-PowerShellDataFile -Path $ResolvedPath
|
||||||
|
if($ConfigurationData -isnot [System.Collections.IDictionary]){
|
||||||
|
throw "Configuration data template [$ResolvedPath] must contain a hashtable."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Files = @()
|
||||||
|
$BasePath = Split-Path -Path $ResolvedPath -Parent
|
||||||
|
foreach($ParentPath in @(Get-ConfigurationDataTemplateExtends -ConfigurationData $ConfigurationData)){
|
||||||
|
if([string]::IsNullOrWhiteSpace([string]$ParentPath)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$ResolvedParentPath = Resolve-ConfigurationDataTemplatePath -Path ([string]$ParentPath) -BasePath $BasePath
|
||||||
|
$Files += @(Get-ConfigurationDataTemplateMergeFile -Path $ResolvedParentPath -Visited $Visited)
|
||||||
|
}
|
||||||
|
|
||||||
|
$Files += $ResolvedPath
|
||||||
|
$Visited.Remove($ResolvedPath)
|
||||||
|
|
||||||
|
return @($Files)
|
||||||
|
}
|
||||||
49
Private/Merge-ConfigurationDataTemplateFile.ps1
Normal file
49
Private/Merge-ConfigurationDataTemplateFile.ps1
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
function Merge-ConfigurationDataTemplateFile {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string[]]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$PassThru
|
||||||
|
)
|
||||||
|
|
||||||
|
$MergeFiles = @()
|
||||||
|
$AddedFiles = @{}
|
||||||
|
|
||||||
|
foreach($Item in $Path){
|
||||||
|
foreach($File in @(Get-ConfigurationDataTemplateMergeFile -Path $Item)){
|
||||||
|
if(-not $AddedFiles.ContainsKey($File)){
|
||||||
|
$MergeFiles += $File
|
||||||
|
$AddedFiles[$File] = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$MergedConfigurationData = $null
|
||||||
|
foreach($File in $MergeFiles){
|
||||||
|
$TemplateData = Import-PowerShellDataFile -Path $File
|
||||||
|
if($null -eq $MergedConfigurationData){
|
||||||
|
$MergedConfigurationData = Copy-ConfigurationDataValue -Value $TemplateData
|
||||||
|
if($MergedConfigurationData -is [System.Collections.IDictionary] -and (Test-ConfigurationDataDictionaryKey -Dictionary $MergedConfigurationData -Key "Metadata")){
|
||||||
|
$MergedConfigurationData.Remove("Metadata")
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$MergedConfigurationData = Merge-DSCConfigurationData -Template $MergedConfigurationData -Deployment $TemplateData
|
||||||
|
if($MergedConfigurationData -is [System.Collections.IDictionary] -and (Test-ConfigurationDataDictionaryKey -Dictionary $MergedConfigurationData -Key "Metadata")){
|
||||||
|
$MergedConfigurationData.Remove("Metadata")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($PassThru){
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Files = $MergeFiles
|
||||||
|
ConfigurationData = $MergedConfigurationData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $MergedConfigurationData
|
||||||
|
}
|
||||||
21
Private/Repair-ConfigurationDataPathEncoding.ps1
Normal file
21
Private/Repair-ConfigurationDataPathEncoding.ps1
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
function Repair-ConfigurationDataPathEncoding {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[AllowEmptyString()]
|
||||||
|
[string]
|
||||||
|
$Path
|
||||||
|
)
|
||||||
|
|
||||||
|
if($Path -notmatch "[ÃÂ]"){
|
||||||
|
return $Path
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$Bytes = [System.Text.Encoding]::GetEncoding(1252).GetBytes($Path)
|
||||||
|
return [System.Text.Encoding]::UTF8.GetString($Bytes)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return $Path
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Private/Resolve-ConfigurationDataTemplatePath.ps1
Normal file
43
Private/Resolve-ConfigurationDataTemplatePath.ps1
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
function Resolve-ConfigurationDataTemplatePath {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$BasePath = (Get-Location).Path
|
||||||
|
)
|
||||||
|
|
||||||
|
$CandidatePaths = @()
|
||||||
|
foreach($CurrentPath in @($Path, (Repair-ConfigurationDataPathEncoding -Path $Path))){
|
||||||
|
if([string]::IsNullOrWhiteSpace($CurrentPath)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
$CandidatePath = $CurrentPath
|
||||||
|
$CandidateBasePath = Repair-ConfigurationDataPathEncoding -Path $BasePath
|
||||||
|
if(-not [System.IO.Path]::IsPathRooted($CandidatePath)){
|
||||||
|
$CandidatePath = Join-Path -Path $CandidateBasePath -ChildPath $CandidatePath
|
||||||
|
}
|
||||||
|
|
||||||
|
if($CandidatePaths -notcontains $CandidatePath){
|
||||||
|
$CandidatePaths += $CandidatePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ResolvedPath = $null
|
||||||
|
foreach($CandidatePath in $CandidatePaths){
|
||||||
|
$ResolvedPath = Resolve-Path -LiteralPath $CandidatePath -ErrorAction SilentlyContinue
|
||||||
|
if($null -ne $ResolvedPath){
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($null -eq $ResolvedPath){
|
||||||
|
throw "Configuration data template [$Path] was not found. Base path [$BasePath]."
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ResolvedPath.ProviderPath
|
||||||
|
}
|
||||||
18
Private/Test-ConfigurationDataDictionaryKey.ps1
Normal file
18
Private/Test-ConfigurationDataDictionaryKey.ps1
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
function Test-ConfigurationDataDictionaryKey {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$Dictionary,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Key
|
||||||
|
)
|
||||||
|
|
||||||
|
if($Dictionary -is [System.Collections.Specialized.OrderedDictionary]){
|
||||||
|
return $Dictionary.Contains($Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Dictionary.ContainsKey($Key)
|
||||||
|
}
|
||||||
32
Public/Export-PowerShellDataFile.ps1
Normal file
32
Public/Export-PowerShellDataFile.ps1
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
function Export-PowerShellDataFile {
|
||||||
|
[CmdletBinding()]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$InputObject,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$Force
|
||||||
|
)
|
||||||
|
|
||||||
|
process {
|
||||||
|
$ResolvedPath = Repair-ConfigurationDataPathEncoding -Path $Path
|
||||||
|
|
||||||
|
if((Test-Path -LiteralPath $ResolvedPath -PathType Leaf) -and (-not $Force)){
|
||||||
|
throw "File [$ResolvedPath] already exists. Use -Force to overwrite it."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Parent = Split-Path -Path $ResolvedPath -Parent
|
||||||
|
if(-not [string]::IsNullOrWhiteSpace($Parent) -and -not (Test-Path -LiteralPath $Parent)){
|
||||||
|
New-Item -Path $Parent -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$Text = ConvertTo-PowerShellDataFileText -InputObject $InputObject
|
||||||
|
Set-Content -LiteralPath $ResolvedPath -Value $Text -Encoding UTF8
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +1,65 @@
|
|||||||
function Merge-DSCConfigurationData {
|
function Merge-DSCConfigurationData {
|
||||||
[CmdletBinding()]
|
[CmdletBinding(DefaultParameterSetName="Data")]
|
||||||
Param(
|
Param(
|
||||||
[Parameter(Mandatory=$true)]
|
[Parameter(Mandatory=$true, ParameterSetName="Data")]
|
||||||
[System.Collections.Hashtable]
|
[System.Collections.IDictionary]
|
||||||
$Template,
|
$Template,
|
||||||
[Parameter(Mandatory=$true)]
|
|
||||||
[System.Collections.Hashtable]
|
[Parameter(Mandatory=$false, ParameterSetName="Data")]
|
||||||
$Deployment,
|
[System.Collections.IDictionary]
|
||||||
[Parameter(Mandatory=$false)]
|
$Deployment = @{},
|
||||||
[System.Collections.Hashtable]
|
|
||||||
$Output
|
[Parameter(Mandatory=$false, ParameterSetName="Data")]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$Output,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true, ParameterSetName="Path", ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
|
||||||
|
[Alias("FullName")]
|
||||||
|
[string[]]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false, ParameterSetName="Path")]
|
||||||
|
[switch]
|
||||||
|
$PassThru
|
||||||
)
|
)
|
||||||
|
|
||||||
|
begin {
|
||||||
|
$TemplatePath = @()
|
||||||
|
}
|
||||||
|
|
||||||
|
process {
|
||||||
|
if($PSCmdlet.ParameterSetName -eq "Path"){
|
||||||
|
$TemplatePath += @($Path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if($Output -eq $null){
|
if($Output -eq $null){
|
||||||
$Output = $Deployment
|
$Output = $Deployment
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($Property in $Template.GetEnumerator()){
|
foreach($Property in $Template.GetEnumerator()){
|
||||||
if($Property.Value -is [System.Collections.Hashtable]){
|
if($Property.Name -eq "Metadata"){
|
||||||
Write-Verbose "Key [$($Property.Name)] is a Hashtable"
|
Write-Verbose "Skipping metadata block during configuration data merge"
|
||||||
if($null -ne $Deployment.$($Property.Name)){
|
continue
|
||||||
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)
|
|
||||||
}else{
|
|
||||||
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
|
|
||||||
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
|
|
||||||
}
|
}
|
||||||
}elseif($Property.Value -is [System.Collections.Specialized.OrderedDictionary]){
|
|
||||||
Write-Verbose "Key [$($Property.Name)] is a Ordered Dictionary"
|
if($Property.Value -is [System.Collections.IDictionary]){
|
||||||
if($null -ne $Deployment.$($Property.Name)){
|
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"
|
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]
|
||||||
}else{
|
}else{
|
||||||
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
|
Write-Verbose "Key [$($Property.Name)] is not present in Deployment Data"
|
||||||
$Output.Add($($Property.Name),(Copy-ConfigurationDataValue -Value $Template.$($Property.Name)))
|
$Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template[$Property.Name]))
|
||||||
}
|
}
|
||||||
}elseif($Property.Value -is [System.Array]){
|
}elseif($Property.Value -is [System.Array]){
|
||||||
Write-Verbose "$($Property.Name) is ein Array"
|
Write-Verbose "$($Property.Name) is ein Array"
|
||||||
Write-Verbose "Total Items in Template Array [$($Property.Value.Count)]"
|
Write-Verbose "Total Items in Template Array [$($Property.Value.Count)]"
|
||||||
Write-Verbose "Total Items in Deployment Array [$($Deployment.$($Property.Name).Count)]"
|
Write-Verbose "Total Items in Deployment Array [$(@(Get-ConfigurationDataDictionaryValue -Dictionary $Deployment -Key $Property.Name -DefaultValue @()).Count)]"
|
||||||
if($null -ne $Deployment.$($Property.Name)){
|
if(Test-ConfigurationDataDictionaryKey -Dictionary $Deployment -Key $Property.Name){
|
||||||
Write-Verbose "Array is defined in Deployment"
|
Write-Verbose "Array is defined in Deployment"
|
||||||
|
|
||||||
|
$DeploymentArray = Get-ConfigurationDataDictionaryValue -Dictionary $Deployment -Key $Property.Name
|
||||||
$TemplateItems = for($i=0;$i -lt $Property.Value.Count; $i++){
|
$TemplateItems = for($i=0;$i -lt $Property.Value.Count; $i++){
|
||||||
$SearchKeyNames = @(Get-ConfigurationDataArrayMergeKeyNames -ArrayName $Property.Name -Item $Property.Value[$i])
|
$SearchKeyNames = @(Get-ConfigurationDataArrayMergeKeyNames -ArrayName $Property.Name -Item $Property.Value[$i])
|
||||||
[PSCustomObject]@{
|
[PSCustomObject]@{
|
||||||
@@ -58,19 +76,19 @@ function Merge-DSCConfigurationData {
|
|||||||
|
|
||||||
if($SearchKeyNames.Count -eq 0){
|
if($SearchKeyNames.Count -eq 0){
|
||||||
Write-Verbose "No matching name key found for item in [$($Property.Name)]"
|
Write-Verbose "No matching name key found for item in [$($Property.Name)]"
|
||||||
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
|
$Output[$Property.Name] += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if($TemplateItem.IsWildcard){
|
if($TemplateItem.IsWildcard){
|
||||||
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemHasKeys -Item $_ -KeyNames $SearchKeyNames })
|
$MatchingDeploymentItems = @($DeploymentArray | Where-Object { Test-ConfigurationDataItemHasKeys -Item $_ -KeyNames $SearchKeyNames })
|
||||||
}else{
|
}else{
|
||||||
$MatchingDeploymentItems = @($Deployment.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $TemplateItem.Value -KeyNames $SearchKeyNames })
|
$MatchingDeploymentItems = @($DeploymentArray | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $TemplateItem.Value -KeyNames $SearchKeyNames })
|
||||||
}
|
}
|
||||||
|
|
||||||
if($MatchingDeploymentItems.Count -gt 0){
|
if($MatchingDeploymentItems.Count -gt 0){
|
||||||
foreach($DeploymentItem in $MatchingDeploymentItems){
|
foreach($DeploymentItem in $MatchingDeploymentItems){
|
||||||
$OutputItem = @($Output.$($Property.Name) | Where-Object { Test-ConfigurationDataItemKeyMatch -Left $_ -Right $DeploymentItem -KeyNames $SearchKeyNames })[0]
|
$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 | Out-Null
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@@ -78,21 +96,29 @@ function Merge-DSCConfigurationData {
|
|||||||
Write-Verbose "Wildcard item [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] in [$($Property.Name)] matched no deployment items"
|
Write-Verbose "Wildcard item [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] in [$($Property.Name)] matched no deployment items"
|
||||||
}else{
|
}else{
|
||||||
Write-Verbose "Pair [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] not present"
|
Write-Verbose "Pair [$(Format-ConfigurationDataMergeKey -Item $TemplateItem.Value -KeyNames $SearchKeyNames)] not present"
|
||||||
$Output.$($Property.Name) += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
|
$Output[$Property.Name] += ,(Copy-ConfigurationDataValue -Value $TemplateItem.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
Write-Verbose "Array is not defined in Deployment"
|
Write-Verbose "Array is not defined in Deployment"
|
||||||
$Output.$($Property.Name) = Copy-ConfigurationDataValue -Value $Template.$($Property.Name)
|
$Output[$Property.Name] = Copy-ConfigurationDataValue -Value $Template[$Property.Name]
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
Write-Verbose "$($Property.Name) is a String or Integer Value"
|
Write-Verbose "$($Property.Name) is a String or Integer Value"
|
||||||
if($null -eq $Deployment.$($Property.Name)){
|
if(-not (Test-ConfigurationDataDictionaryKey -Dictionary $Deployment -Key $Property.Name)){
|
||||||
$Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template.($Property.Name)))
|
$Output.Add($Property.Name,(Copy-ConfigurationDataValue -Value $Template[$Property.Name]))
|
||||||
}elseif($Deployment.$($Property.Name) -ne $Property.Value){
|
}elseif($Deployment[$Property.Name] -ne $Property.Value){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $Output
|
return $Output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end {
|
||||||
|
if($PSCmdlet.ParameterSetName -eq "Path"){
|
||||||
|
return Merge-ConfigurationDataTemplateFile -Path $TemplatePath -PassThru:$PassThru
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
143
Public/New-DSCConfigurationDataDeployment.ps1
Normal file
143
Public/New-DSCConfigurationDataDeployment.ps1
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
function New-DSCConfigurationDataDeployment {
|
||||||
|
[CmdletBinding(SupportsShouldProcess=$true)]
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[string]
|
||||||
|
$Path,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$Name,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]
|
||||||
|
$DeploymentId,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[Alias("SourceTemplates")]
|
||||||
|
[string[]]
|
||||||
|
$SourceTemplatePath,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[hashtable[]]
|
||||||
|
$AllNodes = @(),
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[System.Collections.IDictionary]
|
||||||
|
$DeploymentData = @{},
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$UseRelativePaths,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$Export,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[ValidateSet("PowerShellDataFile", "Json")]
|
||||||
|
[string]
|
||||||
|
$Format = "PowerShellDataFile",
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$Force,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]
|
||||||
|
$PassThru
|
||||||
|
)
|
||||||
|
|
||||||
|
if($Export -and [string]::IsNullOrWhiteSpace($Path)){
|
||||||
|
throw "Parameter [Path] is required when [Export] is used."
|
||||||
|
}
|
||||||
|
|
||||||
|
$ResolvedOutputPath = $null
|
||||||
|
if(-not [string]::IsNullOrWhiteSpace($Path)){
|
||||||
|
$ResolvedOutputPath = Repair-ConfigurationDataPathEncoding -Path $Path
|
||||||
|
}
|
||||||
|
|
||||||
|
$OutputDirectory = if([string]::IsNullOrWhiteSpace($ResolvedOutputPath)){
|
||||||
|
(Get-Location).Path
|
||||||
|
}else{
|
||||||
|
Split-Path -Path $ResolvedOutputPath -Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
if([string]::IsNullOrWhiteSpace($OutputDirectory)){
|
||||||
|
$OutputDirectory = (Get-Location).Path
|
||||||
|
}
|
||||||
|
|
||||||
|
$MergeResult = Merge-DSCConfigurationData -Path $SourceTemplatePath -PassThru
|
||||||
|
$MergedTemplateData = $MergeResult.ConfigurationData
|
||||||
|
|
||||||
|
$DeploymentOverride = Copy-ConfigurationDataValue -Value $DeploymentData
|
||||||
|
if($AllNodes.Count -gt 0){
|
||||||
|
if(-not (Test-ConfigurationDataDictionaryKey -Dictionary $DeploymentOverride -Key "Resources")){
|
||||||
|
$DeploymentOverride["Resources"] = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
$DeploymentOverride["Resources"]["AllNodes"] = $AllNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
$ConfigurationData = Merge-DSCConfigurationData -Template $MergedTemplateData -Deployment $DeploymentOverride
|
||||||
|
|
||||||
|
$TemplatePaths = @($SourceTemplatePath | ForEach-Object {
|
||||||
|
$Resolved = Resolve-ConfigurationDataTemplatePath -Path $_
|
||||||
|
if($UseRelativePaths){
|
||||||
|
ConvertTo-ConfigurationDataRelativePath -Path $Resolved -BasePath $OutputDirectory
|
||||||
|
}else{
|
||||||
|
$Resolved
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$SourceFiles = @($MergeResult.Files | ForEach-Object {
|
||||||
|
if($UseRelativePaths){
|
||||||
|
ConvertTo-ConfigurationDataRelativePath -Path $_ -BasePath $OutputDirectory
|
||||||
|
}else{
|
||||||
|
$_
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$ConfigurationData["Metadata"] = [ordered]@{
|
||||||
|
TemplateType = "Deployment"
|
||||||
|
Name = $Name
|
||||||
|
DeploymentId = $DeploymentId
|
||||||
|
GeneratedOn = (Get-Date).ToString("s")
|
||||||
|
Sources = [ordered]@{
|
||||||
|
Templates = $TemplatePaths
|
||||||
|
Files = $SourceFiles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-not $Export){
|
||||||
|
return $ConfigurationData
|
||||||
|
}
|
||||||
|
|
||||||
|
if($PSCmdlet.ShouldProcess($ResolvedOutputPath, "Export DSC configuration data deployment as [$Format]")){
|
||||||
|
switch($Format){
|
||||||
|
"PowerShellDataFile" {
|
||||||
|
Export-PowerShellDataFile -InputObject $ConfigurationData -Path $ResolvedOutputPath -Force:$Force
|
||||||
|
}
|
||||||
|
"Json" {
|
||||||
|
if((Test-Path -LiteralPath $ResolvedOutputPath -PathType Leaf) -and (-not $Force)){
|
||||||
|
throw "File [$ResolvedOutputPath] already exists. Use -Force to overwrite it."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Parent = Split-Path -Path $ResolvedOutputPath -Parent
|
||||||
|
if(-not [string]::IsNullOrWhiteSpace($Parent) -and -not (Test-Path -LiteralPath $Parent)){
|
||||||
|
New-Item -Path $Parent -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$ConfigurationData | ConvertTo-Json -Depth 100 | Set-Content -LiteralPath $ResolvedOutputPath -Encoding UTF8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($PassThru){
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Path = $ResolvedOutputPath
|
||||||
|
Files = $MergeResult.Files
|
||||||
|
ConfigurationData = $ConfigurationData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
291
Tests/Extends.Tests.ps1
Normal file
291
Tests/Extends.Tests.ps1
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
$script:ModuleRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$script:ModuleManifest = Join-Path -Path $script:ModuleRoot -ChildPath 'Merge-DSCConfigurationData.psd1'
|
||||||
|
|
||||||
|
Import-Module $script:ModuleManifest -Force
|
||||||
|
|
||||||
|
Describe 'Merge-DSCConfigurationData Extends' {
|
||||||
|
It 'keeps the existing hashtable merge behavior' {
|
||||||
|
$Template = @{
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Type = 'string'
|
||||||
|
Required = $true
|
||||||
|
DefaultValue = 'example.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$Deployment = @{
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Value = 'contoso.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$Result = Merge-DSCConfigurationData -Template $Template -Deployment $Deployment
|
||||||
|
|
||||||
|
$Result.Parameters.DomainFQDN.Type | Should Be 'string'
|
||||||
|
$Result.Parameters.DomainFQDN.Required | Should Be $true
|
||||||
|
$Result.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'merges a child template with Metadata.Extends' {
|
||||||
|
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
|
||||||
|
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Default'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Type = 'string'
|
||||||
|
Required = $true
|
||||||
|
DefaultValue = 'example.local'
|
||||||
|
}
|
||||||
|
DomainNetBIOS = @{
|
||||||
|
Type = 'string'
|
||||||
|
Required = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Resources = @{
|
||||||
|
NonNodeData = @{
|
||||||
|
RequiredModules = @(
|
||||||
|
@{
|
||||||
|
Name = 'ActiveDirectoryDsc'
|
||||||
|
Version = '6.7.1'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Contoso'
|
||||||
|
Extends = './Default.psd1'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Value = 'contoso.local'
|
||||||
|
}
|
||||||
|
DomainNetBIOS = @{
|
||||||
|
Value = 'CONTOSO'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $ChildPath -Encoding UTF8
|
||||||
|
|
||||||
|
$Result = Merge-DSCConfigurationData -Path $ChildPath -PassThru
|
||||||
|
|
||||||
|
$Result.Files.Count | Should Be 2
|
||||||
|
[System.IO.Path]::GetFileName($Result.Files[0]) | Should Be 'Default.psd1'
|
||||||
|
[System.IO.Path]::GetFileName($Result.Files[1]) | Should Be 'Contoso.psd1'
|
||||||
|
$Result.ConfigurationData.Parameters.DomainFQDN.Type | Should Be 'string'
|
||||||
|
$Result.ConfigurationData.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
|
||||||
|
$Result.ConfigurationData.Parameters.DomainNetBIOS.Required | Should Be $true
|
||||||
|
$Result.ConfigurationData.Parameters.DomainNetBIOS.Value | Should Be 'CONTOSO'
|
||||||
|
$Result.ConfigurationData.Resources.NonNodeData.RequiredModules[0].Name | Should Be 'ActiveDirectoryDsc'
|
||||||
|
$Result.ConfigurationData.ContainsKey('Metadata') | Should Be $false
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'detects circular Metadata.Extends references' {
|
||||||
|
$APath = Join-Path -Path $TestDrive -ChildPath 'A.psd1'
|
||||||
|
$BPath = Join-Path -Path $TestDrive -ChildPath 'B.psd1'
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
Extends = './B.psd1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $APath -Encoding UTF8
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
Extends = './A.psd1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $BPath -Encoding UTF8
|
||||||
|
|
||||||
|
{ Merge-DSCConfigurationData -Path $APath } | Should Throw
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'exports importable PSD1 files with quoted metadata keys' {
|
||||||
|
$Path = Join-Path -Path $TestDrive -ChildPath 'Export.psd1'
|
||||||
|
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
Description = @{
|
||||||
|
'de-DE' = 'Deutsch'
|
||||||
|
'en-US' = 'English'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} | Export-PowerShellDataFile -Path $Path -Force
|
||||||
|
|
||||||
|
$Data = Import-PowerShellDataFile -Path $Path
|
||||||
|
$Data.Metadata.Description['de-DE'] | Should Be 'Deutsch'
|
||||||
|
$Data.Metadata.Description['en-US'] | Should Be 'English'
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'creates materialized deployment data without exporting by default' {
|
||||||
|
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
|
||||||
|
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Default'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Type = 'string'
|
||||||
|
Required = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Resources = @{
|
||||||
|
AllNodes = @(
|
||||||
|
@{
|
||||||
|
NodeName = '*'
|
||||||
|
PSDSCAllowPlainTextPassword = $true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Contoso'
|
||||||
|
Extends = './Default.psd1'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Value = 'contoso.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $ChildPath -Encoding UTF8
|
||||||
|
|
||||||
|
$Result = New-DSCConfigurationDataDeployment `
|
||||||
|
-Name 'Contoso-Test' `
|
||||||
|
-DeploymentId '123' `
|
||||||
|
-SourceTemplatePath $ChildPath `
|
||||||
|
-AllNodes @(
|
||||||
|
@{
|
||||||
|
NodeName = 'Node01'
|
||||||
|
RunCentralAdministration = $true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$Result.Metadata.TemplateType | Should Be 'Deployment'
|
||||||
|
$Result.Metadata.Sources.Files.Count | Should Be 2
|
||||||
|
$Result.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
|
||||||
|
$Result.Resources.AllNodes[0].NodeName | Should Be 'Node01'
|
||||||
|
$Result.Resources.AllNodes[0].PSDSCAllowPlainTextPassword | Should Be $true
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'exports materialized deployment data as PSD1' {
|
||||||
|
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
|
||||||
|
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
|
||||||
|
$DeploymentPath = Join-Path -Path $TestDrive -ChildPath 'Deployments\Deployment_123.psd1'
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Default'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Type = 'string'
|
||||||
|
Required = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Metadata = @{
|
||||||
|
TemplateType = 'Environment'
|
||||||
|
Name = 'Contoso'
|
||||||
|
Extends = './Default.psd1'
|
||||||
|
}
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Value = 'contoso.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $ChildPath -Encoding UTF8
|
||||||
|
|
||||||
|
$Result = New-DSCConfigurationDataDeployment `
|
||||||
|
-Path $DeploymentPath `
|
||||||
|
-Name 'Contoso-Test' `
|
||||||
|
-DeploymentId '123' `
|
||||||
|
-SourceTemplatePath $ChildPath `
|
||||||
|
-AllNodes @(
|
||||||
|
@{
|
||||||
|
NodeName = 'Node01'
|
||||||
|
RunCentralAdministration = $true
|
||||||
|
}
|
||||||
|
) `
|
||||||
|
-UseRelativePaths `
|
||||||
|
-Export `
|
||||||
|
-Format PowerShellDataFile `
|
||||||
|
-Force `
|
||||||
|
-PassThru
|
||||||
|
|
||||||
|
$DeploymentPath | Should Exist
|
||||||
|
$Result.ConfigurationData.Metadata.TemplateType | Should Be 'Deployment'
|
||||||
|
$Result.ConfigurationData.Metadata.Sources.Files.Count | Should Be 2
|
||||||
|
$Result.ConfigurationData.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
|
||||||
|
$Result.ConfigurationData.Resources.AllNodes[0].NodeName | Should Be 'Node01'
|
||||||
|
$Result.ConfigurationData.Resources.AllNodes[0].RunCentralAdministration | Should Be $true
|
||||||
|
|
||||||
|
$Imported = Import-PowerShellDataFile -Path $DeploymentPath
|
||||||
|
$Imported.Metadata.Name | Should Be 'Contoso-Test'
|
||||||
|
$Imported.Metadata.Sources.Templates.Count | Should Be 1
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'exports materialized deployment data as JSON' {
|
||||||
|
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
|
||||||
|
$DeploymentPath = Join-Path -Path $TestDrive -ChildPath 'Deployment_123.json'
|
||||||
|
|
||||||
|
@'
|
||||||
|
@{
|
||||||
|
Parameters = @{
|
||||||
|
DomainFQDN = @{
|
||||||
|
Type = 'string'
|
||||||
|
Value = 'contoso.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
|
||||||
|
|
||||||
|
New-DSCConfigurationDataDeployment `
|
||||||
|
-Path $DeploymentPath `
|
||||||
|
-Name 'Contoso-Test' `
|
||||||
|
-DeploymentId '123' `
|
||||||
|
-SourceTemplatePath $DefaultPath `
|
||||||
|
-Export `
|
||||||
|
-Format Json `
|
||||||
|
-Force
|
||||||
|
|
||||||
|
$DeploymentPath | Should Exist
|
||||||
|
$Imported = Get-Content -Path $DeploymentPath -Raw | ConvertFrom-Json
|
||||||
|
$Imported.Metadata.TemplateType | Should Be 'Deployment'
|
||||||
|
$Imported.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user