How to get key value from object inside array JSON using PowerShell? - arrays

I am trying to get the key value from object inside JSON array, please also suggest if I need to change my RuleId key structure, below is the output I want
rule = 1300
rulevalue = false
rule = 1304
rulevalue = true
JSON file
{
"Rule": [{
"MPName": "ManagementPackProject",
"Request": "Apply",
"Category": "Rule",
"RuleId": {
"1300": "false",
"1304": "true"
}
}]
}
PowerShell
$Content = Get-Content -Raw -Path "C:\temp\Rule.json" | ConvertFrom-Json -ErrorAction Stop
$Content = $Content.Rule | Where-Object { $_.Request -eq "Apply" }
foreach($item in $Content.RuleId)
{
rule = $item.key
rulevalue = $item.value
process...
}

Are you after something like this?
$JSON = #'
{
"Rule": [{
"MPName": "ManagementPackProject",
"Request": "Apply",
"Category": "Rule",
"RuleId": {
"1300": "false",
"1304": "true"
}
}]
}
'#
$Content = $JSON | ConvertFrom-Json
$Content = $Content.Rule | Where-Object Request -eq 'Apply'
$Output = foreach( $Rule in $Content.RuleId.psobject.Properties ) {
[PSCustomObject]#{
Rule = $Rule.Name
RuleValue = $Rule.Value
}
}
$Output | Format-List
Output:
Rule : 1300
RuleValue : false
Rule : 1304
RuleValue : true

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: ]

Get specific value from JSON array after comparison using PowerShell?

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

Replace symbol in JSON with different array values

I have 2 files
text.json that contains
{
"Files": [
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
},
{
"pattern": "/Something/Something/*"
}
]
}
and dlls.txt
1.dll
2.dll
..
6.dll
I want to replace the symbol * with the necessary dll like this :
"Files": [
{
"pattern": "/Something/Something/1.dll"
},
{
"pattern": "/Something/Something/2.dll"
},
.
.
.
{
"pattern": "/Something/Something/6.dll"
}
]
}
So far my code replaces the symbol but only with the last array element.
Since you're dealing with a structured data format - JSON - using a dedicated parser is always preferable to performing purely textual processing based on regexes.
While using the dedicated ConvertFrom-Json and ConvertTo-Json cmdlets to parse from and serialize back to JSON is slower than textual processing, it is much more robust.
# Read the DLL names from the text file into an array of strings.
$dlls = Get-Content dlls.txt
# Read the JSON file and parse it into an object.
$objFromJson = Get-Content -Raw text.json | ConvertFrom-Json
# Loop over all elements of the array in the .Files property and
# update their .pattern property based on the corresponding DLL names.
$i = 0
$objFromJson.Files.ForEach({
$_.pattern = $_.pattern -replace '(?<=/)\*$', $dlls[$i++]
})
# Convert the updated object back to JSON; save to a file as needed.
$objFromJson | ConvertTo-Json
Why not skip the 'C:\Users\itsan\Desktop\text.json' file alltogether and simply create a new JSON from the dll filenames you have in 'C:\Users\itsan\Desktop\dlls.txt' ?
$dlls = Get-Content -Path 'C:\Users\itsan\Desktop\dlls.txt'
$result = [PsCustomObject]#{
Files = foreach($file in $dlls) {
"" | Select-Object #{Name = 'pattern'; Expression = {"/Something/Something/$file"}}
}
}
$result | ConvertTo-Json
If you want that as new file, simply change the last line into
$result | ConvertTo-Json | Set-Content -Path 'C:\Users\itsan\Desktop\dll.json'
Output wil be like this:
{
"Files": [
{
"pattern": "/Something/Something/1.dll"
},
{
"pattern": "/Something/Something/2.dll"
},
{
"pattern": "/Something/Something/3.dll"
},
{
"pattern": "/Something/Something/4.dll"
},
{
"pattern": "/Something/Something/5.dll"
},
{
"pattern": "/Something/Something/6.dll"
}
]
}

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

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

Resources