ConvertTo-Expression.ps1
<#PSScriptInfo
.VERSION 2.3.0 .GUID 5f167621-6abe-4153-a26c-f643e1716720 .AUTHOR Ronald Bode (iRon) .DESCRIPTION Serializes an object to a PowerShell expression (PSON, PowerShell Object Notation). .COMPANYNAME .COPYRIGHT .TAGS PSON PowerShell Object Notation expression serialize .LICENSEURI https://github.com/iRon7/ConvertTo-Expression/LICENSE.txt .PROJECTURI https://github.com/iRon7/ConvertTo-Expression .ICONURI https://raw.githubusercontent.com/iRon7/ConvertTo-Expression/master/PsonIcon.png .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES .PRIVATEDATA #> Function ConvertTo-Expression { <# .SYNOPSIS Serializes an object to a PowerShell expression. .DESCRIPTION The ConvertTo-Expression (alias ConvertTo-Pson) cmdlet converts any object to a string in PowerShell Object Notation (PSON) format. The properties are converted to field names, the field values are converted to property values, and the methods are removed. You can then use the Invoke-Expression (alias ConvertFrom-Pson) cmdlet to convert a PSON-formatted string to a PowerShell object, which is easily managed in Windows PowerShell. .PARAMETER InputObject Specifies the objects to convert to a PSON expression. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe one or more objects to ConvertTo-Expression. .PARAMETER Depth Specifies how many levels of contained objects are included in the PSON representation. The default value is 9. .PARAMETER Expand Specifies till what level the contained objects are expanded over separate lines and indented according to the -Indentation and -IndentChar parameters. The default value is 9. A negative value will remove redundant spaces and compress the PSON expression to a single line (except for multiline strings). Xml documents and multiline strings are embedded in a "here string" and aligned to the left. .PARAMETER Indentation Specifies how many IndentChars to write for each level in the hierarchy. .PARAMETER IndentChar Specifies which character to use for indenting. .PARAMETER Type Defines how the explicite the object type is being parsed: -Type None No type information will be added to the (embedded) objects and values in the PSON string. This means that objects and values will be parsed to one of the following data types when reading them back with Invoke-Expression: a numeric value, a [String] ('...'), an [Array] (@(...)) or a [HashTable] (@{...}). -Type Native The original type prefix is added to the (embedded) objects and values in the PSON string. Note that most system (.Net) objects can’t be read back with Invoke-Expression, but -SetType Name can help to reveal (embedded) object types and hierarchies. -Type Cast (Default) The type prefix is only added to (embedded) objects and values when required and optimized for read back with Invoke-Expression by e.g. converting system (.Net) objects to PSCustomObject objects. Numeric values won't have a strict type and therefor parsed to the default type that fits the value when read back with Invoke-Expression. -Type Strict All (embedded) objects and values will have an explicit type prefix optimized for read back with Invoke-Expression by e.g. converting system (.Net) objects to PSCustomObject objects. .PARAMETER NewLine Specifies which characters to use for a new line. The default is defined by the operating system. .PARAMETER Iteration Do not use (for internal use only). .EXAMPLE PS C:\>(Get-UICulture).Calendar | ConvertTo-Expression # Convert a Calendar object to a PowerShell expression [PSCustomObject]@{ 'AlgorithmType' = 'SolarCalendar' 'CalendarType' = 'Localized' 'Eras' = 1 'IsReadOnly' = $False 'MaxSupportedDateTime' = [DateTime]'9999-12-31T23:59:59.9999999' 'MinSupportedDateTime' = [DateTime]'0001-01-01T00:00:00.0000000' 'TwoDigitYearMax' = 2029 } .EXAMPLE PS C:\>@{Account="User01";Domain="Domain01";Admin="True"} | ConvertTo-Expression -Expand -1 # Compress the PSON output @{'Admin'='True';'Account'='User01';'Domain'='Domain01'} .EXAMPLE PS C:\>Get-Date | Select-Object -Property * | ConvertTo-Expression # Convert an object to a PSON expression and to a PowerShell object [PSCustomObject]@{ 'Date' = [DateTime]'2018-01-09T00:00:00.0000000+01:00' 'DateTime' = 'Tuesday, January 9, 2018 7:22:57 PM' 'Day' = 9 'DayOfWeek' = 'Tuesday' 'DayOfYear' = 9 'DisplayHint' = 'DateTime' 'Hour' = 19 'Kind' = 'Local' 'Millisecond' = 671 'Minute' = 22 'Month' = 1 'Second' = 57 'Ticks' = 636511225776716485 'TimeOfDay' = [TimeSpan]'19:22:57.6716485' 'Year' = 2018 } PS C:\>Get-Date | Select-Object -Property * | ConvertTo-Expression | Invoke-Expression Date : 2018-01-09 12:00:00 AM DateTime : Tuesday, January 9, 2018 7:27:43 PM Day : 9 DayOfWeek : Tuesday DayOfYear : 9 DisplayHint : DateTime Hour : 19 Kind : Local Millisecond : 76 Minute : 27 Month : 1 Second : 43 Ticks : 636511228630764893 TimeOfDay : 19:27:43.0764893 Year : 2018 .EXAMPLE PS C:\>WinInitProcess = Get-Process WinInit | ConvertTo-Expression # Convert the WinInit Process to a PSON expression .EXAMPLE PS C:\>Get-Host | ConvertTo-Expression -Depth 4 # Reveal complex object hierarchies .LINK Invoke-Expression (Alias ConvertFrom-Pson) #> [CmdletBinding()][OutputType([String])]Param ( [Parameter(ValueFromPipeLine = $True)][Object[]]$InputObject, [Int]$Depth = 9, [Int]$Expand = 9, [Int]$Indentation = 1, [String]$IndentChar = "`t", [ValidateSet("None", "Native", "Cast", "Strict")][String]$TypePrefix = "Cast", [String]$NewLine = [System.Environment]::NewLine, [Int]$Iteration = 0 ) $PipeLine = $Input | ForEach-Object {$_}; If ($PipeLine) {$InputObject = $PipeLine} Function Iterate ($Value) {ConvertTo-Pson @(,$Value) $Depth $Expand $Indentation $IndentChar $TypePrefix $NewLine ($Iteration + 1)} Function Embed ($List, $Dictionary) {If ($Iteration -ge $Depth) {If ($Null -ne $Dictionary) {Return "@{}"} Else {Return "@()"}} $Items = ForEach ($Key in $List) {If ($Null -ne $Dictionary) {"'$Key'$Space=$Space" + (Iterate $Dictionary.$Key)} Else {Iterate $Key}} $Open, $Join, $Separator, $Close = If ($Null -ne $Dictionary) {"@{", ";$Space", "$LineUp$Tab", "}"} Else {"@(", ",$Space", ",$LineUp$Tab", ")"} $Open + (&{If (($Iteration -ge $Expand) -or (@($Items).Count -le 1)) {$Items -Join $Join} Else {"$LineUp$Tab$($Items -Join $Separator)$LineUp"}}) + $Close } $Object = If (@($InputObject).Count -eq 1) {@($InputObject)[0]} Else {$InputObject} If ($Null -eq $Object) {"`$Null"} Else { $Space = If ($Iteration -gt $Expand) {""} Else {" "}; $Tab = $IndentChar * $Indentation; $LineUp = "$NewLine$($Tab * $Iteration)" $Type = $Object.GetType().Name; $Cast = $Null; $Enumerator = $Object.GetEnumerator.OverloadDefinitions $Expression = If ($Object -is [Boolean]) {If ($Object) {'$True'} Else {'$False'}} ElseIf ($Object -is [Char]) {$Cast = $Type; "'$Object'"} ElseIf ($Object -is [String]) {If ($Object -Match "[`r`n]") {"@'$NewLine$Object$NewLine'@$NewLine"} Else {"'$($Object.Replace('''', ''''''))'"}} ElseIf ($Object -is [DateTime]) {$Cast = $Type; "'$($Object.ToString('o'))'"} ElseIf ($Object -is [TimeSpan] -or $Object -is [Version]) {$Cast = $Type; "'$Object'"} ElseIf ($Object -is [Enum]) {$Type = "String"; "'$($Object)'"} ElseIf ($Object -is [Xml]) {$Cast = "Xml"; $SW = New-Object System.IO.StringWriter; $XW = New-Object System.Xml.XmlTextWriter $SW $XW.Formatting = If ($Level -gt $Expand) {"None"} Else {"Indented"}; $XW.Indentation = $Indentation; $XW.IndentChar = $IndentChar $Object.WriteContentTo($XW); If ($Level -gt $Expand) {"'$SW'"} Else {"@'$NewLine$SW$NewLine'@$NewLine"}} ElseIf ($Object.GetType().Name -eq "DictionaryEntry" -or $Type -like "KeyValuePair*") {$Type = "Hashtable"; Embed $Object.Key @{$Object.Key = $Object.Value}} ElseIf ($Object.GetType().Name -eq "OrderedDictionary") {$Type = "Hashtable"; $Cast = "Ordered"; Embed $Object.Keys $Object} ElseIf ($Enumerator -match "[\W]IDictionaryEnumerator[\W]") {$Type = "Hashtable"; Embed $Object.Keys $Object} ElseIf ($Enumerator -match "[\W]IEnumerator[\W]" -or $Object.GetType().Name -eq "DataTable") {$Type = "Array"; Embed $Object} Else {$Property = $Object | Get-Member -Type Property; If (!$Property) {$Property = $Object | Get-Member -Type NoteProperty} $Names = ForEach ($Name in ($Property | Select-Object -Expand "Name")) {$Object.PSObject.Properties | Where-Object {$_.Name -eq $Name -and $_.IsGettable} | Select-Object -Expand "Name"} If ($Property) {$Type = "PSCustomObject"; $Cast = $Type; Embed $Names $Object} Else {$Object} } Switch ($TypePrefix) { 'None' {"$Expression"} 'Native' {"[$($Object.GetType().Name)]$Expression"} 'Cast' {If ($Cast) {"[$Cast]$Expression"} Else {"$Expression"}} 'Strict' {If ($Cast) {"[$Cast]$Expression"} Else {"[$Type]$Expression"}} } } } Set-Alias pson ConvertTo-Expression; Set-Alias ctex ConvertTo-Expression Set-Alias ConvertTo-Pson ConvertTo-Expression -Description "Serializes an object to a PowerShell expression." Set-Alias ConvertFrom-Pson Invoke-Expression -Description "Parses a PowerShell expression to an object." |