bin/PSTypeXml.ps1
#Requires -Assembly 'System.Xml' #region public # . $PSScriptRoot\PublicFunction.ps1 #endregion public #region Add-Node function Script:Add-AliasPropertyNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [Alias("Refer")] [string] $ReferMemberName, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ([string]::IsNullOrEmpty($Name)) { return } $AliasNode = $Root | Add-ChildNode "AliasProperty" $AliasNode | Add-ChildNode "Name" -InnerText $Name -OutNull $AliasNode | Add-ChildNode "ReferencedMemberName" -InnerText $ReferMemberName -OutNull } } function Script:Add-ScriptPropertyNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [Alias("Script")] [string] $GetScriptBlock, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ([string]::IsNullOrEmpty($Name)) { return } $ScriptNode = $Root | Add-ChildNode "ScriptProperty" $ScriptNode | Add-ChildNode "Name" -InnerText $Name -OutNull $FormatScript = $GetScriptBlock.Split("`n").Trim() | Where-Object { $_ } $GetScriptBlock = $(""; $FormatScript; "") -join "`n$("`t" * 4)" $ScriptNode | Add-ChildNode "GetScriptBlock" -InnerText $GetScriptBlock -OutNull } } function Script:Add-CodePropertyNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [Alias("Type")] [string] $TypeName, [Parameter(Position = 2)] [Alias("Method")] [string] $MethodName, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ([string]::IsNullOrEmpty($Name)) { return } $CodeNode = $Root | Add-ChildNode "CodeProperty" $CodeNode | Add-ChildNode "Name" -InnerText $Name -OutNull $ReferNode = $CodeNode | Add-ChildNode "GetCodeReference" $ReferNode | Add-ChildNode "TypeName" -InnerText $TypeName -OutNull $ReferNode | Add-ChildNode "MethodName" -InnerText $MethodName -OutNull } } function Script:Add-NotePropertyNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [string] $Value, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { $NoteNode = $Root | Add-ChildNode "NoteProperty" $NoteNode | Add-ChildNode "Name" -InnerText $Name -OutNull $NoteNode | Add-ChildNode "Value" -InnerText $Value -OutNull } } function Script:Add-MemberSetNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [Alias("Member")] [string] $MemberSetName, [Parameter(Position = 1)] [Alias("Prop")] [string] $PropertyName, [Parameter(Position = 2)] [Alias("Refers")] [string[]] $ReferProperties, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ([string]::IsNullOrEmpty($MemberSetName)) { return } $MemberSetNode = $Root | Add-ChildNode "MemberSet" $MemberSetNode | Add-ChildNode "Name" -InnerText $MemberSetName -OutNull $PropSetNode = $MemberSetNode | Add-ChildNode "Members" | Add-ChildNode "PropertySet" $PropSetNode | Add-ChildNode "Name" -InnerText $PropertyName -OutNull if ($null -ne $ReferProperties) { $ReferPropsNode = $PropSetNode | Add-ChildNode "ReferencedProperties" foreach ($_ in $ReferProperties) { $ReferPropsNode | Add-ChildNode "Name" -InnerText $_ -OutNull } } } } function Script:Add-ScriptMethodNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [string] $Script, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ([string]::IsNullOrEmpty($Name)) { return } $ScriptNode = $Root | Add-ChildNode "ScriptMethod" $ScriptNode | Add-ChildNode "Name" -InnerText $Name -OutNull $FormatScript = $Script.Split("`n").Trim() $FormatScript = $Script.Split("`n").Trim() | Where-Object { $_ } $Script = $(""; $FormatScript; "") -join "`n$("`t" * 4)" $ScriptNode | Add-ChildNode "Script" -InnerText $Script -OutNull } } function Script:Add-MemberNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [ValidateSet( "AliasProperty", "CodeProperty", "NoteProperty", "ScriptProperty", "MemberSet", "ScriptMethod")] [string] $MemberType, [Parameter(Position = 1)] [hashtable] $Member, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { if ($null -eq $Member) { return } switch ($MemberType) { "AliasProperty" { $Root | Script:Add-AliasPropertyNode @Member } "CodeProperty" { $Root | Script:Add-CodePropertyNode @Member } "NoteProperty" { $Root | Script:Add-NotePropertyNode @Member } "ScriptProperty" { $Root | Script:Add-ScriptPropertyNode @Member } "MemberSet" { $Root | Script:Add-MemberSetNode @Member } "ScriptMethod" { $Root | Script:Add-ScriptMethodNode @Member } Default { } } } } function Script:Add-TypeNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string] $Name, [Parameter(Position = 1)] [hashtable[]] $Members, [Parameter(Mandatory, ValueFromPipeline)] [System.Xml.XmlElement] $Root ) process { $TypeNode = $Root | Add-ChildNode "Type" $TypeNode | Add-ChildNode "Name" -InnerText $Name -OutNull if ($null -ne $Members) { $MembersNode = $TypeNode | Add-ChildNode "Members" foreach ($_ in $Members) { $MembersNode | Script:Add-MemberNode @_ } } } } function Add-TypesNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [hashtable[]] $Types, [Parameter()] [string] $OutXml ) process { if ($null -eq $Types) { return } [xml]$Script:doc = [xml]::new() $null = $Script:doc.AppendChild($Script:doc.CreateXmlDeclaration("1.0", "utf-8", $null)) $TypesNode = $Script:doc.AppendChild($Script:doc.CreateElement("Types")) Write-Verbose "Creat xml element - Types" foreach ($item in $Types) { $TypesNode | Script:Add-TypeNode @item } if ($OutXml -ne $null) { $Script:doc.Save($OutXml) Write-Verbose "Save in $OutXml" } } } #endregion Add-Node #region ConvertTo-PSTypeXml function Script:ConvertTo-TypeNode { [CmdletBinding()] param ( [Parameter(Position = 0)] [string[]] $InputObject ) process { $Types = Resolve-PSIndentSyntax $InputObject -Exclude "^Members" -StrArrayToRaw -Verbose:$false $Types = $Types.Types for ($i = 0; $i -lt $Types.Count; $i++) { $Members = foreach ($item in [string[]]$Types[$i].Members) { switch -Regex ($item) { '^\$_\.(?<Name>\w+)\s*->\s*\$_\.(?<Refer>\w+)$' { @{ MemberType = "AliasProperty" Member = @{ Name = $Matches.Name Refer = $Matches.Refer } } } '^\$_\.(?<Name>\w+)\s*->\s*{(?<Script>(.|\n)+)}' { @{ MemberType = "ScriptProperty" Member = @{ Name = $Matches.Name Script = $Matches.Script + "`t" } } } '^\$_\.(?<Name>\w+)\s*->\s*\[(?<Type>[A-z0-9_.]+)\]\.(?<Method>\w+)' { @{ MemberType = "CodeProperty" Member = @{ Name = $Matches.Name TypeName = $Matches.Type MethodName = $Matches.MethodName } } } '^\$_\.(?<Name>\w+)\s*->\s*\b(?<Value>.*)' { @{ MemberType = "NoteProperty" Member = @{ Name = $Matches.Name Value = $Matches.Value } } } '^\[(?<Member>\w+)\]\.(?<Prop>\w+)\s*->\s*(?<Refers>.+)$' { @{ MemberType = "MemberSet" Member = @{ Member = $Matches.Member Prop = $Matches.Prop Refers = $Matches.Refers.Split(",", [System.StringSplitOptions]1).Trim() } } } '^\$_\.(?<Name>\w+)\(\)\s*->\s*{(?<Script>(.|\n)+)}' { @{ MemberType = "ScriptMethod" Member = @{ Name = $Matches.Name Script = $Matches.Script } } } Default { } } } $Types[$i].Members = $Members } Write-Output $Types } } function ConvertTo-PSTypeXml { [CmdletBinding(DefaultParameterSetName = "Load")] param( [Parameter(Position = 0, ParameterSetName = "Load")] [string[]] $InputObject, [Parameter(Position = 0, ParameterSetName = "LoadFile")] [string] $Path, [Parameter(Position = 1, ParameterSetName = "LoadFile")] [Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding] $Encoding = "UTF8", [Parameter(ValueFromPipeline, ParameterSetName = "Load")] [Parameter(ValueFromPipeline, ParameterSetName = "LoadFile")] [Alias("Out")] [string] $OutXml = $($Path -replace "\.\w+$", ".ps1xml") ) if ($($PSCmdlet.ParameterSetName -eq "LoadFile") -and $(Test-Path $Path)) { if ($Path.EndsWith(".ps1")) { $InputObject = $(& $Path).Split("`n") } else { $InputObject = $(Get-Content $Path -Raw -Encoding $Encoding).Split("`n") } } if ($null -eq $InputObject) { return } $Types = Script:ConvertTo-TypeNode -InputObject $InputObject Add-TypesNode -Types $Types -OutXml $OutXml } #endregion ConvertTo-PSTypeXml |