I have seen many questions around this however none of the answers seem to work (please correct me if i am wrong)
I have created a function that queries an API and saves the result as a json file.
However I would like to amend the file that is saved
powershell code:
$search = ""
function searchMtgApi($searchName){
$uriSafeName = [uri]::EscapeDataString($searchName)
$res = Invoke-WebRequest "https://api.magicthegathering.io/v1/cards?name=$uriSafeName" -UseBasicParsing
$resJson = $res.content | ConvertFrom-Json
$resJson.cards | Format-Table
$resJson.cards | Select name, setName, "quantity" | ConvertTo-Json | Out-File "D:\Magic the Gathering\$searchName.json"
}
while ($search -ne "exit"){
Write-Host #'
To exit, type "Exit".
'#
$search = Read-Host "Search Magic the Gathering.IO by card name"
if($search -ne "exit"){
searchMtgApi $search
}
}
Json generated (searching for the card 'Ponder')
[
{
"name": "Ponder",
"setName": "Commander 2018",
"quantity": null
},
{
"name": "Ponder",
"setName": "Lorwyn",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic 2010",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic 2012",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic Player Rewards 2008",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic Online Promos",
"quantity": null
}
]
What I would like to do is load the file and amend the "quantity" for a particular set.
Can anyone point me in the right direction?
Update -
I will get the json content from a file:
function updateJsonFile($jsonfile){
$resJson = Get-Content "$jsonfile.json" | ConvertFrom-Json
#Edit Quantity here
$resJson | ConvertFrom-Json | Format-Table
}
Focusing just on the core question, with abridged sample input:
The following selectively updates the quantity property for an object with a given setName property value, converting from and to JSON:
$setName = 'Magic 2010' # the set name of interest
$newQuantity = 42 # new quantity
(#'
[
{
"name": "Ponder",
"setName": "Commander 2018",
"quantity": null
},
{
"name": "Ponder",
"setName": "Lorwyn",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic 2010",
"quantity": null
}
]
'# | ConvertFrom-Json) |
ForEach-Object {
if ($_.setName -eq $setName) {
$_.quantity = $newQuantity
}
$_ # pass the (possibly updated) object through.
} | ConvertTo-Json
Note the need to enclose the ConvertFrom-Json call in (...), which forces enumeration of the individual objects in the array constructed from the JSON input (see this answer for background information).
The above yields (note the updated last quantity value):
[
{
"name": "Ponder",
"setName": "Commander 2018",
"quantity": null
},
{
"name": "Ponder",
"setName": "Lorwyn",
"quantity": null
},
{
"name": "Ponder",
"setName": "Magic 2010",
"quantity": 42
}
]
Applied to your updateJsonFile function:
function updateJsonFile($jsonfile, $setName, $newQuantity){
$resJson = Get-Content "$jsonfile.json"
# Note the (...) around the ConvertFrom-Json command.
($resJson | ConvertFrom-Json) |
ForEach-Object {
if ($_.setName -eq $setName) {
$_.quantity = $newQuantity
}
$_ # pass the (possibly updated) object through.
} | ConvertTo-Json | Set-Content -Encoding Utf8 $jsonfile
}
Related
I'm trying to sort the following JSON objects by the value of the "Index" key.
JSON = {
"PIPoint": {
"Label": "\"PIPoint\"",
"Visible": "True",
"Index": "2"
},
"Description": {
"Label": "\"Description\"",
"Visible": "True",
"Index": "3"
},
"Analysis": {
"Label": "\"Analysis\"",
"Visible": "True",
"Index": "4"
},
"PIPointExist": {
"Label": "\"PIPointExist\"",
"Visible": "True",
"Index": "5"
},
"Custom Location": {
"Label": "\"Custom Location\"",
"Visible": "True",
"Index": "1"
}
}
I've try the following code but it did not work
$json = Get-Content 'C:\column.json' | ConvertFrom-Json
$json = $json | Sort-Object -Property {$_.Index}
$json | ConvertTo-Json | Out-File 'C:\\column_sorted.json'
One way to do this would be to sort the properties and use Select-Object to reorder the output:
# Return objects based on JSON strings
$jsonObjs = Get-Content 'C:\column.json' | ConvertFrom-Json
# Sorted properties list
$Properties = ($jsonObjs.psobject.properties | Sort-Object {[int]$_.Value.Index}).Name
# Create new JSON strings with new order
$jsonObjs | Select-Object $Properties | ConvertTo-Json
$jsonĀ¹ is a single object (with just 5 properties).
So you need to sort the properties:
$Data = Get-Content 'C:\column.json' | ConvertFrom-Json
$Properties = [ordered]#{}
$Data.PSObject.Properties |Sort-Object { $_.Value.Index } |ForEach-Object { $Properties[$_.Name] = $_.Value }
[pscustomobject]$Properties | ConvertTo-Json
I would call it $Json as it is no longer a Json string but an object
{
"value": [{
"ExternalKey": "12345",
"PortfolioId": "ABC",
"InceptionDate": null,
"TerminationDate": null,
"Version": 2,
"SourceRef": "ABC",
"MasterSeries": [{
"Points": [{
"Date": "1900-01-01T00:00:00+00:00",
"Name": "XYZ Name",
"Type": "IP",
"Status": "Active",
"Version": 1
}],
"ExternalKey": "12345",
"Version": 1,
"IsDeleted": false,
"SourceRef": "ABC"
}]
}]
}
I tried to loop through each level and manually selecting the keys
ForEach($d in $json.value) { $row=$d.column1+","+ $d.column2 ..
$rootProps = $d| Get-Member | Where-Object { $_.MemberType -match "Property"}
$rootProps | ForEach-Object {
if($_.Name -eq "MasterSeries") {
$d | select -Expand MasterSeries | select-object * -ExcludeProperty Points | ForEach { $row = $_.column1 + "," $_.column2 ..
}
}
and so on..... but when I export it to Out-File "Export.csv" and try importing it gives me a UTF error. Is there a better way to achieve?
If this helps any, here's the typical way to loop through json properties in powershell 5 using the hidden psobject.properties. You might search for "flatten json".
$a = get-content file.json | convertfrom-json
$a.value[0].psobject.properties | select name,value
Name Value
---- -----
ExternalKey 12345
PortfolioId ABC
InceptionDate
TerminationDate
Version 2
SourceRef ABC
MasterSeries
For this you will need to create a recursive function.
To make things easier, I recommend you to use the ConvertFrom-Json -AsHashTable parameter which will return [HashTable] objects rather than [PSCustomObject] Objects
Function Get-Values($Object) {
if ($Object -is [String]) { $Object } # A string is also Enumerable
elseif ($Object -is [Collections.IDictionary]) { $Object.get_Values() | ForEach-Object { Get-Values $_ } }
elseif ($Object -is [Collections.IEnumerable]) { $Object.GetEnumerator() | ForEach-Object { Get-Values $_ } }
else { $Object }
}
$Object = ConvertFrom-Json -AsHashTable '{
"value": [
{
"ExternalKey": "12345",
"PortfolioId": "ABC",
"InceptionDate": null,
"TerminationDate": null,
"Version": 2,
"SourceRef": "ABC",
"MasterSeries": [
{
"Points": [
{
"Date": "1900-01-01T01:00:00+01:00",
"Name": "XYZ Name",
"Type": "IP",
"Status": "Active",
"Version": 1
}
],
"ExternalKey": "12345",
"Version": 1,
"IsDeleted": false,
"SourceRef": "ABC"
}
]
}
]
}'
Get-Values $Object
12345
False
1
IP
Monday, January 1, 1900 1:00:00 AM
XYZ Name
Active
ABC
1
12345
2
ABC
ABC
I have json body in powershell variable and want to get value from it.
Json Body :
"value": [
{
"id": 1,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Default",
"isHosted": false,
"poolType": "automation",
"size": 3
},
{
"id": 2,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Hosted",
"isHosted": true,
"poolType": "automation",
"size": 10
},
{
"id": 4,
"scope": "3e93f9e6-f427-48e1-b37b-994d196e1121",
"name": "Hosted VS2017",
"isHosted": true,
"poolType": "automation",
"size": 10
}]
I want to get the id value where name=Hosted VS2017 i.e 4
powershell :
Write-Host "json body:" $projects
$id = $projects.value | where { $_.name -eq "Hosted VS2017" }
Write-Host "id :" $id
You need to convert your JSON into a powershell object before you can work with it:
$projects = $projects | ConvertFrom-Json
Then you can access its members:
#requires -Version 3
$projects.value | ? name -eq 'Hosted VS2017'
I want to read my JSON file and write the same file with a rearranged code.
My JSON file give me something like that:
{
"one": [
{
"name": { "displayName": "Alex" },
"two": [
{
"date": "20072008",
"data": {
"id": "524556",
"fullname": "Alexandre Gagne",
"name": "Alexandre",
"lastName": "Gagne"
}
}
]
}
]
}
But I want something like this
{
"id": "524556",
"fullname": "Alexandre Gagne",
"name": "Alexandre",
"lastName": "Gagne"
}
Here's the code I use:
$jsonfile118 = 'C:/Users/Web_Q/Desktop/json/8472382-2017-2018.json'
$json118 = Get-Content $jsonfile118 | Out-String | ConvertFrom-Json
$json118.stats.splits
$json118 | Add-Member -Type NoteProperty -Name "id" -Value 524556
$json118 | ConvertTo-Json -Depth 10 | Set-Content $jsonfile118
I also use another piece of code that give me what I want but only in the terminal, when I use Set-Content the output looks like this:
"{ \'id'\ 536453 }"
Here's the code:
(New-Object PSObject |
Add-Member -PassThru NoteProperty id $json118.stats.splits.getId
) | ConvertTo-Json
What you need is,
Convert the Json to Object
Select the required member
Convert back to json
$Data = $JsonString | ConvertFrom-Json
$Data.One.Two.Data | ConvertTo-Json
Using this Flatten-Object cmdlet:
#'
{
"one": [
{
"name": { "displayName": "Alex" },
"two": [
{
"date": "20072008",
"data": {
"id": "524556",
"fullname": "Alexandre Gagne",
"name": "Alexandre",
"lastName": "Gagne"
}
}
]
}
]
}
'# | ConvertFrom-Json | Flatten-Object -Depth 9 -Base "" | ConvertTo-Json
Result:
{
"one.name.displayName": "Alex",
"one.two.date": "20072008",
"one.two.data.id": "524556",
"one.two.data.fullname": "Alexandre Gagne",
"one.two.data.name": "Alexandre",
"one.two.data.lastName": "Gagne"
}
It is not exactly what you defined as "Something like this" because it uses the parent names in the property names. This is to make sure that the names are always unique as it is technical possible to have the same child names under different parents.
For a JSON like this:
{
"Tours": [{
"Code": "r",
"Name": "Tour 1",
"Tournaments": [{
"Number": "464",
"Title": "Open Tournament 1"
},
{
"Number": "047",
"Title": "Open Tournament 2"
}]
},
{
"Code": "s",
"Name": "Tour 2",
"Tournaments": [{
"Number": "524",
"Title": "Tournament 3"
},
{
"Number": "009",
"Title": "Tournament 4"
}]
}]
}
when converted to a PS custom object and saved in $data variable, I can access values under 'Tournaments' for specific 'Tours' like this:
$data.Tours[0].Tournaments
$data.Tours[1].Tournaments
But, is it possible to access 'Tournaments' properties and values by specifying 'Code' or 'Name' values under 'Tours'? Something like that, maybe:
$data.Tours.Code['r'].Tournaments
Actually, in a PS script I want to filter data by 'Code' under 'Tours' and get underlying 'Tournaments' (get 'Tournaments' for specific 'Code' of the 'Tours').
You would need to do something like:
$data.Tours | Where-Object { $_.Code -eq 'r' } | Select-Object -ExpandProperty 'Tournaments'
To get the list of concatenated codes and tournament numbers (where the code is "r") you could do:
$data.Tours | Where-Object { $_.Code -eq 'r' } | ForEach-Object { $Code = $_.Code; $_.Tournaments | ForEach-Object { $Code + $_.Number }}