storing foreach loop output to an array - arrays

Have a JSON array with same key values , want to loop through those and get one key of the same value of the array and store the output to an array
{
"contents":[
{
"name":"windows-Instance",
"Buildid":"1234",
"Buildtime":"1563350400238"
},
{
"name":"linux-Instance",
"Buildid":"1454",
"Buildtime":"1563264000198"
},
{
"name":"linux-Instance",
"Buildid":"1278685",
"Buildtime":"1563177600092"
}
]
}
Here is code i tried and doesn't give any output.
$result = #()
foreach ($Builtime in $contents) {
}
return $result

You can do it like this:
First convert the json string to an object:
$contents = '{
"contents":[
{
"name":"windows-Instance",
"Buildid":"1234",
"Buildtime":"1563350400238"
},
{
"name":"linux-Instance",
"Buildid":"1454",
"Buildtime":"1563264000198"
},
{
"name":"linux-Instance",
"Buildid":"1278685",
"Buildtime":"1563177600092"
}
]
}' | ConvertFrom-Json
Than retrieve the required properties:
$result = $contents | Select-Object -ExpandProperty "contents" | Select-Object -ExpandProperty "Buildtime"

You could loop over the JSON and create a custom-object that would allow you to further "manipulate" the data if needed.
Otherwise the example of #mhu is a perfect onliner
$json_content = (Get-Content ".\sample.json") | ConvertFrom-Json
$result = foreach ($content in $json_content."contents") {
[PSCustomObject]#{
"Buildtime" = $content."Buildtime"
}
}

Related

How to update values from a JSON input

I had another question that I ended up solving myself where I take a JSON input that has names and IP addresses. Then I resolve those IP addresses by looping through and need to replace the IP address with the resolve FQDN if there is one
I have no idea how to update/replace these values from the original JSON. I’ve read that arrays cannot be changed, only added to. This is where I’m stuck as I can get my script to write-out the resolve FQDN is there was one or the IP if there wasn’t... but I can’t get these values to replace the original value from the JSON with the ultimate goal to then take the newly modified JSON and upload it as a new config
Sample JSON input
{
"entry": [
{
"#name": "31.170.162.203",
"ip-netmask": "31.170.162.203",
"description": "test1"
},
{
"#name": "37.193.217.222",
"ip-netmask": "37.193.217.222",
"description": "test2"
},
{
"#name": "46.17.63.169",
"ip-netmask": "46.17.63.169",
"description": "test3"
}
]
}
$input = Get-Content 'C:\Users\e\Desktop' -raw | ConvertFrom-Json
$iplist = $input.entry.'ip-netmask'
foreach ($ip in $iplist) #for each line in the file...
{
$hostnames = $null
try {
$hostnames = [System.Net.Dns]::GetHostByAddress("$ip").Hostname #...resolve the ip
}
catch [System.Management.Automation.MethodInvocationException] {
$hostnames = "Server IP cannot resolve."
}
catch {
$hostnames = "unknown error."
}
if ($hostnames -ne "Server IP cannot resolve.") {
$ip -replace $ip, $hostnames
} else {
Write-Host $ip
}
}
Your json had an extra comma. I would do it this way. A property with a dash is harder to work with.
$a = cat file.json | convertfrom-json
$a.entry | foreach {
if ($namehost = (resolve-dnsname $_.'ip-netmask').namehost ) { # not null
$_.'ip-netmask' = $namehost
}
}
$a.entry
#name ip-netmask description
----- ---------- -----------
31.170.162.203 31.170.162.203 test1
37.193.217.222 l37-193-217-222.novotelecom.ru test2
46.17.63.169 46.17.63.169 test3
This is sort of like saying:
$namehost = (resolve-dnsname $_.'ip-netmask').namehost
if ($namehost -ne $null) { # ...
# or
if ($namehost) { # ...
but I'm doing the assignment and testing the value of the assignment at the same time, like in C. An assignment can be an expression.
$a = ($b = 1)
Then I'm going through the "entry" array and assigning each 'ip-netmask' property to the results if they aren't null.
The following code snippet could help:
$Json = #'
{
"entry":[
{
"#name":"31.170.162.203",
"ip-netmask":"31.170.162.203",
"description":"test1"
},
{
"#name":"37.193.217.222",
"ip-netmask":"37.193.217.222",
"description":"test2"
},
{
"#name":"46.17.63.169",
"ip-netmask":"46.17.63.169",
"description":"test3"
}
]
}
'# | ConvertFrom-Json
for ( $i = 0; $i -lt $Json.entry.Count; $i++ ) {
$entry = $Json.entry[$i]
$ip = $entry.'ip-netmask'
$hostnames = $null
try {
$hostnames = [System.Net.Dns]::GetHostByAddress("$ip").Hostname #...resolve the ip
$entry.'ip-netmask' = $hostnames
}
catch [System.Management.Automation.MethodInvocationException] {
$hostnames = "Server IP cannot resolve."
}
catch {
$hostnames = "unknown error."
}
Write-Host $entry.'#name', $hostnames -ForegroundColor Cyan
}
### debugging output:
$Json.entry
### final conversion hinted:
### $Json | ConvertTo-Json
###
Note that I use a here-string instead of (probably incorrect)
Get-Content 'C:\Users\e\Desktop' -raw

How to get index of hashtable in array?

I'm having a little trouble finding the index of a hashtable in an array. I create a JSON with this code:
$start = {
Clear-Host
$BIB = Read-Host 'Bibliothek'
$BIBName = Read-Host 'Bibliothek Name'
$Standort = Read-Host 'Bibliothek Standort'
$Autor = Read-Host 'Buchautor'
$BuchName = Read-Host 'Buchname'
$jsonfile = "C:\Skripte\bibV2-1000.xml"
if(![System.IO.File]::Exists($jsonfile)){
$Data = #{BIBs = #(
#{$BIB = #{BIBName=$BIBName},
#{Standort = $Standort},
#{Bücher = #(
#{BuchName = $BuchName;
Autor = $Autor})
}}
)}
ConvertTo-Json -Depth 50 -InputObject $Data | Add-Content $jsonfile
.$continue
} else {
$jsonfile = "C:\Skripte\bibV2-1000.json"
$Data = Get-Content $jsonfile | ConvertFrom-Json
$Data.BIBs += New-Object -TypeName psobject -Property #{$BIB =
#{BIBname=$BIBName},
#{Standort=$Standort},
#{Bücher = #(#{
Buchname=$BuchName;
Autor=$Autor})
}
}
ConvertTo-Json -Depth 50 -InputObject $Data | Out-File $jsonfile}
.$continue
}
$continue = {
Write-Host ""
Write-Host "Was wollen Sie machen?"
Write-Host "(1) Eine weitere Bibliothek hinzufügen"
Write-Host "(2) Einer Bibliothek neue Bücher hinzufügen"
Write-Host "(E) Script beenden"
If (($read = Read-Host ) -eq "1") {
&$start} else {
if (($read) -eq "2") {
. C:\Skripte\büc.ps1 } else {
if (($read) -eq "E") {
exit} else {
Write-Host "+++ FALSCHE EINGABE! Bitte wählen Sie (1) oder (2) für die entsprechende Aktion +++"
.$continue
}
}
}
}
&$start
The output is as follows:
{
"BIBs": [{
"BIB1": [{
"BIBName": "123"
},
{
"Standort": "123"
},
{
"Bücher": [{
"Autor": "123",
"BuchName": "123"
}]
}
]
},
{
"BIB2": [{
"BIBname": "345"
},
{
"Standort": "345"
},
{
"Bücher": [{
"Autor": "345",
"Buchname": "345"
}]
}
]
}
]
}
Now I want to find out the index of "BIB1". I already tried the IndexOf()-Method which should create the output "0" but it gives me "-1" instead, because it can't find the value. How can I get the index of "BIB1"?
Judging by your earlier question, you're attempting to get the index of a specific object so you can access it via its containing array. However, you can do this more directly: $objOfInterest = $Data.BIBs | ? BIB1 - see my answer to your earlier question for details.
You need to iterate over the array elements of $Data.BIBs, which - on reading your serialized-to-a-file-as-JSON hashtables back in with ConvertFrom-Json - are custom objects (as Ansgar correctly points out; they are instances of [System.Management.Automation.PSCustomObject]), and check each for the presence of property 'BIB1':
(In a hashtable, you'd check for the presence of key 'BIB1' with .ContainsKey('BIB1'))
To test the existence of an object property, you need reflection, which is most easily - but somewhat obscurely - achieved via the hidden .PSObject property, as demonstrated in Ansgar Wiechers' more elegant solution.
However, given that the properties of interest have nonempty values, we can infer from the presence of a nonempty value that a given property exists, using implicit Boolean (logic): $obj.'BIB1' by default returns $null if there is no BIB1 property, which is "falsy" in a Boolean context such as an if conditional; conversely, any nonempty value is "truthy":
$propName = 'BIB1'
$i = $ndx = -1
foreach ($obj in $Data.BIBs) {
++$i
if ($obj.$propName) { $ndx = $i; break}
}
$ndx # $ndx now contains the index of the target object or -1 if there was no match
$Date.BIBs is an array of custom objects, not hashtables (since you wrote your original data to a JSON file and then converted that back), so you need something like this:
$arr = $Data.BIBs | ForEach-Object { $_.PSObject.Properties.Name }
$arr.IndexOf('BIB1') # returns 0
$arr.IndexOf('BIB2') # returns 1

convert 1 dimension strings array into json file

Perhaps it's easy question and will be banned but I spend hours today and not make it work as I expected.
so I have such object:
data_1 data_2 ... abra_12 ...
I want convert it into json like this:
[
{"data_1" : "data_1"},
{"data_2" : "data_2"},
...
]
I tried this:
$result = Get-ChildItem $Path2Search -recurse | Select-String -Pattern '(?<=locI(.*)\(\").+?(?=\")' -casesensitive | foreach {$_.matches} | select value | ConvertTo-Json | Out-File $save2file
But I'm getting this:
{
"Value": "data_1"
},
{
"Value": "data_2"
},
While I want it like this:
{
"data_1": "data_1"
},
{
"data_2": "data_2"
},
Any advice how? :)
You can first shape the result in a list of key-values then convert it to json.
For example if your input is a comma separated string, you can use:
$input = "data_1, data_2, data_3"
$input.Split(',').Trim() |
ForEach-Object {#{$_=$_}} |
ConvertTo-Json |
Out-File "C:\test.txt"
Or if the input is a string array:
$input = #("data_1", "data_2", "data_3")
$input | ForEach-Object {#{$_=$_}} |
ConvertTo-Json |
Out-File "C:\test.txt"
And the result would be:
[
{
"data_1": "data_1"
},
{
"data_2": "data_2"
},
{
"data_3": "data_3"
}
]
While I prefer to use above solution for creating json result, but you also can rely on string manipulation as well:
$input = "data_1, data_2, data_3"
#"
[
`t$(($input -split '\s*,\s*' |%{"{ `"$_`" : `"$_`" }"}) -join ",`n`t")
]
"#

Unexpected array to string conversion

I'm trying to pack my data into objects before displaying them with ConvertTo-Json. The test case below shows perfectly how I'm dealing with data and what problem occurs:
$array = #("a","b","c")
$data = #{"sub" = #{"sub-sub" = $array}}
$output = #{"root" = $data}
ConvertTo-Json -InputObject $data
ConvertTo-Json -InputObject $output
Output (formatted by hand for clarity):
{ "sub": { "sub-sub": [ "a", "b", "c" ] }}
{ "root": { "sub": { "sub-sub": "a b c" } }}
Is there any way to assign $data to $output without this weird implicit casting?
As mentioned in the comments, ConvertTo-Json will try to flatten the object structure beyond a maximum nesting level, or depth, by converting whatever object it finds beyond that depth to a string.
The default depth is 2, but you can specify that it should go deeper with the Depth parameter:
PS C:\> #{root=#{level1=#{level2=#("level3-1","level3-2")}}}|ConvertTo-Json
{
"root": {
"level1": {
"level2": "level3-1 level3-2"
}
}
}
PS C:\> #{root=#{level1=#{level2=#("level3-1","level3-2")}}}|ConvertTo-Json -Depth 3
{
"root": {
"level1": {
"level2": [
"level3-1",
"level3-2"
]
}
}
}

Looping through $json variable and grabbing each id to add to an array

Given that I am processing the following $json variable, how would I grab each server id (i.e. 215d1109-216d-48c3-af8e-998bb9bc3ca0 and 440cf918-3ee0-4143-b289-f63e1d2000e6 in this case) and put it into an array?
Right now $obj.servers.id returns nothing (as expected), but $obj.servers.id[0] returns an error message.
clear
[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") | out-null
$json = '
{
"servers": [
{
"admin_password": "qpYU66rKxmnK",
"id": "215d1109-216d-48c3-af8e-998bb9bc3ca0",
"links": [
{
"href": "http://openstack.example.com/v3/servers/<id>",
"rel": "self"
},
{
"href": "http://openstack.example.com/servers/<id>",
"rel": "bookmark"
}
]
},
{
"admin_password": "wfksH3GTTseP",
"id": "440cf918-3ee0-4143-b289-f63e1d2000e6",
"links": [
{
"href": "http://openstack.example.com/v3/servers/<id>",
"rel": "self"
},
{
"href": "http://openstack.example.com/servers/<id>",
"rel": "bookmark"
}
]
}
]
}
'
$ser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$obj = $ser.DeserializeObject($json)
$obj.servers.id;
Please note that I am using Powershell 2.0.
You're misunderstanding the structure of your data. $obj.servers is an array with two fields, each of which contains a dictionary, not an object containing an array id. You need to make the index access like this:
$obj.servers[0].id
$obj.servers.id[0] will certainly throw an error, because the array object $obj.servers doesn't have a property id, so in PowerShell v2 $obj.servers.id returns $null, and index access on a null array fails (as you'd expect).
Demonstration:
PS C:\> [void][Reflection.Assembly]::LoadWithPartialName('System.Web.Extensions')
$json = #'
...
'#
PS C:\> $ser = New-Object Web.Script.Serialization.JavaScriptSerializer
PS C:\> $obj = $ser.DeserializeObject($json)
PS C:\> $obj.servers.GetType().FullName
System.Object[]
PS C:\> $obj.servers.id -eq $null
True
PS C:\> $obj.servers[0].GetType().Name
Dictionary`2
PS C:\> $obj.servers[0] | Format-Table -AutoSize
Key Value
--- -----
admin_password qpYU66rKxmnK
id 215d1109-216d-48c3-af8e-998bb9bc3ca0
links {System.Collections.Generic.Dictionary`2[System.Str...
PS C:\> $obj.servers[0].id
215d1109-216d-48c3-af8e-998bb9bc3ca0
To extract all IDs simply pipe the array into a ForEach-Object loop where you echo the id property:
PS C:\> $ids = $obj.servers | % { $_.id }
PS C:\> $ids
215d1109-216d-48c3-af8e-998bb9bc3ca0
440cf918-3ee0-4143-b289-f63e1d2000e6

Resources