Write-MarkupWriter.ps1

function Write-MarkupWriter
{
    <#
    .Synopsis
        Write-MarkupWriter produces PowerShell commands that create markup
    .Description
        Write-MarkupWriter will create a single PowerShell function
        to create a single XML element, with as rich parameter binding
        and defaults as you would like.
         
        In this way, you can build up scripts that interact with XML with
        all of the parameter binding PowerShell has to offer.
         
        The -AttributeParameter and -ElementParameter will accept full parameter
        declarations, like [Parameter(Manadatory=$true)]$foo.
         
        These parameter declarations will become parameters on the new command,
        with -AttributeParameter mapping to escaped attributes, and
        -ElementParameter mapping to cData elements.
         
        The commandname will be set implicily to "Write-${TagName}Tag"
    .Example
        Write-MarkupWriter -TagName "a" -AttributeParameter '$href', '$class' -ElementParameter InnerHtml
    #>
    
    param(
    # The name of the tag
    [Parameter(Mandatory=$true)]
    [String]$TagName,    
    # -AttributeParameter defines the parameters that will provide values for an attribute.
    [string[]]
    $AttributeParameter,
    # -ElementParameter defines the parameters that will provide values for an element
    [String[]]$ElementParameter,    
    # -CommandName allows you to define a custom command name. If -CommandName is missing,
    # the command will be named "Write-${TagName}Tag"
    [String]$CommandName    
    )
    
    begin {
        <#
        .Synopsis
            Given a given parameter block of parameters to declare, gets the name of the parameters
        #>

        function Get-ParameterName($declartion) {
            & ([ScriptBlock]::Create("
            function foo {
                param($declartion)
            }
            (Get-Command foo).Parameters.Keys |
                Where-Object {
                    'Verbose','Debug','ErrorAction','WarningAction',
                        'ErrorVariable','WarningVariable','OutVariable',
                        'OutBuffer' -notcontains `$_
                }
            "
))
        }                
    }
    
    process 
    {        
        #region Initialize the Code to Generate
        $paramBlock = ""
        $processBlock = "" + {
            function esc($str) { [Security.SecurityElement]::Escape($str) }
            $attributeChunk =  ''
            $elementChunk = '' 
        }
        #endregion
        
        #region Generate code for the attribute parameters
        foreach ($Attribute in $AttributeParameter) {
            if (-not $attribute) { continue} 
            if (-not $attribute.Contains('$')) {
                $attribute = '$' + $attribute
            }
            $paramBlock += "$attribute,
            "
        
            $paramName = Get-ParameterName $attribute  
            $processBlock += "
            if (`$psBoundParameters.ContainsKey('$paramName')) {
                if (`$singleQuote) {
                    `$attributeChunk += `" $paramName `='`$(esc `$$paramName)'`"
                } else {
                    `$attributeChunk += `" $paramName`=```"`$(esc `$$paramName)```"`"
                }
            }"

        }
        foreach ($Element in $ElementParameter) {
            if (-not $Element) { continue} 
            if (-not $Element.Contains('$')) {
                $Element = '$' + $Element
            }

            $paramName = Get-ParameterName $Element                
            $paramBlock += "$element,
             
            "

            $processBlock += "
                `$elementChunk += `$$paramName
            "

        }
        $paramBlock += '
        [Switch]$AsXml,
        [Switch]$SingleQuote
        '

        $processBlock += "
         
        `$xml = `"<$TagName `$AttributeChunk >
            `$ElementChunk
        </$TagName>
        `" -as [xml]
        if (`$asXml) {
            `$xml
        } else {
            `$strWrite = New-Object IO.StringWriter
            `$xml.Save(`$strWrite)
            `"`$strWrite`"
        }
        "


        if (-not $commandName) {
            $commandName = "Write-${TagName}Tag"
        }
        $outputFunction = "
        function $commandName {
            param (
            $paramBlock
            )
            process {
                $ProcessBlock
            }
        }
        "


        $outputFunction
    }
}