Get specific value from JSON array after comparison using PowerShell? - arrays

I want to get specific value once key is matched from JSON array object
Input:
[
{
"Id": "19A7A3C4",
"displayName": "somename",
"tags": [
{
"context": "CONTEXTLESS",
"key": "apple",
"value": "10"
},
{
"context": "CONTEXTLESS",
"key": "orange",
"value": "20"
},
{
"context": "CONTEXTLESS",
"key": "grapes",
"value": "30"
}
]
},
{
"Id": "111111",
"displayName": "somename",
"tags": [
{
"context": "CONTEXTLESS",
"key": "cat",
"value": "10"
},
{
"context": "CONTEXTLESS",
"key": "cat",
"value": "20"
}
]
}
]
I want to get the value of tag where key matches to cat and value matches to 10, I am using below query but getting whole object
$content = Get-Content -Raw -Path "data.json" | ConvertFrom-Json
$content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"}
Desired Output: 10

Mathias's answer already shows a clean way to solve the problem.
A similar approach is using the intrinsic method .Where{}:
$tagValues = $content.tags.Where{ $_.key -eq "cat" -and $_.value -eq "10" }.value
$content.tags employs member enumeration to collect all tags properties into an array. .Where{} filters array elements similar to Where-Object. Lastly .value uses member enumeration again to collect the filtered tag values into an array.
Intrinsic methods like .Where{} are supposed to be faster than pipeline commands because they don't involve the overhead of the pipeline machinery.
If you want to keep your original query, you have to deal with nested properties.
Use grouping operator () and dot notation to extract a given property:
$tagValues = ($content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"}).tags.value
An alternative is Select-Object with parameter -ExpandProperty (alias -Expand), but it doesn't work as straightforward for nested properties (yet):
$tagValues = $content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"} |
Select-Object -Expand tags | Select-Object -Expand value
A more straightforward alternative is ForEach-Object:
$tagValues = $content | Where-Object{ $_.tags.key -eq "cat" -and $_.tags.value -eq "10"} |
ForEach-Object { $_.tags.value }

Enumerate all tags, then use ForEach-Object to grab just the value property of any match:
$content.tags | Where-Object { $_.key -eq "cat" -and $_.value -eq "10"} |ForEach-Object -MemberName value

Related

Powershell - json File - select only first value

I've got this json file:
[
{
"group": [313, 312, 313, 311],
"group_name": ["example", "example", "example1"],
"status": ["not_available_time", "no_time"]
}
]
And in Powershell I want the output to be:
313, example, not_available_time
So I always need just the first value.
I've tried this:
$responseJson = ConvertFrom-Json $response.Content
$group = $responseJson.group[0]
$name = $responseJson.group_name[0]
$status = $responseJson.status[0]
That works. But only if there is always more than one value.
For example: if "group_name" in the JSON file would only hold the value "example" (and not ["example", "example", "example1"]) => the output would only be "e" instead of "example". It takes not the first value, but only the first letter if there is only one value.
How can I select the first value?
BR and thanks!
There are 2 safe methods to ensure you're always selecting the first Value, be it an array, a scalar or null:
You can use the array subexpression operator #(), which will ensure that even if the value is $null or [System.Management.Automation.Internal.AutomationNull]::Value the result will always be an array (object[]):
#([System.Management.Automation.Internal.AutomationNull]::Value).GetType().Name # => Object[]
#($null).GetType().Name # => Object[]
As an alternative, Select-Object with the -First 1 argument, the difference is the returned object's Type remains the same:
(1 | Select-Object -First 1).GetType().Name # => Int32
('a', 'b' | Select-Object -First 1).GetType().Name # => String
$null -eq ($null, $null | Select-Object -First 1) # => True
Both alternatives are valid and depends on your use case which one fits your need better:
$json = #'
[
{
"group": [313, 312, 313, 311],
"group_name": "single_element",
"status": null
}
]
'# | ConvertFrom-Json
$json.PSObject.Properties | ForEach-Object {
$arr = #($_.Value)[0]
$slo = $_.Value | Select-Object -First 1
[pscustomobject]#{
'ArraySubExpression' = "[ {0}: $arr ]" -f $_.Name
'Select-Object' = "[ {0}: $slo ]" -f $_.Name
}
}
ArraySubExpression Select-Object
------------------ -------------
[ group: 313 ] [ group: 313 ]
[ group_name: single_element ] [ group_name: single_element ]
[ status: ] [ status: ]

Cannot retrieve ARM output array in powershell when using New-AzureRmResourceGroupDeployment

I have a simple ARM template that outputs an array of elements. I am trying to retrieve said array of elements in powershell, but nothing seems to help. It seems like the deployment result does contain the values of the array, but as soon as I try to navigate to it they become empty strings.
Ideally I want to retrieve the array output from the ARM template into a powershell variable.
ARM template:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
},
"variables": {
"test": [
"value1",
"value2"
]
},
"resources": [
],
"outputs": {
"result": {
"type": "array",
"value": "[variables('test')]"
}
}
}
Everything I have tried:
Powershell code:
$name = ((Get-Date).ToUniversalTime()).ToString('MMdd-HHmmss')
$deploymentResult = New-AzureRmResourceGroupDeployment `
-Name $name `
-ResourceGroupName test4 `
-TemplateFile 'test2.json' `
-Force -Verbose `
-ErrorVariable ErrorMessages
if ($ErrorMessages) {
Write-Output '', 'Template deployment returned the following errors:', #(#($ErrorMessages) | ForEach-Object { $_.Exception.Message.TrimEnd("`r`n") })
}
Write-Output $deploymentResult
Write-Host ($deploymentResult.outputs | Format-Table | Out-String)
Write-Host "Outputs:" $deploymentResult.outputs
Write-Host "Outputs.value:" $deploymentResult.outputs.value
Write-Host "Outputs.values:" $deploymentResult.outputs.values
Write-Host "Outputs[0]:" $deploymentResult.outputs[0]
Write-Host "Outputs[1]:" $deploymentResult.outputs[1]
Write-Host "Outputs[0].value:" $deploymentResult.outputs[0].value
Write-Host "Outputs[1].value:" $deploymentResult.outputs[1].value
Write-Host "Outputs.result:" $deploymentResult.outputs.result
Write-Host "Outputs.result.value:" $deploymentResult.outputs.result.value
Write-Host "Outputs.result.values:" $deploymentResult.outputs.result.values
Write-Host "Outputs.result[0]:" $deploymentResult.outputs.result[0]
Write-Host "Outputs.result[1]:" $deploymentResult.outputs.result[1]
Write-Host "Outputs.result[0].value:" $deploymentResult.outputs.result[0].value
Write-Host "Outputs.result[1].value:" $deploymentResult.outputs.result[1].value
Write-Host "Outputs.result[0][0]:" $deploymentResult.outputs.result[0][0]
Write-Host "Outputs.result.value1:" $deploymentResult.outputs.result.value1
Write-Host "Outputs.result[0].value1:" $deploymentResult.outputs.result[0].value1
Write-Host
Write-Host "Outputs.values:" $deploymentResult.outputs.values
Write-Host "Outputs.result.Count:" $deploymentResult.outputs.result.Count
Write-Host "Outputs.result:" $deploymentResult.outputs.result
Write-Host "Outputs.result[0]:" $deploymentResult.outputs.result[0]
Write-Host "Outputs['result']:" $deploymentResult.outputs['result']
Write-Host
Write-Host "Deployment properties:"
($deploymentResult) | Select-Object -Property *
Write-Host "Outputs properties:"
($deploymentResult.outputs) | Select-Object -Property *
Write-Host "Result properties:"
($deploymentResult.outputs.result) | Select-Object -Property *
Write-Host "['Result'] properties:"
$deploymentResult.outputs['result'] | Select-Object -Property *
Write-Host "[array]['Result'] properties:"
[array]$deploymentResult.outputs['result'] | Select-Object -Property *
Write-Host "Outputs.values properties:"
($deploymentResult.outputs.values) | Select-Object -Property *
Write-Host
ForEach ($res in $deploymentResult.outputs['result']){
Write-Host "Result element:" $res
}
Write-Host
ForEach ($res in $deploymentResult.outputs.values){
Write-Host "Values element:" $res
}
Write-Host
Write-Host "JSON:"
Write-Host "Deployment ConvertTo-Json:"
$json = ($deploymentResult) | ConvertTo-Json
Write-Host $json
Write-Host "Outputs ConvertTo-Json:"
$json = ($deploymentResult.outputs) | ConvertTo-Json
Write-Host $json
Write-Host "Result.Value ConvertTo-Json:"
$json = ($deploymentResult.outputs.result.value) | ConvertTo-Json
Write-Host $json
Powershell output:
VERBOSE: Performing the operation "Creating Deployment" on target "test4".
VERBOSE: 11:00:26 - Template is valid.
VERBOSE: 11:00:26 - Create template deployment '0521-100025'
VERBOSE: 11:00:26 - Checking deployment status in 5 seconds
DeploymentName : 0521-100025
ResourceGroupName : test4
ProvisioningState : Succeeded
Timestamp : 21/05/2020 10:00:26
Mode : Incremental
TemplateLink :
Parameters :
Outputs :
Name Type Value
=============== ========================= ==========
result Array [
"value1",
"value2"
]
DeploymentDebugLogLevel :
Key Value
--- -----
result Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs: [result, Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable]
Outputs.value:
Outputs.values: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs[0]:
Outputs[1]:
Outputs[0].value:
Outputs[1].value:
Outputs.result: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs.result.value:
Outputs.result.values:
Outputs.result[0]: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs.result[1]:
Outputs.result[0].value:
Outputs.result[1].value:
Outputs.result[0][0]: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs.result.value1:
Outputs.result[0].value1:
Outputs.values: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs.result.Count: 1
Outputs.result: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs.result[0]: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Outputs['result']: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Deployment properties:
ResourceGroupName : test4
OnErrorDeployment :
DeploymentName : 0521-100025
CorrelationId : 10be00bb-fada-4b54-8749-87460672e9ec
ProvisioningState : Succeeded
Timestamp : 21/05/2020 10:00:26
Mode : Incremental
TemplateLink :
TemplateLinkString :
DeploymentDebugLogLevel :
Parameters : {}
ParametersString :
Outputs : {[result, Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable]}
OutputsString :
Name Type Value
=============== ========================= ==========
result Array [
"value1",
"value2"
]
Outputs properties:
Comparer : System.Collections.Generic.GenericEqualityComparer`1[System.String]
Count : 1
Keys : {result}
Values : {Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable}
IsReadOnly : False
IsFixedSize : False
SyncRoot : System.Object
IsSynchronized : False
Result properties:
Type : Array
Value : {, }
['Result'] properties:
Type : Array
Value : {, }
[array]['Result'] properties:
Type : Array
Value : {, }
Outputs.values properties:
Type : Array
Value : {, }
Result element: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
Values element: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.DeploymentVariable
JSON:
Deployment ConvertTo-Json:
{
"ResourceGroupName": "test4",
"OnErrorDeployment": null,
"DeploymentName": "0521-100025",
"CorrelationId": "10be00bb-fada-4b54-8749-87460672e9ec",
"ProvisioningState": "Succeeded",
"Timestamp": "\/Date(1590055226689)\/",
"Mode": 0,
"TemplateLink": null,
"TemplateLinkString": null,
"DeploymentDebugLogLevel": null,
"Parameters": {
},
"ParametersString": "",
"Outputs": {
"result": {
"Type": "Array",
"Value": "value1 value2"
}
},
"OutputsString": "\r\nName Type Value \r\n=============== ========================= ==========\r\nresult Array [\r\n \"value1\",\r\n \"value2\"\r\n]\r\n"
}
Outputs ConvertTo-Json:
{
"result": {
"Type": "Array",
"Value": [
"",
""
]
}
}
Result.Value ConvertTo-Json:
[
[
],
[
]
]
The array output is in fact a JArray. Access the result like this: $deploymentResult.outputs.result.value[0].value and $deploymentResult.outputs.result.value[1].value.
More info: PowerShell -- Accessing a JArray inside a JObject

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.

I want to extract the data present in JSON file from a odata url but i am unable to extract the content using a loop

Below is the JSON file which i am referring..
{
"#odata.context": "https://ac.com/odata/$metadata#ModelVariableDataTypes(Id,ModelVariable,DoubleValues,ModelVariable(Id,Name,UnitOfMeasure,UnitOfMeasure(Name,Abbreviation)),DoubleValues(Id,Value,Timestamp,DataQuality,DataQuality(Id,Name)))",
"#odata.count": 1,
"value": [
{
"Id": 1928155,
"ModelVariable": {
"Id": 1929663,
"Name": "AccCore_CPULoadProcess",
"UnitOfMeasure": {
"Name": "%",
"Abbreviation": "%"
}
},
"DoubleValues": [
{
"Id": 75865549,
"Value": 0.0,
"Timestamp": "2018-09-25T03:35:00Z",
"DataQuality": {
"Id": 1,
"Name": "Good"
}
},
{
"Id": 75865729,
"Value": 0.0,
"Timestamp": "2018-09-25T03:40:00Z",
"DataQuality": {
"Id": 1,
"Name": "Good"
}
},
{
"Id": 75865873,
"Value": 0.0,
"Timestamp": "2018-09-25T03:45:00Z",
"DataQuality": {
"Id": 1,
"Name": "Good"
}
}
]
}
]
}
I want to extract the data present in JSON file from a odata url but i am unable to extract the content using a loop as in the JSON file the odata count is mentioned as 1(#odata.count": 1) so when i am trying to catch the entire data using a loop it is not working.
I want to extract the data present in the array field of doublevalues and wanted to show the output of the top three values of CPU process.
I am trying with the below code to extract the JSON data.
$path= "C:\Users\s.papolu\Desktop\mem.json"
$data = Get-Content -Path 'C:\Users\S.Papolu\Desktop\mem.json' | ConvertFrom-Json
$maxCount = $data.'#odata.count'
$maxCount
#"
for ($i = 0; $i -lt $maxCount; $i++)
{
$Name = $("{0:N1}" -f $data.value.ModelVariable.Name)
$cpu = $("{$i`:N2}" -f $data.value.DoubleValues.Value)
}
write-host $Name,$cpu
I'm not quite sure what you're asking here. For one thing, you've got an extraneous at-sign and double-quote in there.
MaxCount is just 1 here, so the loop only runs once. For each item, though, are you trying to store the results in some structure and then show it? Which of the DoubleValues do you want? The top three?
Is this closer to what you want?
$data = Get-Content -Path $path | ConvertFrom-Json
$maxCount = $data.'#odata.count'
$maxCount
$results = #()
for ($i = 0; $i -lt $maxCount; $i++)
{
# get the top three doubles values
$Doubles = #($data.value[$i].DoubleValues | sort -Property Value -Descending | select -first 3)
$results += [PsCustomObject]#{
Name = $data.value[$i].ModelVariable[0].Name;
Cpu = $Doubles;
}
}
$results | ft

how to create foreach loop in powershell with equal to command

Im starting to learn PowerShell and have been trying to create a foreach loop so that if one of the JSON items has a status other than STARTED, it runs a command using its name as a variable in the executable command. Here is what my json txt file looks like;
{
"UNIT": {
"name": "AB",
"address": "fadasdaer",
"status": "MIA"
},
"UNIT": {
"name": "CD",
"address": "fadasdahsfaaer",
"status": "STARTED"
},
"UNIT": {
"name": "EF",
"address": "9afahegt",
"status": "DEAD"
}
}
And what I am trying to do is read this from my json.txt and get it to run a foreach loop and execute a command where the name is incorporated in the command. I currently have something like this, but my PowerShell understand is limited and it doesnt work...
$JSON = json.txt
$check = $JSON | ConvertFrom-Json
$started=STARTED
foreach($unit in $check.unit){
if ($unit.status -notmatch $started) {
$name=$unit.name
executable.exe start $name
}
}
Any guidance would be greatly appreciated.
Your primary problem is that your JSON is malformed: it defines a single object and then defines its UNIT property multiple times.
You should define it as an array: note the enclosing top-level [...] and the absence of UNIT properties:
[
{
"name": "AB",
"address": "fadasdaer",
"status": "MIA"
},
{
"name": "CD",
"address": "fadasdahsfaaer",
"status": "STARTED"
},
{
"name": "EF",
"address": "9afahegt",
"status": "DEAD"
}
]
With both the JSON input and your other syntax problems corrected:
$JSON = 'json.txt'
$check = Get-Content -Raw $JSON | ConvertFrom-Json
$started = 'STARTED'
foreach ($unit in $check) {
if ($unit.status -notmatch $started) {
$name = $unit.name
executable.exe start $name
}
}
If you cannot fix the JSON at the source, you can transform it yourself before passing it to ConvertFrom-Json:
$check = (Get-Content -Raw $JSON) `
-replace '\A\{', '[' `
-replace '\}\Z', ']' `
-replace '"UNIT": ' | ConvertFrom-JSON

Resources