Skip to content

EliteLoser/ConvertTo-Json

Repository files navigation

ConvertTo-Json

ConvertTo-STJson is a pure-PowerShell ConvertTo-Json that's compatible with PowerShell version 2.

You can read about JSON syntax here: http://json.org

If you have PowerShell version 3 or higher, it's already built into the system.

Online blog documentation: https://www.powershelladmin.com/wiki/ConvertTo-Json_for_PowerShell_version_2

There's a "Send-STSplunkMessage" script/function in this repo here if you're interested in ad hoc splunking from PowerShell (v2 and up): https://github.com/EliteLoser/Send-SplunkMessage

Complex example object screenshot:

alt tag

Resulting JSON from ConvertTo-STJson:

alt tag

For a while calculated properties caused bugs for now (sort of) known reasons (some sort of inheritance), but it now works directly. I implemented a conversion of DateTime objects to a different type, ISO8601 string (2023-10-20T19:22:00), like the PowerShell team's ConvertTo-Json does (in unpredictable ways).

Get-ChildItem wat.psd1 | Select FullName, Name, LastWriteTime,
    @{ Name = 'MeasuredTime'; Expression = { [DateTime]::Now } } |
    ConvertTo-STJson
{
    "FullName": "C:\\temp\\wat.psd1",
    "LastWriteTime": "03/09/2017 19:40:21",
    "MeasuredTime": "04/14/2017 18:32:34",
    "Name": "wat.psd1"
}

Here's a demonstration of how to do the same as above using a ForEach-Object and the -InputObject parameter working on $_ and its properties.

PS C:\temp> Get-ChildItem wat.psd1 | Select FullName, Name, LastWriteTime |
ForEach-Object { ConvertTo-STJson -InputObject @{
    FullName = $_.FullName
    Name = $_.Name
    LastWriteTime = $_.LastWriteTime
    MeasuredTime = [DateTime]::Now # trying to add
} }
{
    "FullName": "C:\\temp\\wat.psd1",
    "Name": "wat.psd1",
    "MeasuredTime": "04/13/2017 04:41:55",
    "LastWriteTime": "03/09/2017 19:40:21"
}

With -Compress:

Get-ChildItem wat.psd1 | Select FullName, Name, LastWriteTime,
    @{ Name = 'MeasuredTime'; Expression = { [DateTime]::Now } } |
    ConvertTo-STJson -Compress
{"FullName":"C:\\temp\\wat.psd1","LastWriteTime":"03/09/2017 19:40:21","MeasuredTime":"04/14/2017 18:31:20","Name":"wat.psd1"}

Another demonstration of the -Compress parameter introduced in v0.8.

. C:\Dropbox\PowerShell\ConvertTo-Json\ConvertTo-STJson.ps1;
@{
    a = @{ a1 = 'val\t\nue1'; a2 = 'va\"lue2'; a3 = @(1, 't\wo\b---\f', 3) }
    b = "test", "42.3e-10"
    c = [pscustomobject] @{ c1 = 'value1'; c2 = "false"; c3 = "null" }
    d = @( @{ foo = 'bar' }, @{ foo2 = 'bar2';
    foo_inner_array = @( @{ deephash = @(@(1..4) + @('foobar', @{ hrm = 'hrmz' }));
    deephash2 = [pscustomobject] @{ a = 1 } }  )})
} | ConvertTo-STJson -Compress

{"c":{"c1":"value1","c2":"false","c3":"null"},"d":[{"foo":"bar"},{"foo_inner_array":[{"dee
phash2":{"a":1},"deephash":[1,2,3,4,"foobar",{"hrm":"hrmz"}]}],"foo2":"bar2"}],"b":["test"
,"42.3e-10"],"a":{"a1":"val\\t\\nue1","a2":"va\\\"lue2","a3":[1,"t\\wo\\b---\\f",3]}}

As of v0.8.2, calculated properties also work.

[PSCustomObject] @{ testkey = 'testvalue' } | Select *, @{ n='added'; e={'yep, added'}} | ConvertTo-STJson
{
    "added": "yep, added",
    "testkey": "testvalue"
}

Passing through $true and $false as of v0.9.2, but it turns out $null is buggy, but only when passed in as a single value (would essentially just be passed through). Will look into it. It works as a value anywhere else (array or PSobject/hash value).

PS C:\temp> ($false | ConvertTo-STJson) -eq $false
True

PS C:\temp> ($true | ConvertTo-STJson) -eq $true
True

Comparing my cmdlet to the PowerShell team's. DateTime objects are another story still. I'm unsure why they chose the /Date(01234567...)/ approach - and also with "meta properties" added (but not always...). As of 2018-06-25, I handle dates with the -DateTimeAsISO8601 parameter (terrible name). See the separate section below.

> $ComplexObject = @{
    a = @{ a1 = "value`nwith`r`nnewlines"; a2 = 'va\"lue2'; a3 = @(1, 'tw"o"', 3) }
    b = "test\u0123\foo", "42.3e-10", "2.34", 2.34
    c = [pscustomobject] @{ c1 = 'value1'; c2 = "false"; c3 = "null" }
    d = @( @{ foo = 'bar/barb' }, @{ foo2 = 'bar2';
    foo_inner_array = @( @{ deephash = @(@(1..4) + @('foobar', 
    @{ boobar = @{ nullvalue = $null; nullstring = 'null';
    trueval = $true; falseval = $false; falsestring = "false" }}));
    deephash2 = [pscustomobject] @{ a = 1.23 } }  )})
}

# PS team cmdlet output vs. mine (mine works on PSv2).
> ($ComplexObject | ConvertTo-Json -Compress -Depth 99) -eq `
  ($ComplexObject | ConvertTo-STJson -Compress)
True

DateTime handling

Specify the -DateTimeAsISO8601 parameter (or just -date for short since it's uniquely identifying in the parameter set...) to get dates formatted in the format: yyyy-MM-ddTHH:mm:ss (e.g. 2018-06-25T12:29:00 for today at the time of writing).

PS C:\temp> @{ key = @((get-date), (get-date).AddDays(-1)) } | convertto-stjson -DateTimeAsISO8601
{
    "key":
    [
        "2018-06-25T12:27:32",
        "2018-06-24T12:27:32"
    ]
}

PS C:\temp> @{ key = @((get-date), (get-date).AddDays(-1)) } | convertto-stjson -DateTimeAsISO8601 -Compress
{"key":["2018-06-25T12:27:45","2018-06-24T12:27:45"]}