I did invoke-restmethod and stored the output in variable $a and used convertTo-json and i want to remove the variables and values which are not required.
I have used $a -replace "variables" -replace "value" but it's not working
Don't try to manipulate JSON as text (as a string).
It's easier and more robust to transform the _objects ([pscustomobject] instances) representing the input JSON that Invoke-RestMethod returns:
# Assume that $fromJson was obtained as follows:
# $fromJson = Invoke-RestMethod ...
$fromJson.variables | ForEach-Object {
# Replace the property values with the current value's .value property
# value.
foreach ($prop in $_.psobject.Properties) {
$_.($prop.Name) = $prop.Value.value
}
$_ # Output the modified object.
} | ConvertTo-Json
$json.variables uses member-access enumeration to return an array of the variables property values, and the ForEach-Object command transforms the resulting objects by replacing their property values with their .value property value.
.psobject.Properties is a way of reflecting on any object's properties, and each property-information object returned has a .Name and a .Value property.
ConvertTo-Json converts the modified objects back to JSON
Given the following sample JSON input:
[
{
"variables": {
"appdata": {
"value": "x1"
},
"appinsta": {
"value": "y1"
}
}
},
{
"variables": {
"appdata": {
"value": "x2"
},
"appinsta": {
"value": "y2"
}
}
}
]
the above outputs:
[
{
"appdata": "x1",
"appinsta": "y1"
},
{
"appdata": "x2",
"appinsta": "y2"
}
]
Related
I have a text file with below data which is Dynamically generated, so the contents of the repo.txt keep changing
repo.txt -> Content as below
repo1
repo2
repo_3
And a JSON file
template.json -> Content as below
{
"name": "new-report-test-1",
"resources": {
"repositories": [
{
"name": "repoa"
},
{
"name": "repo_b"
}
]
},
"filters": {
"severities": [
"High"
]
}
}
now i want to read the repo list from the repo.txt file and update the template.json to below
{
"name": "new-report-test-1",
"resources": {
"repositories": [
{
"name": "repoa"
},
{
"name": "repo_b"
},
{
"name": "repo1"
},
{
"name": "repo2"
},
{
"name": "repo_3"
}
]
},
"filters": {
"severities": [
"High",
"Medium",
"Critical"
]
}
}
I have this bash script that does the job thiugh I'm unsure how to translate it to PoweShell. Any inputs would be highly appreciated
cat ./tmpgen_reponames.txt | while read repoEntry do echo " Repository: $repoEntry" cat <<< $(jq --arg REPOID "$repoEntry" '[ .[] , {"name":$REPOID} ]' tmpgen_repoarray.json) > tmpgen_repoarray.json done
You can accomplish this in PowerShell using ConvertFrom-Json to convert your Json into objects then following an object-oriented approach adding new custom objects to the .resources.repositories property and adding the new values Medium and Critical to the .filters.severities property of your Json, lastly, converting it back to a Json string with ConvertTo-Json:
$json = Get-Content path\to\template.json -Raw | ConvertFrom-Json
$json.resources.repositories = #(
$json.resources.repositories
(Get-Content path\to\repo.txt).Trim() | ForEach-Object {
[pscustomobject]#{ Name = $_ }
}
)
$json.filters.severities = #(
$json.filters.severities
'Medium'
'Critical'
)
$json | ConvertTo-Json -Depth 99 | Set-Content path\to\newJson.Json
I'm using PowerShell to extract data from an API call, update it and then pass it back to the API.
What I would like to know is whether or not there is a simple way to modify the JSON object, to filter out all the properties which are not desired at any location within the JSON structure?
I've tried the following, however the resultant JSON only has the lowest level properties removed (ie. "p2")
$example = ConvertFrom-Json '{"a":{"p1": "value1"},"p2": "value2", "b":"valueb"}'
$exclude = "p1", "p2"
$clean = $example | Select-Object -Property * -ExcludeProperty $exclude
ConvertTo-Json $clean -Compress
Result => {"a":{"p1":"value1"},"b":"valueb"}
I would like to have all $exlude entries removed, regardless of where they are located within the JSON. Is there a simple solution?
Update
Here is another (more complicated) JSON example:
{
"a": {
"p1": "value 1",
"c": "value c",
"d": {
"e": "value e",
"p2": "value 3"
},
"f": [
{
"g": "value ga",
"p1": "value 4a"
},
{
"g": "value gb",
"p1": "value 4b"
}
]
},
"p2": "value 2",
"b": "value b"
}
The expected result (all p1 and p2 keys removed):
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": [
{
"g": "value ga"
},
{
"g": "value gb"
}
]
},
"b": "value b"
}
Unfortunately there doesn't appear to be an easy way. It actually proved quite challenging to correctly handle arrays. My approach is to recursively unroll the input (JSON) object, including any arrays, so we can easily apply filtering, then build a new object from the filtered properties.
Steps one and three are wrapped in the following reusable helper functions, one for unroll (ConvertTo-FlatObjectValues) and one for rebuilding the object (ConvertFrom-FlatObjectValues). There is a third function (ConvertFrom-TreeHashTablesToArrays), but it is only used internally by ConvertFrom-FlatObjectValues.
Function ConvertTo-FlatObjectValues {
<#
.SYNOPSIS
Unrolls a nested PSObject/PSCustomObject "property bag".
.DESCRIPTION
Unrolls a nested PSObject/PSCustomObject "property bag" such as created by ConvertFrom-Json into flat objects consisting of path, name and value.
Fully supports arrays at the root as well as for properties and nested arrays.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline)] $InputObject,
[string] $Separator = '.',
[switch] $KeepEmptyObjects,
[switch] $KeepEmptyArrays,
[string] $Path, # Internal parameter for recursion.
[string] $Name # Internal parameter for recursion.
)
process {
if( $InputObject -is [System.Collections.IList] ) {
if( $KeepEmptyArrays ) {
# Output a special item to keep empty array.
[PSCustomObject]#{
Path = ($Path, "#").Where{ $_ } -join $Separator
Name = $Name
Value = $null
}
}
$i = 0
$InputObject.ForEach{
# Recursively unroll array elements.
$childPath = ($Path, "#$i").Where{ $_ } -join $Separator
ConvertTo-FlatObjectValues -InputObject $_ -Path $childPath -Name $Name `
-Separator $Separator -KeepEmptyObjects:$KeepEmptyObjects -KeepEmptyArrays:$KeepEmptyArrays
$i++
}
}
elseif( $InputObject -is [PSObject] ) {
if( $KeepEmptyObjects ) {
# Output a special item to keep empty object.
[PSCustomObject]#{
Path = $Path
Name = $Name
Value = [ordered] #{}
}
}
$InputObject.PSObject.Properties.ForEach{
# Recursively unroll object properties.
$childPath = ($Path, $_.Name).Where{ $_ } -join $Separator
ConvertTo-FlatObjectValues -InputObject $_.Value -Path $childPath -Name $_.Name `
-Separator $Separator -KeepEmptyObjects:$KeepEmptyObjects -KeepEmptyArrays:$KeepEmptyArrays
}
}
else {
# Output scalar
[PSCustomObject]#{
Path = $Path
Name = $Name
Value = $InputObject
}
}
}
}
function ConvertFrom-FlatObjectValues {
<#
.SYNOPSIS
Convert a flat list consisting of path and value into tree(s) of PSCustomObject.
.DESCRIPTION
Convert a flat list consisting of path and value, such as generated by ConvertTo-FlatObjectValues, into tree(s) of PSCustomObject.
The output can either be an array (not unrolled) or a PSCustomObject, depending on the structure of the input data.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipelineByPropertyName)] [string] $Path,
[Parameter(Mandatory, ValueFromPipelineByPropertyName)] [AllowNull()] $Value,
[Parameter()] [string] $Separator = '.'
)
begin {
$tree = [ordered]#{}
}
process {
# At first store everything (including array elements) into hashtables.
$branch = $Tree
do {
# Split path into root key and path remainder.
$key, $path = $path.Split( $Separator, 2 )
if( $path ) {
# We have multiple path components, so we may have to create nested hash table.
if( -not $branch.Contains( $key ) ) {
$branch[ $key ] = [ordered] #{}
}
# Enter sub tree.
$branch = $branch[ $key ]
}
else {
# We have arrived at the leaf -> set its value
$branch[ $key ] = $value
}
}
while( $path )
}
end {
# So far we have stored the original arrays as hashtables with keys like '#0', '#1', ... (possibly non-consecutive).
# Now convert these hashtables back into actual arrays and generate PSCustomObject's from the remaining hashtables.
ConvertFrom-TreeHashTablesToArrays $tree
}
}
Function ConvertFrom-TreeHashTablesToArrays {
<#
.SYNOPSIS
Internal function called by ConvertFrom-FlatObjectValues.
.DESCRIPTION
- Converts arrays stored as hashtables into actual arrays.
- Converts any remaining hashtables into PSCustomObject's.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline)] [Collections.IDictionary] $InputObject
)
process {
# Check if $InputObject has been generated from an array.
$isArray = foreach( $key in $InputObject.Keys ) { $key.StartsWith('#'); break }
if( $isArray ) {
# Sort array indices as they might be unordered. A single '#' as key will be skipped, because it denotes an empty array.
$sortedByKeyNumeric = $InputObject.GetEnumerator().Where{ $_.Key -ne '#' } |
Sort-Object { [int]::Parse( $_.Key.SubString( 1 ) ) }
$outArray = $sortedByKeyNumeric.ForEach{
if( $_.Value -is [Collections.IDictionary] ) {
# Recursion. Output array element will either be an object or a nested array.
ConvertFrom-TreeHashTablesToArrays $_.Value
}
else {
# Output array element is a scalar value.
$_.Value
}
}
, $outArray # Comma-operator prevents unrolling of the array, to support nested arrays.
}
else {
# $InputObject has been generated from an object. Copy it to $outProps recursively and output as PSCustomObject.
$outProps = [ordered] #{}
$InputObject.GetEnumerator().ForEach{
$outProps[ $_.Key ] = if( $_.Value -is [Collections.IDictionary] ) {
# Recursion. Output property will either be an object or an array.
ConvertFrom-TreeHashTablesToArrays $_.Value
}
else {
# Output property is a scalar value.
$_.Value
}
}
[PSCustomObject] $outProps
}
}
}
Usage example:
$example = ConvertFrom-Json #'
{
"a": {
"p1": "value 1",
"c": "value c",
"d": {
"e": "value e",
"p2": "value 3"
},
"f": [
{
"g": "value ga",
"p1": "value 4a"
},
{
"g": "value gb",
"p1": "value 4b"
}
]
},
"p2": "value 2",
"b": "value b"
}
'#
$exclude = "p1", "p2"
$clean = ConvertTo-FlatObjectValues $example | # Step 1: unroll properties
Where-Object Name -notin $exclude | # Step 2: filter
ConvertFrom-FlatObjectValues # Step 3: rebuild object
$clean | ConvertTo-Json -Depth 9
Output:
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": [
{
"g": "value ga"
},
{
"g": "value gb"
}
]
},
"b": "value b"
}
Usage Notes:
Child objects are removed if they don't contain any properties after filtering. Empty arrays are removed as well. You can prevent this by passing -KeepEmptyObjects and/or -KeepEmptyArrays to function ConvertTo-FlatObjectValues.
If the input JSON is an array at the root level, make sure to pass it as an argument to ConvertTo-FlatObjectValues, instead of piping it (which would unroll it and the function would no longer know it's an array).
Filtering can also be done on the whole path of a property. E. g. to remove the P1 property only within the a object, you could write Where-Object Path -ne a.p1. To see how paths look like, just call ConvertTo-FlatObjectValues $example which outputs the flat list of properties and array elements:
Path Name Value
---- ---- -----
a.p1 p1 value 1
a.c c value c
a.d.e e value e
a.d.p2 p2 value 3
a.f.#0.g g value ga
a.f.#0.p1 p1 value 4a
a.f.#1.g g value gb
a.f.#1.p1 p1 value 4b
p2 p2 value 2
b b value b
Implementation Notes:
During unrolling ConvertTo-FlatObjectValues creates separate path segments (keys) for array elements which look like "#n" where n is the array index. This allows us to treat arrays and objects more uniformly, when rebuilding the object in ConvertFrom-FlatObjectValues.
ConvertFrom-FlatObjectValues first creates nested hashtables for all objects and arrays in its process section. This makes it easy to recollect properties into their respective objects. In this part of the code there is still no special treatment of arrays. The intermediate result now looks like this:
{
"a": {
"c": "value c",
"d": {
"e": "value e"
},
"f": {
"#0": {
"g": "value ga"
},
"#1": {
"g": "value gb"
}
}
},
"b": "value b"
}
Only in the end section of ConvertFrom-FlatObjectValues, the arrays are rebuilt from the hashtables, which is done by function ConvertFrom-TreeHashTablesToArrays. It turns hashtables that have keys starting with "#" back into actual arrays. Due to filtering, the indices might be non-consecutive, so we could just collect the values and ignore the indices. Though not necessary for the given use case, the array indices will be sorted to make the function more robust and support indices that are received in any order.
Recursion in PowerShell functions is comparatively slow, because of the parameter-binding overhead. If performance is paramount, the code should be rewritten in inline C# or use data structures like Collections.Queue to avoid recursion (at the expense of code readability).
I am trying to access a particular property value of a JSON object with Powershell. Unfortunately I do not know the keys of some of the parent properties within the structure, so I cannot do this in a straightforward way. Also as the JSON is not an array I am unable to access via index position.
The context is that I am querying a list of running tasks from elasticsearch and need to get the ID of the task (I know that there will only be one) so I can make subsequent calls to discover its completion status.
I've researched some querying methods but am unsure on how to apply them (PowerShell syntax is quite new to me).
The JSON response I am working with looks like this;
"nodes" : {
"oTUltX4IQMOUUVeiohTt8A" : {
"name" : "H5dfFeA",
"transport_address" : "127.0.0.1:9300",
"host" : "127.0.0.1",
"ip" : "127.0.0.1:9300",
"tasks" : {
"oTUltX4IQMOUUVeiohTt8A:124" : {
"node" : "oTUltX4IQMOUUVeiohTt8A",
"id" : 124,
"type" : "direct",
"action" : "cluster:monitor/tasks/lists[n]",
"start_time_in_millis" : 1458585884904,
"running_time_in_nanos" : 47402,
"cancellable" : false,
"parent_task_id" : "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
With this given structure, I would like to be able to access the ID property of the first 'task'.
So if I knew the prop keys it would be:
nodes.oTUltX4IQMOUUVeiohTt8A.tasks.oTUltX4IQMOUUVeiohTt8A:124.id
How can I access this value without knowing the keys beforehand?
Any help very appreciated.
Thanks
Nick
The following code defines and uses function Get-FirstPropertyValue, which performs a recursive, depth-first search for the first property inside an object graph that has a given name and returns its value, assuming the value is non-null:
# Function that returns the value of the first property with the given
# name found during recursive depth-first traversal of the given object.
# Note that null-valued properties are ignored.
function Get-FirstPropertyValue($obj, $propName) {
$propNames = $obj.psobject.properties.Name
if ($propName -in $propNames) {
$obj.$propName
} else {
foreach ($iterPropName in $propNames) {
if ($null -ne ($val = Get-FirstPropertyValue $obj.$iterPropName $propName)) {
return $val
}
}
}
}
# Input JSON
$json = #'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'#
# Convert the JSON to a [pscustomobject] graph with ConvertFrom-Json.
$objFromJson = $json | ConvertFrom-Json
# Using the function defined above, get the first 'tasks' object found
# during recursive depth-first traversal.
$tasks = Get-FirstPropertyValue $objFromJson 'tasks'
# Get the name of the resulting object's first property.
$propName = #($tasks.psobject.properties.Name)[0]
# Extract the .id property from the object stored in the first property.
$tasks.$propName.id
The above yields:
124
A more concise, but more obscure and presumably slower alternative is to convert the JSON input to XML and then use XPath to query it:
# Input JSON
$json = #'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'#
$parent = 'tasks'
$prop = 'id'
$propType = 'int'
$json |
ConvertFrom-Json |
ConvertTo-Xml -Depth ([int]::MaxValue) |
Select-Xml "//Property[#Name='$parent']/*/*[#Name='$prop']/text()" |
ForEach-Object { $_.Node.InnerText -as $propType }
There are two ways I know of that you can achieve this, both look a bit gnarly.
For these examples, I will load the JSON you have provided into $json.
$json = #'
{
"nodes": {
"oTUltX4IQMOUUVeiohTt8A": {
"name": "H5dfFeA",
"transport_address": "127.0.0.1:9300",
"host": "127.0.0.1",
"ip": "127.0.0.1:9300",
"tasks": {
"oTUltX4IQMOUUVeiohTt8A:124": {
"node": "oTUltX4IQMOUUVeiohTt8A",
"id": 124,
"type": "direct",
"action": "cluster:monitor/tasks/lists[n]",
"start_time_in_millis": 1458585884904,
"running_time_in_nanos": 47402,
"cancellable": false,
"parent_task_id": "oTUltX4IQMOUUVeiohTt8A:123"
}
}
}
}
}
'# | ConvertFrom-Json
The first is to use Select-Object to select the first item and then expand the properties.
(($json.nodes | Select-Object -First 1 -ExpandProperty *).tasks | Select-Object -First 1 -ExpandProperty *).id
A more robust method, is to use the hidden PSObject property Value, as the JSON is parsed by PowerShell into a PSCustomObject.
PS C:\Windows\system32> $json.nodes.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
The Properties of .PSObject
PS C:\Windows\system32> $json.nodes.PSObject.Properties
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : #{name=H5dfFeA; transport_address=127.0.0.1:9300; host=127.0.0.1; ip=127.0.0.1:9300; tasks=}
TypeNameOfValue : Selected.System.Management.Automation.PSCustomObject
Name : oTUltX4IQMOUUVeiohTt8A
IsInstance : True
The full command to access the ID value:
$json.nodes.PSObject.Properties.Value.tasks.PSObject.Properties.Value.id
I'm trying to ingest a JSON file into Powershell, append a block of JSON to an existing node (Components), then convert the PSCustomObject back to JSON and save the file. The JSON I'm playing with looks something like Figure 1.
As you see in my code, I run ConvertTo-Json to cast the data into a PSCustomObject, and I then append a new object to the Components node. If I view the object, $configFile in this case it all looks fine, but when I convert back to JSON the items in the Components node, are treated as strings and not evaluated into JSON (see last snippet). I imagine this is because ConvertTo-JSON treats arrays literally, but not 100% sure.
If someone can advise how to ensure the PSCustomObjects in the Components node get casted back to JSON properly I would be grateful, thank you.
Figure 1 - the original JSON:
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
{
"Id": "ApplicationEventLog",
"FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
"Parameters": {
"LogName": "Application",
"Levels": "1"
}
},
{
"Id": "SystemEventLog",
"FullName": "AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch",
"Parameters": {
"LogName": "System",
"Levels": "7"
}
}
],
"Flows": {
"Flows":
[
"(ApplicationEventLog,SystemEventLog),CloudWatchLogs"
]
}
}
}
Figure 2 - my code:
#Requires -Version 3.0
$configFile = "C:\Program Files\Amazon\EC2ConfigService\Settings\AWS.EC2.Windows.CloudWatch.json"
$configToPSObject = ConvertFrom-Json "$(Get-Content $configFile)"
$configToPSObject.EngineConfiguration.Components += New-Object -Type PSObject -Property ([ordered]#{
"Id" = "IISRequestQueueSize"
"FullName" = "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch"
"Parameters" = [PSCustomObject]#{
"CategoryName" = "HTTP Service Request Queues"
"CounterName" = "CurrentQueueSize"
"InstanceName" = "_Total"
"MetricName" = "IISRequestQueueSize"
"Unit" = ""
"DimensionName" = ""
"DimensionValue" = ""
}
})
$configJson = ConvertTo-Json -Depth 5 $configToPSObject
Set-Content -Path $configFile -Value $configJson
Figure 3 - the JSON output:
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
"#{Id=ApplicationEventLog; FullName=AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch; Parameters=}",
"#{Id=SystemEventLog; FullName=AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch; Parameters=}",
"#{Id=IISRequestQueueSize; FullName=AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch; Parameters=}"
],
"Flows": {
"Flows":
"(ApplicationEventLog,SystemEventLog),CloudWatchLogs"
}
}
}
If I increase the depth to say, 8 or beyond, the JSON comes out as follows:
{
"EngineConfiguration": {
"PollInterval": "00:00:15",
"Components": [
"#{Id=ApplicationEventLog; FullName=AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch; Parameters=}",
"#{Id=SystemEventLog; FullName=AWS.EC2.Windows.CloudWatch.EventLog.EventLogInputComponent,AWS.EC2.Windows.CloudWatch; Parameters=}",
"Id": "IISRequestQueueSize",
"FullName": "AWS.EC2.Windows.CloudWatch.PerformanceCounterComponent.PerformanceCounterInputComponent,AWS.EC2.Windows.CloudWatch",
"Parameters": {
"CategoryName": "HTTP Service Request Queues",
"CounterName": "CurrentQueueSize",
"InstanceName": "_Total",
"MetricName": "IISRequestQueueSize",
"Unit": "",
"DimensionName": "",
"DimensionValue": ""
}
}
],
"Flows": {
"Flows": "(ApplicationEventLog,SystemEventLog),CloudWatchLogs"
}
}
}
The ConvertTo-Json cmdlet also has a Depth parameter, beyond which an object is treated with toString() instead of going deeper with recursion. So just setting that parameter to whatever max depth of objects you have should result in a correctly formed JSON.
$configJson = ConvertTo-Json $configToPSObject -Depth 8
# your JSON has depth of 5, get some extra
You have to supply the depth for the ConvertTo-Json commandlet.
Otherwise it only does the first level and leaves the subnodes as is and converts them to a string apparently.
$configJson = ConvertTo-Json $obj -Depth 3
Powershell can't seem to correctly round-trip this JSON object:
{
"settings": {
"minimumApproverCount": 2,
"creatorVoteCounts": false,
"scope": [
{
"refName": "refs/heads/d14rel",
"matchKind": "Exact",
"repositoryId": "a290117c-5a8a-40f7-bc2c-f14dbe3acf6d"
}
]
}
}
Assuming $json is a string, this command:
$json | ConvertFrom-Json | ConvertTo-Json
produces the wrong JSON out of it:
{
"settings": {
"minimumApproverCount": 2,
"creatorVoteCounts": false,
"scope": [
"#{refName=refs/heads/d14rel; matchKind=Exact; repositoryId=a290117c-5a8a-40f7-bc2c-f14db
e3acf6d}"
]
}
}
Notice it gets the "scope" variable wrong. Is there a way to fix this?
Use the parameter Depth with value 3 or larger. The default 2 is not enough, deeper data are simply converted to strings.
$json | ConvertFrom-Json | ConvertTo-Json -Depth 3
Output
{
"settings": {
"minimumApproverCount": 2,
"creatorVoteCounts": false,
"scope": [
{
"refName": "refs/heads/d14rel",
"matchKind": "Exact",
"repositoryId": "a290117c-5a8a-40f7-bc2c-f14dbe3acf6d"
}
]
}
}