By default, PowerShell's ConvertFrom-Json
cmdlet does not seem to handle references in JSON documents.
{
"foo": {"$ref": "#/bar"},
"bar": true
}
I don't really know about the official status of this JSON spec (see here and here), but is there a way to manage such a thing in PowerShell?
AFAIK there are no built-in ways to resolve JSON-references. I usually search for a C# solution for a problem that's not supported in PowerShell as those can be converted to PowerShell-code most of the time, but I couldn't find an easy way to do this in C# without custom code.
So I think you might need to write some functions yourself and use something like Invoke-Expression
and reference types (which the converted object is as it is a PSCustomObject) to help you.
Proof of concept (contains many errors):
$json = @'
{
"foo": {"$ref": "#/bar"},
"bar": true
}
'@
$t = ConvertFrom-Json -InputObject $json
Write-Host "Before"
$t | Out-Host
function resolveReferences ($obj) {
#Loop through propeties
$obj.psobject.Properties | ForEach-Object {
#ref-values are PSCustomObjects with a $ref-property, so let's find the PSCustomObjects
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject') {
#Verify it was a ref-value by checking for $ref-property
if ($_.Value.'$ref') {
#Convert value to powershell-path like $t.foo
$refpath = $_.Value.'$ref'.Replace("#/",'$t.').Replace("/",".")
#Execute generated powershell-path to get the referenced object and replace reference with the referenced object
$_.Value = (Invoke-Expression -Command $refpath)
}
}
}
}
resolveReferences -obj $t
Write-host "After"
$t | Out-Host
Output:
Before
foo bar
--- ---
@{$ref=#/bar} True
After
foo bar
--- ---
True True
Which you can expand to fit your needs. Ex. support for array of objects:
$json = @'
{
"foo": {"$ref": "#/bar"},
"fooarray": [
{"item": {"$ref": "#/bar"}},
{"item": {"$ref": "#/hello"}}
],
"test": [1,2,3],
"bar": true,
"hello": "world"
}
'@
$t = ConvertFrom-Json -InputObject $json
Write-Host "Before"
$t | Out-Host
function resolveReferences ($obj) {
$obj.psobject.Properties | ForEach-Object {
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject') {
if ($_.Value.'$ref') {
$refpath = $_.Value.'$ref'.Replace("#/",'$t.').Replace("/",".")
$_.Value = (Invoke-Expression -Command $refpath)
}
} elseif ($_.TypeNameOfValue -eq 'System.Object[]') {
#If array, loop through objects (recursive search)
$_.Value | ForEach-Object { resolveReferences -obj $_ }
}
}
}
resolveReferences -obj $t
Write-host "After"
$t | Out-Host
Output:
#item properties in fooarray-objects are ref paths, it's just PS being to lazy to go deeper and show their values
Before
foo : @{$ref=#/bar}
fooarray : {@{item=}, @{item=}}
test : {1, 2, 3}
bar : True
hello : world
After
foo : True
fooarray : {@{item=True}, @{item=world}}
test : {1, 2, 3}
bar : True
hello : world
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