PowerShell ConvertTo-JSON with multiple arrays - arrays

I'm trying to convert data to JSON as input for a REST API. The challenge I have is that the data should consist of multiple depths (For a lack of better words). The code I'm using now is:
(#{name = "Contoso"; all_assets = "false"; all_users="false"; rules= #{type="fqdn"; operator="match"; terms=#("contoso") } }| ConvertTo-Json)
the output now is:
{
"all_users": "false",
"name": "Contoso",
"all_assets": "false",
"rules": {
"operator": "match",
"terms": [
"contoso"
],
"type": "fqdn"
}
}
The REST-Api is complaining that the data contains invalid characters. Looking at the output, the section "rules:" contains { } instead of [ ]. I've been trying all kinds of tricks but I can't seem to figure this one out.
Anyone know what I'm doing wrong here?

If you want rules to contain an array of objects instead of an object with properties, enclose everything that goes inside the rules with #().
Because terms then becomes the 3rd level, you need to add parameter -Depth to the ConvertTo-Json cmdlet:
For better readability, I didn't do this as one-liner
#{
name = "Contoso"
all_assets = "false"
all_users = "false"
rules = #(
#{
type = "fqdn"
operator = "match"
terms = #("contoso")
}
)
} | ConvertTo-Json -Depth 3
Output:
{
"all_users": "false",
"name": "Contoso",
"all_assets": "false",
"rules": [
{
"operator": "match",
"terms": [
"contoso"
],
"type": "fqdn"
}
]
}

For what it's worth...
Not the answer to the Unexpected ConvertTo-Json results? Answer: it has a default -Depth of 2 issue, but how you might generally build a PowerShell expression from a Json file using ConvertTo-Expression cmdlet:
'{
"all_users": "false",
"name": "Contoso",
"all_assets": "false",
"rules": [
{
"operator": "match",
"terms": [
"contoso"
],
"type": "fqdn"
}
]
}' | ConvertFrom-Json | ConvertTo-Expression
[pscustomobject]#{
'all_users' = 'false'
'name' = 'Contoso'
'all_assets' = 'false'
'rules' = ,[pscustomobject]#{
'operator' = 'match'
'terms' = ,'contoso'
'type' = 'fqdn'
}
}

Related

How to add a value to an existing JSON object via Powershell

I have pulled a large amount of data from a website via REST and converted it to JSON.
I have extracted the specific entry in JSON I need to edit. See below
$variables = contains all the data converted to JSON
$dacpacvariable = contains the specific entry I need to edit (which is below)
{
"Id": "c1f4fe9b-3c4d-8j02-0e7x-0a6528bn192c",
"Name": "Variable1",
"Value": "abc123",
"Description": null,
"Scope": {
"Machine": [
"Machines-1"
]
},
}
I need to edit the scope section to look like the following:
"Scope": {
"Machine": [
"Machines-1",
"Machines-2"
]
},
And then add the whole entry with the edited scope back to the larger JSON.
Any ideas?
You might simply replace the Attribute "Machine" with its new value like:
$dacpacvariable = $dacpacvariable.Scope.Machine = $dacpacvariable.Scope.Machine + "Machines-2"
Do you mean something like this:
$json = #'
{
"Id": "c1f4fe9b-3c4d-8j02-0e7x-0a6528bn192c",
"Name": "Variable1",
"Value": "abc123",
"Description": null,
"Scope": {
"Machine": [
"Machines-1"
]
}
}
'# | ConvertFrom-Json
$json.Scope.Machine += 'Machines-2'
$json | ConvertTo-Json # -Depth 99 unsure how many nestings there are in the complete json
Output:
{
"Id": "c1f4fe9b-3c4d-8j02-0e7x-0a6528bn192c",
"Name": "Variable1",
"Value": "abc123",
"Description": null,
"Scope": {
"Machine": [
"Machines-1",
"Machines-2"
]
}
}

How to add objects to a blank array in a json file using powershell

here is my json body .
{
"source": 2,
"revision": 3,
"description": null,
"triggers": [],
"releaseNameFormat": "Release-$(rev:r)",
"tags": [],
"pipelineProcess": {
"type": 1
},
"properties": {
"DefinitionCreationSource": {
"$type": "System.String",
"$value": "BuildSummary"
},
"System.EnvironmentRankLogicVersion": {
"$type": "System.String",
"$value": "2"
}
},
"id": 5,
"name": "CheckListAPI - CD",
"path": "\\Admin",
"projectReference": null,
"url": "",
"_links": {
"self": {
"href": ""
},
"web": {
"href": ""
}
}
}
I want to add some values inside the brackets at "triggers": [],
What I'm trying to get is:
"triggers":
[
{
"artifactAlias": "_DV_NJ_PIPE",
"triggerConditions": [],
"triggerType": 1
}
],
i tried -replace and replace() saving the json file to local system, but none of them are working, I even tried to edit the json file directly like this but failed.
$alias = $json.triggers
foreach ($artifact in $alias )
{
$artifact.artifactAlias = "_$DefName"
$artifact.triggerConditions = "{}"
$artifact.triggertype = "artifactSource"
}
Please help.
You can import the json file as PowerShell objects, manipulate the structure until it looks the way you want it to and export it back to json format:
$pipeline = Get-Content .\input.json | ConvertFrom-Json
$trigger = [ordered]#{
artifactAlias = "_DV_NJ_PIPE"
triggerConditions = #()
triggerType = 1
}
$pipeline.triggers += $trigger
$pipeline | ConvertTo-Json -Depth 5 | Out-File .\output.json
As it was pointed out in the comments, it is of course also possible to import the trigger definition from a json file instead of building it in a hash table.

Flatten a hierarchical JSON array using JQ

Can anyone help me get the correct jq command to flatten the below example? I've seen a few other posts and I'm hacking away at it but can't seem to get it. I'd greatly appreciate any help.
Input:
[
{
"name": "level1",
"children": [
{
"name": "level2",
"children": [
{
"name": "level3-1",
"children": []
},
{
"name": "level3-2",
"children": []
}
]
}
]
}
]
Output:
[
{
"displayName": "level1",
"parent": ""
},
{
"displayName": "level2",
"parent": "level1"
},
{
"displayName": "level3-1",
"parent": "level2"
},
{
"displayName": "level3-2",
"parent": "level2"
}
]
Here's a straightforward solution that does not involve a helper function and actually solves a more general problem. It is based on the idea of beginning by adding a "parent" key to each child, and then using .. to collect all the name/parent pairs.
So first consider:
[ walk(if type=="object" and has("children")
then .name as $n | .children |= map(.parent = $n)
else . end)
| ..
| select(type=="object" and has("name"))
| {displayName: .name, parent}
]
This meets the requirements except that for the top-level (parentless) object, it produces a .parent value of null. That would generally be more JSON-esque than "", but if the empty string is really required, one has simply to replace the last non-trivial line above by:
| {displayName: .name, parent: (.parent // "")}
With a simple recursive function:
def f: .name as $parent | .children[] | {$parent, displayName: .name}, f;
[ {name: "", children: .} | f ]
Online demo

Convert JSON array object to String in Powershell

I am working with a JSON like that looks like this:
[
{
"Ack": "no",
"Rule": "dont",
"Tags": [
"server"
],
"Type": "blue"
},
{
"Ack": "no1",
"Rule": "knock",
"Tags": [
"yellow",
"green"
],
"Type": "multiplecolour"
}
]
I need to convert the Tags array into a comma-separated string [and replace the array with the converted string in the JSON file]. I have tried converting from JSON, but I am struggling to convert the array into string in a clean way, still learning PS so please bear with me.
ConvertFrom-Json may work for you. Here's an example of converting your JSON string to an array of PowerShell objects, then joining the tags for each object with a comma delimiter:
$json = #"
[
{
"Ack": "no",
"Rule": "dont",
"Tags": [
"server"
],
"Type": "blue"
},
{
"Ack": "no1",
"Rule": "knock",
"Tags": [
"yellow",
"green"
],
"Type": "multiplecolour"
}
]
"#
(ConvertFrom-Json -InputObject $json) `
| ForEach-Object { $_.Tags = ($_.Tags -join ","); $_ } `
| ConvertTo-Json `
| Out-File -FilePath new.json
EDIT: Note (as #mklement0 points out), the parentheses around ConvertFrom-Json are required to force the enumeration of the results as an array of objects through the pipeline.

JQ: Remove object from multiple arrays

I want to use jq to remove all objects with a given name from all arrays in the input data. For example deleting "Name1" from this:
{
"Category1": [
{
"name": "Name1",
"desc": "Desc1"
},
{
"name": "Name2",
"desc": "Desc2"
}
],
"Category2": [
{
"name": "Name1",
"desc": "Desc1"
},
{
"name": "Name3",
"desc": "Desc3"
}
],
"Category3": [
{
"name": "Name4",
"desc": "Desc4"
}
]
}
Should yield this:
{
"Category1": [
{
"name": "Name2",
"desc": "Desc2"
}
],
"Category2": [
{
"name": "Name3",
"desc": "Desc3"
}
],
"Category3": [
{
"name": "Name4",
"desc": "Desc4"
}
]
}
I haven't worked with jq, or indeed JSON, much and after several hours of googling and experimenting I haven't been able to figure it out. How would I do this?
The closest I managed was this:
cat input | jq 'keys[] as $k | .[$k] |= map( select( .name != "Name1"))'
This does filter each of the arrays but returns the result as three separate objects and this is not what I want.
If the structure of your input JSON is always as seen on your example, try this:
map_values(map(select(.name != "Name1")))
Here is a solution that will remove all objects with the specified name, wherever they occur. It uses the generic function walk/1,
which is a built-in in versions of jq > 1.5, and can therefore be omitted if your jq includes it, but there is no harm in including it redundantly, e.g. in a jq script.
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
walk(if type == "object" and .name == "Name1" then empty else . end)
If you really only want to remove objects from arrays, then you could use:
walk(if type == "array" then map(select( type != "object" or .name != "Name1")) else . end)
Here is a solution which uses reduce and del
reduce keys[] as $k (
.
; del(.[$k][] | select(.name == "Name1"))
)

Resources