I have
function Foo($a, $b)
{
$o = @{}
$o.A = $a
$o.B = $b
$post = @{}
$post.X="x"
$post.entity =$o
$newton::SerializeObject($post)
}
then do
foo "a" "b"
I get
Exception calling "SerializeObject" with "1" argument(s): "Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'. Path 'entity.Members[0]'."
however
function Foo2($o)
{
$post = @{}
$post.X="x"
$post.entity =$o
$newton::SerializeObject($post)
}
foo2 @{a="a"; b="b"}
works fine. Also
function foo3($a, $b)
{
$o = @{}
$o.A = $a
$o.B = $b
$newton::SerializeObject($o)
}
foo3 "a" "b"
works but
foo3 "a" 1
fails
The latter can be made to work by doing
$o.B= [Int32]::Parse($b.Tostring())
Which all seems very odd
powershell v2 on windows 7, json.net 4.4.5
The JavaScriptSerializer
from the .NET framework also has a similar problem with serializing PowerShell's hashes. I suspect it something slightly odd in the PowerShell type system. You could skip Json.Net altogether and roll your own.
Below is something to start you off. It's likely not as robust as PowerShell 3's built-in ConvertTo-Json
cmdlet, but I think it's mostly complete.
Here are all of your examples, in working order.
# See below for ConvertTo-Json.psm1
Import-Module ConvertTo-Json
function Foo($a, $b)
{
$o = @{}
$o.A = $a
$o.B = $b
$post = @{}
$post.X="x"
$post.entity =$o
ConvertTo-Json $post
}
function Foo2($o)
{
$post = @{}
$post.X="x"
$post.entity =$o
ConvertTo-Json $post
}
function foo3($a, $b)
{
$o = @{}
$o.A = $a
$o.B = $b
ConvertTo-Json $o
}
PS> foo "a" "b"
{"entity":{"A":"a","B":"b"},"X":"x"}
PS> foo2 @{a="a"; b="b"}
{"entity":{"a":"a","b":"b"},"X":"x"}
PS> foo3 "a" "b"
{"A":"a","B":"b"}
PS> foo3 "a" 1
{"A":"a","B":1}
And here's the PowerShell module that implements ConvertTo-Json
.
# Save these contents to Modules\ConvertTo-Json\ConvertTo-Json.psm1 in your
# PowerShell documents folder, and load them in your $profile using the
# "Import-Module ConvertTo-Json" cmdlet. This will make the ConvertTo-Json cmdlet
# available for use.
Set-StrictMode -Version Latest
function convertToJsonNull($InputObject) {
"null"
}
function convertToJsonArray($InputObject) {
$value = ($InputObject | %{ convertToJson $_ }) -join ','
"[$value]"
}
function convertToJsonHash($InputObject) {
$value = ($InputObject.Keys | %{
$name = $_ | asJsonString
$itemValue = convertToJson ($InputObject[$_])
'"{0}":{1}' -f $name, $itemValue
}) -join ','
"{$value}"
}
function convertToJsonObject($InputObject) {
$value = ($InputObject | get-member -membertype *property | %{
$name = $_.Name
$value = convertToJson ($InputObject.($name))
'"{0}":{1}' -f ($name | asJsonString), $value
}) -join ','
"{$value}"
}
function convertToJsonString($InputObject) {
'"{0}"' -f ($InputObject | asJsonString)
}
function convertToJsonBool($InputObject) {
$InputObject.ToString().ToLower()
}
function convertToJsonNumeric($InputObject) {
"$InputObject"
}
function convertToJsonDate($InputObject) {
$epoch = [datetime]"1970-01-01T00:00:00Z"
$elapsed = [long]($InputObject - $epoch).TotalMilliseconds
'"\/Date({0})\/"' -f $elapsed
}
filter isNumeric() {
$_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or
$_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or
$_ -is [float] -or $_ -is [double] -or $_ -is [decimal]
}
filter asJsonString {
($_ -replace '\\', '\\') -replace '"', '\"'
}
function convertToJson($InputObject) {
if ($InputObject -eq $null) { convertToJsonNull $InputObject }
elseif ($InputObject -is [array]) { convertToJsonArray $InputObject }
elseif ($InputObject -is [hashtable]) { convertToJsonHash $InputObject }
elseif ($InputObject -is [datetime]) { convertToJsonDate $InputObject }
elseif ($InputObject -is [string]) { convertToJsonString $InputObject }
elseif ($InputObject -is [char]) { convertToJsonString $InputObject }
elseif ($InputObject -is [bool]) { convertToJsonBool $InputObject }
elseif ($InputObject | isNumeric) { convertToJsonNumeric $InputObject }
else { convertToJsonObject $InputObject }
}
function ConvertTo-Json {
[CmdletBinding()]
param(
[Parameter(
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
$InputObject
)
convertToJson $InputObject
}
Export-ModuleMember -Function ConvertTo-Json
The self referencing loop issue sems to be all about.... the order in which you assign things. The below example works:
function Foo($a, $b)
{
$o = @{}
$post = @{}
$post.entity =$o
$o.A = $a
$o.B = $b
$post.X="x"
[Newtonsoft.Json.JsonConvert]::SerializeObject($post)
}
Foo "a" "b"
{"entity":{"A":"a","B":"b"},"X":"x"}
If you convert the type before you pass it in then it will keep your foo3 function generic:
function foo3($a, $b)
{
$o = @{}
$o.A = $a
$o.B = $b
[Newtonsoft.Json.JsonConvert]::SerializeObject($o)
}
$var2 = [Int32]::Parse((1).Tostring())
Foo3 "a" $var2
{"A":"a","B":1}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With