Commands/Format.PS1XML/Push-FormatData.ps1

function Push-FormatData
{
    <#
    .Synopsis
        Pushes formatting to the current session.
    .Description
        Push-FormatData pushes formatting data into the current session.

        The formatting data is defined in .Format.ps1xml files (such as those in the $pshome directory).
        Add-FormatData will take one or more XML documents containing format data and will create a
        temporary module to use the formatting file.
    .Link
        Clear-FormatData
    .Link
        Pop-FormatData
    .Link
        Out-FormatData
    .Example
        # Let's start off by looking at how something like XML is rendered in PowerShell
        [xml]"<a an='anattribute'><b d='attribute'><c/></b></a>"

        # It's not very intuitive.
        # I cannot really only see the element I am looking at, instead of a chunk of data

        # Create a quick view for any XML element.
        # Piping it into Out-FormatData will make one or more format views into a full format XML file
        # Piping the output of that into Add-FormatData will create a temporary module to hold the formatting data
        # There's also a Remove-FormatData and
        Write-FormatView -TypeName "System.Xml.XmlNode" -Wrap -Property "Xml" -VirtualProperty @{
            "Xml" = {
                $strWrite = New-Object IO.StringWriter
                ([xml]$_.Outerxml).Save($strWrite)
                "$strWrite"
            }
        } |
            Out-FormatData |
            Push-FormatData

        # Now let's take a look at how the xml renders
        [xml]"<a an='anattribute'><b d='attribute'><c /></b></a>"

        # In case we want to go back to the original formatter, we can use Clear-FormatData to return
        # to the old formatting data
        Clear-FormatData

        # And we're back to the original formatting
        [xml]"<a an='anattribute'><b d='attribute'><c/></b></a>"
    #>

    [OutputType([Nullable], [PSModuleInfo])]
    [Alias('Add-FormatData')]
    param(
    # The Format XML Document. The XML document can be supplied directly,
    # but it's easier to use Write-FormatView to create it
    [Parameter(Mandatory=$true,
        ValueFromPipeline=$true)]
    [ValidateScript({
        if ((-not $_.Configuration)) {
            throw "The root of a format XML most be a Configuration element"
        }
        return $true
    })]
    [Xml]
    $FormatXml,

    # The name of the format module. If the name is not provided, the name of the module will be the first
    # type name encountered. If no typename is encountered, the name of the module will be FormatModuleN, where
    # N is the number of modules loaded so far
    [string]
    $Name,

    # If set, the module that contains the format files will be outputted to the pipeline
    [Switch]
    $PassThru
    )

    begin {
        # Create a list of all of the format files that will be loaded in this batch.
        $formatFiles = @()
    }

    process {
        #region Create a temporary file to hold each of the formatters
        $tempDir = $env:Temp, '/tmp' -ne '' | Select-Object -First 1
        $tempFile = Join-Path $tempDir ([IO.Path]::GetRandomFileName())
        $formatFileName = "${tempFile}.Format.ps1xml"
        $FormatXml.Save($FormatFileName)
        $formatFiles += (Get-Item $formatFileName).Name
        #endregion Create a temporary file to hold each of the formatters
    }

    end {
        #region Generate Module for the Type
        if (-not $Name) {
            $typeName = $FormatXml.SelectSingleNode("//TypeName")
            if ($typeName) {
                $Name = $typeName.'#text'
            } else {
                $Name = "FormatModule$($FormatModules.Count + 1)"
            }

        }
        $Name = $Name.Replace("#","").Replace("\","").Replace("/","").Replace(":","")

        $tempFile = Join-Path $tempDir $Name
        $tempFile = "${tempFile}_${pid}.psd1" # this path was colliding with other processes because its type name was fixed
        # old: 'C:\Users\User\AppData\Local\Temp\System.Text.RegularExpressions.Match.psd1'
        # new: 'C:\Users\User\AppData\Local\Temp\System.Text.RegularExpressions.Match_1234.psd1'

        Get-Module $Name -ErrorAction SilentlyContinue |
            Remove-Module
        $ModuleManifestParameters = @{
            FormatsToProcess = $FormatFiles
            NestedModules = @()
            Author = $env:UserName
            CompanyName = ""
            Copyright = Get-Date
            ModuleToProcess =  ""
            RequiredModules = @()
            Description = ""
            RequiredAssemblies = @()
            TypesToProcess = @()
            FileList = $FormatFiles
            Path = $tempFile
        }
        New-ModuleManifest @ModuleManifestParameters
        if ($script:FormatModules.Count) {
            $script:FormatModules.Values | Where-Object { $_ } |Import-Module -Force
        }
        $module = Import-Module $tempFile -Force -PassThru
        $script:formatModules[$Name] = $module
        if ($passThru) { $module }
        <#
        I didn't delete the $TempFile here because other cmdlets might assume it's not removed,
           when they reference '$script:formatModules'
        #>

        #endregion Generate Module for the Type
    }
}