functions/Export-PSTypeExtension.ps1
Function Export-PSTypeExtension { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "Object")] Param( [Parameter( Position = 0, Mandatory, HelpMessage = "The type name to export like System.IO.FileInfo", ParameterSetName = "Name" )] [ValidateNotNullOrEmpty()] [String]$TypeName, [Parameter( Mandatory, HelpMessage = "The type extension name", ParameterSetName = "Name" )] [ValidateNotNullOrEmpty()] [string[]]$MemberName, [Parameter( Mandatory, HelpMessage = "The name of the export file. The extension must be .json,.xml or .ps1xml" )] [ValidatePattern("\.(xml|json|ps1xml)$")] [String]$Path, [Parameter(ParameterSetName = "Object", ValueFromPipeline)] [object]$InputObject, [Switch]$PassThru ) DynamicParam { #create a dynamic parameter to append to .ps1xml files. if ($Path -match '\.ps1xml$') { #define a parameter attribute object $attributes = New-Object System.Management.Automation.ParameterAttribute $attributes.HelpMessage = "Append to an existing .ps1xml file" #define a collection for attributes $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($attributes) #define the dynamic param $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Append", [Switch], $attributeCollection) #create array of dynamic parameters $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary $paramDictionary.Add("Append", $dynParam1) #use the array return $paramDictionary } #if } #dynamic parameter Begin { Write-Verbose "Starting: $($MyInvocation.MyCommand)" Write-Verbose "Detected parameter set $($PSCmdlet.ParameterSetName)" $PathParent = Split-Path -Path $Path if (Test-Path -Path $PathParent) { $validPath = $true } else { Write-Warning "Can't find parent path $pathParent" $validPath = $False } #test if appending if ($append -AND (Test-Path $Path)) { $validPath = $true } elseif ($append) { Write-Warning "Can't find $path for appending." $validPath = $False } #initialize a list of objects $data = [System.Collections.Generic.list[object]]::new() if ($TypeName) { Write-Verbose "Converting $TypeName to properly cased type name." $TypeName = _convertTypeName $TypeName } } Process { #test if parent path exists If ($validPath) { if ($InputObject) { Write-Verbose "Processing input type: $($InputObject.TypeName)" Write-Verbose "Converting $($InputObject.TypeName) to properly cased type name." $TypeName = _convertTypeName $InputObject.TypeName $data.Add($InputObject) } else { Write-Verbose "Processing type: $TypeName" foreach ($member in $MemberName) { $TypeMember = Get-PSTypeExtension -TypeName $TypeName -Members $Member $data.Add($TypeMember) } } } #test path parent } End { if ($validPath) { Write-Verbose "Exporting data to $path" if ($Path -match "\.ps1xml$") { if ($PSBoundParameters["Append"]) { $cPath = Convert-Path $path Write-Verbose "Appending to $cPath" [xml]$doc = Get-Content $cPath $members = $doc.types.SelectNodes("Type[Name='$TypeName']").Members if ($members) { Write-Verbose "Appending to existing TypeName entry" } else { Write-Verbose "Creating a new TypeName entry for $TypeName" $main = $doc.CreateNode("element", "Type", $null) $tName = $doc.CreateElement("Name") $tName.InnerText = $TypeName [void]($main.AppendChild($tName)) $members = $doc.CreateNode("element", "Members", $null) $IsNewType = $True } foreach ($extension in $data) { Write-Verbose "Exporting $($extension.MemberName)" $MemberType = $doc.createNode("element", $extension.MemberType, $null) $MemberNameEL = $doc.CreateElement("Name") $MemberNameEL.InnerText = $extension.MemberName [void]($MemberType.AppendChild($MemberNameEL)) Switch ($extension.MemberType) { "ScriptMethod" { $MemberDef = $doc.CreateElement("Script") } "ScriptProperty" { $MemberDef = $doc.CreateElement("GetScriptBlock") } "AliasProperty" { $MemberDef = $doc.CreateElement("ReferencedMemberName") } "NoteProperty" { $MemberDef = $doc.CreateElement("Value") } Default { Throw "Can't process a type of $($extension.MemberType)" } } #switch MemberType $MemberDef.InnerText = $extension.value [void]($MemberType.AppendChild($MemberDef)) [void]($members.AppendChild($MemberType)) } #foreach extension if ($IsnewType) { Write-Verbose "Appending new type" [void]($main.AppendChild($members)) [void]($doc.types.AppendChild($main)) } if ($PSCmdlet.ShouldProcess($cPath)) { $doc.save($cPath) } #end WhatIf } #if append else { Write-Verbose "Saving as new PS1XML" #create a placeholder file so that I can later convert the path [void](New-Item -Path $path -Force) [xml]$Doc = New-Object System.Xml.XmlDocument #create declaration $dec = $Doc.CreateXmlDeclaration("1.0", "UTF-8", $null) #append to document [void]($doc.AppendChild($dec)) #create a comment and append it in one line $text = @" This file was created with Export-PSTypeExtenstion from the PSTypeExtensionTools module which you can install from the PowerShell Gallery. Use Update-TypeData to import this file in your PowerShell session. Created $(Get-Date) "@ [void]($doc.AppendChild($doc.CreateComment($text))) #create root Node $root = $doc.CreateNode("element", "Types", $null) $main = $doc.CreateNode("element", "Type", $null) $name = $doc.CreateElement("Name") $name.InnerText = $data[0].TypeName [void]($main.AppendChild($name)) $members = $doc.CreateNode("element", "Members", $null) foreach ($extension in $data) { Write-Verbose "Exporting $($extension.MemberName)" $MemberType = $doc.createNode("element", $extension.MemberType, $null) $MemberNameEL = $doc.CreateElement("Name") $MemberNameEL.InnerText = $extension.MemberName [void]($MemberType.AppendChild($MemberNameEL)) Switch ($extension.MemberType) { "ScriptMethod" { $MemberDef = $doc.CreateElement("Script") } "ScriptProperty" { $MemberDef = $doc.CreateElement("GetScriptBlock") } "AliasProperty" { $MemberDef = $doc.CreateElement("ReferencedMemberName") } "NoteProperty" { $MemberDef = $doc.CreateElement("Value") } Default { Throw "Can't process a type of $($extension.MemberType)" } } $MemberDef.InnerText = $extension.value [void]($MemberType.AppendChild($MemberDef)) [void]($members.AppendChild($MemberType)) } #foreach extension [void]($main.AppendChild($members)) [void]($root.AppendChild($main)) [void]($doc.AppendChild($root)) $out = Convert-Path $path if ($PSCmdlet.ShouldProcess($out)) { $doc.save($out) } #end WhatIf } #else } #if ps1xml elseif ($path -match "\.xml$") { Write-Verbose "Saving as XML" $data | Export-Clixml -Path $path } else { Write-Verbose "Saving as JSON" $data | ConvertTo-Json | Set-Content -Path $Path } } #if valid path if ($PassThru) { Get-Item -Path $Path } Write-Verbose "Ending: $($MyInvocation.MyCommand)" } } #end Export-PSTypeExtension |