Access Array of object inside a PSCustomObject Powershell - arrays

I have this PSCustomObject which I'm trying to format into a table and export it to an .csv file, when the .csv file is built, the output in the cell is System.Object[].
$tableFindings = #()
foreach ($item in $findings.results) {
$tabledata = [ordered]#{
dnsName = $item.assets| ForEach-Object dsnName
}
$tableFindings += New-Object psobject -Property $tabledata
}
$tableFindings outputs
{
"temporary_id": "xxxxxxxxxxxxxxxxxx",
"affects_rating": true,
"assets": [
{
"asset": "xxxxxxxx",
"identifier": null,
"category": "critical",
"dnsName": [
"xxxxxxxxxxxxxxx",
"xxxxxxxxxxxxxxx"
],
"is_ip": false
},
{
"asset": "xxxxxxxx",
"identifier": null,
"category": "critical",
"dnsName": [
"xxxxxxxxxxxxxxx",
"xxxxxxxxxxxxxxx"
],
"is_ip": false
}
]
}
I'm having a hard time trying to figure out how to access the array of objects, assets is one of the arrays, but inside there is dnsName that is also an array.
Any suggestions?

If all you're interested in is a flat array of the dnsName values, across all objects stored in the assets array, use member-access enumeration:
$item.assets.dnsName
To incorporate this into [pscustomobject] instances you can send to Export-Csv:
$tableFindings = foreach ($item in $findings.results) {
[pscustomobject] #{
# ... add other properties as needed.
dnsName = $item.assets.dnsName
}
}
Note how the foreach statement is used as an expression, which means that PowerShell automatically collects the [pscustomobject] instances output in each iteration in variable $tableFindings.

Related

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"
}
]
}

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