Functions/Expand-Template.ps1

function Expand-Template {
    <#
            .SYNOPSIS
            Expand-Template.ps1
            Simple templating engine to expand a given template text containing PowerShell expressions.
 
            .EXAMPLE
            $text="hello"; .\Expand-Template.ps1 -Text 'Hello [[$text]] world'
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false, ParameterSetName='Text',ValueFromPipeline=$true)]
        #The text of the template to do the expansion
        [string]$Text,
        [Parameter(Mandatory=$true, ParameterSetName='Path')]
        #Path to template to do the expansion
        [string]$Path,
        #Destination path to write expansion result. If not specified, write to output stream.
        [string]$Destination,
        #Path to file containing JSON template property values
        [string[]]$ConfigJsonPath,
        #Begin tag for detecting expand expression in template, default is '[['
        [string]$BeginTag = '[[',
        #End tag for detecting expand expression in template, default is ']]'
        [string]$EndTag = ']]',
        [ref]$TotalExpansions,
        [string]$ContentMatchRegEx = '.*?',
        [string]$ReplacementExpression
    )
    if($TotalExpansions) { $TotalExpansions.Value = 0 }
    $BeginTag = [RegEx]::Escape($BeginTag)
    $EndTag = [RegEx]::Escape($EndTag)
    $encoding = 'UTF8'
    
    
    Write-Verbose "Expand-Template: $Path"
    if ($Path) {
        if (!(Test-Path -LiteralPath $path )) { throw "Template-Expand: path `'$path`' can't be found"  }
        $Text = Get-Content -LiteralPath $path -Raw
        $encoding = Get-FileEncoding -Path $path
    } 

    if(-not $text) {
        Write-Verbose 'WARNING: No text to replace $Path'
        return;
    }

    #Load the configuration
    if ($ConfigJsonPath) {
        if (!(Test-Path -Path $ConfigJsonPath)) { throw "Replace-AllTemplateFiles: JSON configuration file(s) `'$ConfigJsonPath`' can't be found" }
        Write-Verbose "Loading JSON Configuration file: $ConfigJsonPath"
        Import-TemplateConfiguration -Path $ConfigJsonPath
    }
    if($TotalExpansions) {
        $global:expansionCount = $TotalExpansions.Value
    } else {
        $global:expansionCount = 0
    }
    
    $pattern = New-Object -Type System.Text.RegularExpressions.Regex `
                          -ArgumentList "$BeginTag($ContentMatchRegEx)$EndTag",([System.Text.RegularExpressions.RegexOptions]::Singleline -bor [System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
    $matchEvaluatorDelegate =  [System.Text.RegularExpressions.MatchEvaluator] {
               param([System.Text.RegularExpressions.Match]$Match)
                $expression = $ReplacementExpression
                if(-not $expression) {
                    $expression = $match.get_Groups()[1].Value # content between markers
                }
           
               
               trap { Write-Error "Failed to expand template. Can't evaluate expression '$expression'. The following error occured: $_"; break }
               $global:expansionCount++
               $numReplaced = $global:expansionCount
               #Perform expansion on the values too
               $expression = $expression -replace '\\"','"'
               Write-Verbose "`texpanding expression: $expression"
               
               Invoke-Expression -command "Write-output ($expression)" | 
                    Expand-Template -TotalExpansions ([ref]$global:expansionCount) | 
                        Tee-Object -Variable result
                        
               Write-Verbose "`texpanded expression evaluated value:`n$result`n"
               
               $global:expansionCount += $numReplaced
               
        }

    $expandedText = $pattern.Replace($text, $matchEvaluatorDelegate)

    if (-not $destination){ $expandedText }
    elseif($expandedText -ne $text -or $Destination -notlike $path) { 
        $expandedText | Out-File -LiteralPath $destination -Encoding $encoding -Force -NoNewline
    }
    
    if($Destination -and -not (Test-Path $Destination)) {
        throw "Expected file $Destination to exist, but it does not"
    }
    

    if($TotalExpansions) { $TotalExpansions.Value += $global:expansionCount }
}