Skip to content

Instantly share code, notes, and snippets.

@Chirishman
Last active July 23, 2018 16:56
Show Gist options
  • Save Chirishman/018499555da4cd1165d5d75dfc341e18 to your computer and use it in GitHub Desktop.
Save Chirishman/018499555da4cd1165d5d75dfc341e18 to your computer and use it in GitHub Desktop.
Convert to PowerShell Object Notation
function ConvertTo-PSON {
<#
.SYNOPSIS
Generates a PowerShell object-notation in the style of a PSD1 document
.DESCRIPTION
This stringifies a PowerShell object following the style of a PSD1 document, the powerShell-equivalent of JSON. The behavior is incomplete but works fine for simple objects.
.EXAMPLE
$array=@()
$array+=Get-Process wi* | Select-Object Handles,NPM,PM,WS,VM,CPU,Id,ProcessName
ConvertTo-PSON $array
.EXAMPLE
Import-PowerShellDataFile -Path C:\FakePath\FakeFilename.psd1 | ConvertTo-PSON
.PARAMETER Object
the object that you want scripted out
.PARAMETER Depth
The depth that you want your object scripted to
.PARAMETER Nesting Level
internal use only. required for formatting
#>
[CmdletBinding()]
param (
[Parameter(
Position = 0,
Mandatory = $true,
ValueFromPipeline = $true
)]
[AllowNull()]
$InputObject,
[Parameter(
Position = 1,
Mandatory = $false,
ValueFromPipeline = $false
)]
[int]
$depth = 16,
[Parameter(
Position = 2,
Mandatory = $false,
ValueFromPipeline = $false,
DontShow = $true
)]
[int]
$NestingLevel = 0,
[Parameter(
Position = 3,
Mandatory = $false,
ValueFromPipeline = $false
)]
[int]
$XMLAsInnerXML = 0
)
BEGIN {
[string[]]$BasicTypes = @(
'boolean',
'byte',
'char',
'datetime',
'decimal',
'double',
'float',
'single',
'guid',
'int',
'int32',
'int16',
'long',
'int64',
'OutOfDepth',
'RuntimeType',
'PSNoteProperty',
'regex',
'sbyte',
'string',
'timespan',
'uint16',
'uint32',
'uint64',
'uri',
'version',
'void',
'xml',
'datatable',
'List`1',
'SqlDataReader',
'datarow',
'ScriptBlock',
'type'
)
[string]$BasePadding = ' '
[string]$padding = $BasePadding * $NestingLevel # lets just create our left-padding for the block
[int32]$ArrayEnd=0; #until proven false
}
PROCESS
{
If ($inputObject -eq $Null) { $p += '$Null'; return $p } # if it is null return null
try
{
[string]$Type = $inputObject.GetType().Name # we start by getting the object's type
if ($Type -ieq 'Object[]') {
# see what it really is
$Type = [string]($inputObject.GetType().BaseType.Name)
}
if ($depth -ilt $NestingLevel) {
#report the leaves in terms of object type
$Type = 'OutOfDepth'
} elseif ($Type -ieq 'XmlDocument' -or $Type -ieq 'XmlElement') {
# convert to PS Alias
$Type = $(
if ($XMLAsInnerXML -ne 0) {
'InnerXML'
} else {
'XML'
}
)
}
# prevent these values being identified as an object
if ($BasicTypes -notcontains $type) {
$Type = $(
if ($Type -ieq 'OrderedDictionary') {
# for our purposes it is a hashtable
'HashTable'
}
elseif ($Type -ieq 'PSCustomObject') {
'PSObject'
} elseif ($inputObject -is "Array") {
# whatever it thinks it is called
'Array'
}
elseif ($inputObject -is "HashTable") {
'HashTable'
}
elseif (($inputObject | gm -membertype Properties | Select name | Where name -like 'Keys') -ne $null) {
#use dot notation
'generic'
}
elseif (($inputObject | gm -membertype Properties | Select name).count -gt 1) {
'Object'
} else {
Write-Error -Exception 'UNIDENTIFIED TYPE' -Message 'Help! Unidentified type!' -ErrorAction Stop
}
)
}
write-verbose "$($padding)Type:='$Type', Object type:=$($inputObject.GetType().Name), BaseName:=$($inputObject.GetType().BaseType.Name) $NestingLevel "
switch ($Type)
{
'ScriptBlock' {
@(
'[',
$type,
'] {',
($inputObject.ToString()),
'}'
) -join $Null
}
'InnerXML' {
# use a 'here' string
@(
'[',
$type,
"]@'`r`n",
($inputObject.OuterXMl),
"`r`n'@`r`n"
) -join $Null
}
'DateTime' {
# s=SortableDateTimePattern (based on ISO 8601) local time
@(
"[datetime]'",
($inputObject.ToString('s')),
"'"
) -join $Null
}
'Boolean' {
@(
"[bool] `$",
$inputObject
) -join $null
}
'string' {
if ($inputObject -match '[\r\n]') {
@(
"@'`r`n",
[string]$inputObject,
"`r`n'@"
) -join $null
} else {
@(
"'",
[string]($inputObject -replace "'", "''"),
"'"
) -join $null
}
}
'Char' {
@(
'[',
$type,
']',
([int]$inputObject)
) -join $Null
}
{ @('byte', 'decimal', 'double', 'float', 'single', 'int', 'int32', 'int16', 'long', 'int64', 'sbyte', 'uint16', 'uint32', 'uint64') -contains $_ } {
"$inputObject"
} # rendered as is without single quotes
'PSNoteProperty' {
"$(ConvertTo-PSON -inputObject $inputObject.Value -depth $depth -NestingLevel ($NestingLevel))"
}
'Array' {
$ArrayEnd = [int][bool]($inputObject.count)
@(
"`r`n",
$padding,
"@(",
(
(
[string](
$inputObject | ForEach {
@(
",",
(
ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1)
)
) -join $Null
}
)
).Substring($ArrayEnd)
),
"`r`n",
$padding,
")"
) -join $Null
}
'HashTable' {
$ArrayEnd = [int][bool]($inputObject.count)
@(
"`r`n",
$padding,
'@{',
(
(
[string](
$inputObject.GetEnumerator() | ForEach {
@(
"; `r`n",
($BasePadding * ($NestingLevel + 1)),
'''',
$_.Name,
''' = ',
(
ConvertTo-PSON -inputObject $_.Value -depth $depth -NestingLevel ($NestingLevel + 1)
)
) -join $Null
}
)
).Substring($ArrayEnd)
),
"`r`n",
$padding,
'}'
) -join $Null
}
'PSObject' {
@(
"`r`n$padding[pscustomobject]@{" + ("$($inputObject.PSObject.Properties | ForEach {$ArrayEnd=1; "; '$($_.Name)' = " + (ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1)) })".Substring($ArrayEnd) + "`r`n$padding}")
)
}
'Dictionary' {
@(
"`r`n$padding@{" + ($inputObject.item | ForEach {$ArrayEnd=1; '; ' + "'$_'" + " = " + (ConvertTo-PSON -inputObject $inputObject.Value[$_] -depth $depth -NestingLevel $NestingLevel+1) }) + '}'
) -join $Null
}
'Generic' {
@(
"`r`n$padding@{" + ("$($inputObject.Keys | ForEach {$ArrayEnd=1; "; $_ = $(ConvertTo-PSON -inputObject $inputObject.$_ -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}")
) -join $Null
}
'Object' {
@(
"`r`n$padding@{" + ("$($inputObject | Get-Member -membertype properties | Select-Object name | ForEach {$ArrayEnd=1; "; $($_.name) = $(ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $NestingLevel -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}")
) -join $Null
}
'XML' {
@(
"`r`n$padding@{" + ("$($inputObject | Get-Member -membertype properties | where name -ne 'schema' | Select-Object name | ForEach {$ArrayEnd=1; "; $($_.name) = $(ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1))" })".Substring($ArrayEnd) + "`r`n$padding}")
) -join $Null
}
'Datatable' {
$ArrayEnd = [int][bool]($inputObject.count)
@(
"`r`n",
$padding,
"@{",
(
@(
$inputObject.TableName,
"=`r`n",
$padding,
" @(",
(
(
[string](
$inputObject | ForEach {
@(
",",
(ConvertTo-PSON -inputObject $_ -depth $depth -NestingLevel ($NestingLevel + 1))
) -join $Null
}
)
).Substring($ArrayEnd)
),
"`r`n",
$padding,
" )`r`n",
$padding,
"}"
) -join $Null
)
) -join $Null
}
'DataRow' {
$ArrayEnd = [int][bool]($inputObject.count)
@(
"`r`n",
$padding,
"@{",
(
(
[string](
$inputObject | Get-Member -membertype properties | Select-Object name | ForEach {
@(
"; ",
$_.name,
"= ",
(
ConvertTo-PSON -inputObject $inputObject.$($_.name) -depth $depth -NestingLevel ($NestingLevel + 1)
)
) -join $Null
}
)
).Substring($ArrayEnd)
),
"}"
) -join $Null
}
default {
"'$inputObject'"
}
}
}
catch
{
write-error "Error'$($_)' in script $($_.InvocationInfo.ScriptName) $($_.InvocationInfo.Line.Trim()) (line $($_.InvocationInfo.ScriptLineNumber)) char $($_.InvocationInfo.OffsetInLine) executing $($_.InvocationInfo.MyCommand) on $type object '$($inputObject.Name)' Class: $($inputObject.GetType().Name) BaseClass: $($inputObject.GetType().BaseType.Name) "
}
finally {}
}
END {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment