ExportTypeData.ps1

<#PSScriptInfo
    .VERSION 1.0
    .GUID 7525e932-9963-4d1c-bdb4-a0fdbb42cb5c
    .AUTHOR j@mobulaconsulting.com
    .COPYRIGHT (C) James O'Neill 2023
    .LICENSEURI https://opensource.org/licenses/MIT
    .RELEASENOTES First Public Release
    .DESCRIPTION Saves type data from the current session in - similar to what Export-FormatData does for format data
#>

function Export-TypeData {
<#
  .SYNOPSIS
    Saves type data from the current session in - similar to what Export-FormatData does for format data.
 
  .DESCRIPTION
    Creates PowerShell type files (types.ps1xml) from the current session.
    It takes the TypeData objects that `Get-TypeData` returns and saves them in a file in XML format, or sends the XML to the clipboard
 
    PowerShell uses this Extended type data to define additional properties and methods ("members") of object types
     You can view and edit the type files and use the Update-TypeData cmdlet to add the type data to a session.
 
    For more information about types files in PowerShell, see about_Types.ps1xml
 
.PARAMETER Path
    Specifies a location for the output file. Enter a path (optional) and file name with a types.ps1xml file name extension.
    If you omit the path, the file is created in the current directory.
 
  .PARAMETER InputObject
    Specifies the type data objects to be exported. You can also pipe the objects from `Get-TypeData` to `Export-TypeData`.
 
  .PARAMETER ToClipboard
    Sends output to the clipboard instead of to a file
 
  .PARAMETER NoClobber
    Indicates that the command should not overwrite existing files. By default, files are overwritten without warning unless the file has the read-only attribute.
 
  .EXAMPLE
    ------------ Example 1: Export session type data ------------
    Get-TypeData -TypeName "*" | Export-typeData -Path "Alltype.ps1xml"
 
    This command exports all of the type data in the session to the Alltype.ps1xml file.
 
  .EXAMPLE
    ------------ Example 2: Export type data for a single type ------------
    Get-TypeData -TypeName "System.Diagnostics.Process" | Export-typeData -Path "Process.type.ps1xml"
 
    This command exports the data for a single type. The exported file may be modified and imported with
    Update-TypeData -PrependPath ".\process.format.ps1xml"
 
    Specifying PrependPath gives the modified data higher precedence than the default data for Process objects
 
  .EXAMPLE
    ------------ Example 3: Add and then export type-data for a type ------------
 
    Update-TypeData -TypeName Collection -MemberType ScriptProperty -MemberName Created -Value {[datetime]::unixEpoch.AddSeconds($this.when)}
    Update-TypeData -TypeName Collection -MemberType AliasProperty -MemberName Items -Value ount
    Update-TypeData -TypeName Collection -DefaultDisplayPropertySet Name,Items,Created
    Get-TypeData -TypeName Collection | Export-TypeData -Path Collection.Type.ps1xml
 
    The first three lines add a read-only script property, an alias proper and a default display set to a user defined class named collection
    The fourth line exports the type information for collection so it can be included the TypesToProcess section of a module manifest, or
    using Update-TypeData
 
  .LINK Get-TypeData
  .LINK Update-TypeData
  .LINK about_Types.ps1xml
  .LINK Export-FormatData
#>

  [CmdletBinding(DefaultParameterSetName='ToFile')]
  param   (
    [Parameter(Mandatory=$true,Position=0,ParameterSetName='ToFile')]
    $Path,
    [Parameter(ValueFromPipeline=$true,Position=1)]
    $InputObject,
    [Parameter(Mandatory=$true,ParameterSetName='UseClipboard')]
    [switch]$ToClipboard,
    [switch]$NoClobber
  )
  begin   {
    $xml = New-Object -type System.Text.StringBuilder
    $xml.appendLine(      "<?xml version=""1.0"" encoding=""utf-8"" ?>"),
    $xml.appendLine(      "<Types>")                                   | Out-Null
  }
  process {
    foreach ($t in $InputObject) {
      $xml.appendLine(    " <Type><Name>$($t.TypeName)</Name>"),
      $xml.appendLine(    " <Members>")                             | Out-Null
      if ($t.DefaultDisplayPropertySet)  {
        $xml.appendLine(  " <MemberSet>") ,
        $xml.appendLine(  " <Name>PSStandardMembers</Name>") ,
        $xml.appendLine(  " <Members><PropertySet>") ,
        $xml.appendLine(  " <Name>DefaultDisplayPropertySet</Name>"),
        $xml.appendLine(  " <ReferencedProperties>")          | Out-Null
        foreach ($n in $t.DefaultDisplayPropertySet.ReferencedProperties){
          $xml.appendline(" <Name>$n</Name>")             | Out-Null
        }
        $xml.appendLine(  " </ReferencedProperties>"),
        $xml.appendLine(  " </PropertySet></Members>"),
        $xml.appendLine(  " </MemberSet>")                        | Out-Null
      }
      if ($t.DefaultDisplayProperty)     {
          $xml.appendLine(" <MemberSet>") ,
          $xml.appendLine(" <Name>PSStandardMembers</Name>"),
          $xml.appendLine(" <Members><NoteProperty>") ,
          $xml.appendLine(" <Name>DefaultDisplayProperty</Name>") ,
          $xml.appendLine(" <Value>$($t.DefaultDisplayProperty)</Value>"),
          $xml.appendLine(" </NoteProperty></Members>") ,
          $xml.appendLine(" </MemberSet>")                        | Out-Null
      }
      foreach ($m in $t.members.values)   {
        switch ($m.Gettype().name)       {
          "AliasPropertyData"          {
            if($m.IsHidden)            { $xml.append(
                          " <AliasProperty IsHidden=""true"">")   | Out-Null}
            else                       { $xml.append(
                          " <AliasProperty>")                     | Out-Null}
            $xml.append(    "<Name>$($m.name)</Name><ReferencedMemberName>"),
            $xml.append(    $m.ReferencedMemberName),
            $xml.AppendLine("</ReferencedMemberName></AliasProperty>") | Out-Null
        }

        "CodeMethodData"             { $xml.AppendLine(
                          " <CodeMethod><Name>$($m.name)</Name>" +
                          "<CodeReference><TypeName>"+
                          $m.CodeReference.DeclaringType.FullName +
                          "</TypeName>" +
                          "<MethodName>$($m.CodeReference.Name)</MethodName>"+
                          "</CodeReference></CodeMethod>")            | Out-Null}
        "CodePropertyData"           {
          if($m.IsHidden)           { $xml.append(
                           " <CodeProperty IsHidden=""true"">")   | Out-Null}
          else                      { $xml.append(
                           " <CodeProperty>")                     | Out-Null}
          $xml.AppendLine("<Name>$($m.name)</Name>")                  | Out-Null
          if ($m.GetCodeReference)  { $xml.appendLine(
                           " <GetCodeReference><TypeName>" +
                           $m.GetCodeReference.DeclaringType.FullName +
                           "</TypeName><MethodName>" + $m.GetCodeReference.Name +
                           "</MethodName></GetCodeReference>")        | Out-Null}
          if ($m.SetCodeReference)  { $xml.appendLine(
                           " <SetCodeReference><TypeName>"+
                           $m.SetCodeReference.DeclaringType.FullName +
                           "</TypeName><MethodName>" + $m.SetCodeReference.Name +
                           "</MethodName></SetCodeReference>")        | Out-Null}
          $xml.appendLine( " </CodeProperty>")                    | Out-Null
        }
        "NotePropertyData"           {
          if($m.IsHidden)          { $xml.append(
                          " <NoteProperty IsHidden=""true"">")   | Out-Null}
          else                     { $xml.append(
                          " <NoteProperty>" )                    | Out-Null}
          $xml.Appendline("<Name>$($m.name)</Name><Value>" +
                            $m.Value + "</Value></NoteProperty>")     | Out-Null
        }
        "ScriptMethodData"           { $xml.appendLine(
                          " <ScriptMethod><Name>$($m.name)</Name><Script>" +
                          $m.Script + "</Script></ScriptMethod>")     | Out-Null}
        "ScriptPropertyData"         {
          if($m.IsHidden)            { $xml.append(
                          " <ScriptProperty IsHidden=""true"">") | Out-Null}
          else                       { $xml.append(
                          " <ScriptProperty>")                   | Out-Null}
          $xml.AppendLine("<Name>$($m.name)</Name>")                  | Out-Null
          if ($m.GetScriptBlock)     { $xml.appendLine(
                          " <GetScriptBlock>" +
                           $m.GetScriptBlock + "</GetScriptBlock>")   | Out-Null}
          if ($m.SetScriptBlock)     { $xml.appendLine(
                          " <SetScriptBlock>" +
                          $m.SetScriptBlock +" </SetScriptBlock>")    | Out-Null}
          $xml.appendLine(" </ScriptProperty>" )                 | Out-Null
        }
      }
    }
    $xml.appendLine(      " </Members>")                           | Out-Null
    $xml.appendLine(      " </Type>")                                | Out-Null
    }
  }
  end     {
    $xml.appendLine(      "</Types>")                                 | Out-Null
    if ($ToClipboard) {Set-Clipboard $xml.ToString()}
    else {$xml.ToString() | Out-file -FilePath $Path -Encoding utf8  -NoClobber:$NoClobber}
  }
}