How to get child dynamically with name in power shell - powershell

wanted to traverse in json body and get values from list using powershell.
json file
{   
 "TopicPropProfiles": [    
{        
"TP1":{            
"enable-duplicate-detection": true,            
"enable-batched-operations": true,            
"enable-ordering": true      
},        
"TP2":{            
"max-delivery-count": 3,            
"enable-batched-operations": true      
}    
}    
],    
"SubPropProfiles": [    
{        
"SP1":{            
"enable-duplicate-detection": true,                        
"max-size": 1024        
},        
"SP2":{            
"max-delivery-count": 3,            
"enable-batched-operations": true,                       
"enable-session": false                  
}    
}    
],    
"Topics":[    
{        
"TopicName": "topic1",        
"SubNames": ["sub1","sub2","sub3"],        
"TopicPropertyProfile": "TP1",        
"SubPropertyProfile": "SP2" 
},    
{        
"TopicName": "topic2",        
"SubNames": ["sub4","sub5","sub6"],        
"TopicPropertyProfile": "TP2",        
"SubPropertyProfile": "SP1"    
}
]
}
powershell --getting file from somepath($profilepath)
$profilejson = Get-Content -Raw $profilePath | ConvertFrom-Json;
$profileObject = [PSCustomObject]$profilejson;
$TopicProps=$profileObject.TopicPropProfiles.**TP1**;
Write-Host $TopicProps.'enable-duplicate-detection'
Wanted to get fields values under TP1 or TP2(this value will be passed dynamically through some other parameters). Is above syntax/approach correct?

I have reproduced in my environment and I got expected results as below:
$result = Get-Content "Path" -raw | ConvertFrom-Json
$result.TopicPropProfiles.TP1
what if TP1 if also in some var like $profile=TP1 then?
$result = Get-Content "path" -raw | ConvertFrom-Json
$profile='TP1'
$result.TopicPropProfiles[0].$profile

To get the values of specific keys, you can use the dot notation. Example :
$json = Get-Content -Raw .\json.json | ConvertFrom-Json
$json.TopicPropProfiles
To see the content of TP1
$json.TopicPropProfiles.TP1
To get get the value of your first key/value pair inside TP1
$json.TopicPropProfiles.TP1.'enable-batched-operations'
Like this, you'll get the object returned. If you want the values, you need to use Select-Object
$json.TopicPropProfiles.TP1 |Select-Object -ExpandProperty TP1

Related

Powershell - Using ConvertFrom-csv

I'm brand new to Powershell. I have a variable that contains comma separated values. What I want to do is read each entry in the csv string variable, and assign it to a variable. I am using ConvertFrom-csv to separate the data with headers.
How can I assign each value to a variable, or even better, use ConvertTo-csv to create a new csv string which only has, for example, columns 2/3/6/7 in it?
I would ultimately want to write that data out to a new csv file.
Here is my test code:
#Setup the variable
$Data = "test1,test2,test3,1234,5678,1/1/2021,12/31/2021"
$Data | ConvertFrom-csv -Header Header1,Header2, Header3, Header4, Header5, Header6, Header7
# Verify that an object has been created.
$Data |
ConvertFrom-csv -Header Header1,Header2, Header3, Header4, Header5, Header6, Header7 |
Get-Member
#Show header1
Write-Host "--------Value from $Data----------------------------------------"
$Data[0] #doesn't work, only displays the first character of the string
Write-Host "-----------------------------------------------------------------"
Let me suggest a different approach. If you use ConvertFrom-Csv and assign the result of a variable ($data), this will be an array of Custom Objects. You can run this through a loop that steps through the elements of the array , one at a time, and then through an inner loop that steps through the properties of each object one at a time, setting a variable with the same name as the field header and the same value as the current record's value.
I don't have code that does exactly what you want. But I'm including code that I wrote a few years back that does something similar only using Import-Csv instead of ConverFrom-Csv.
Import-Csv $driver | % {
$_.psobject.properties | % {Set-variable -name $_.name -value $_.value}
Get-Content $template | % {$ExecutionContext.InvokeCommand.ExpandString($_)}
}
Focus on the first inner loop. Each property of the current object will have a name that came from the header and a value that came from the current record of the Csv file. You can ignore the line that says ExpandString. That's just what I choose to do with the variables once they have been defined.
How can I assign each value to a variable, or even better, use ConvertTo-Csv to create a new csv string which only has, for example, columns 2/3/6/7 in it?
This is one way of automating this:
# Define the CSV without headers
$Data = "test1,test2,test3,1234,5678,1/1/2021,12/31/2021"
# Set the number of headers needed
$headers = $Data.Split(',') | ForEach-Object -Begin { $i = 1 } -Process {
"Header$i"; $i++
}
# Set the desired columns we want
$desiredColumns = 2,3,6,7 | ForEach-Object { $_ - 1 } | ForEach-Object {
$headers[$_]
}
# Convert to CSV and filter by Desired Columns
$Data | ConvertFrom-Csv -Header $headers | Select-Object $desiredColumns
Result
Header2 Header3 Header6 Header7
------- ------- ------- -------
test2 test3 1/1/2021 12/31/2021
Result as CSV
$Data | ConvertFrom-Csv -Header $headers |
Select-Object $desiredColumns | ConvertTo-Csv -NoTypeInformation
"Header2","Header3","Header6","Header7"
"test2","test3","1/1/2021","12/31/2021"

Why does the pipeline not work on converted json objects?

Consider the following code:
$data = '[
{
"Name": "banana",
"Color": "yellow"
},
{
"Name": "kiwi",
"Color": "green"
},
{
"Name": "apple",
"Color": "red"
}
]'
# Returns 3 objects while only 1 was expected
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }
# Workaround, returns 1 object as expected:
($data | ConvertFrom-Json) | Where-Object { $_.Name -eq 'banana' }
Why is it not possible to use the first option? It seems like the Where-Object function does not correctly after an object is converted from json. This is happening on PowerShell version 5.1.
Are we missing something obvious here?
With:
$data | ConvertFrom-Json | Where-Object { $_.Name -eq 'banana' }
The following happens:
ConvertFrom-Json returns an array of objects (which is an object itself). As this is the first (in the end also the only) "finished" object ConvertFrom-Json returns, it is passed as a whole down the pipeline. Remember, a cmdlet could return multiple arrays of objects in general.
So, Where-Object receives only one object in this case (the whole array with three elements). $_ then references the whole array, not each element. Therefore, $_.Name does not return the name of one element, but a list of all element names. Furthermore, the term $_.Name -eq 'banana' in this case is not a boolean expression, but a filtered list of element names (the list then only contains 'banana'). As long as the list is not empty, it will be evaluated to $true by Where-Object and therefore your whole array (one object, with three elements) is piped further (printed in your case). So, it doesn't return three objects like you assumed, but one object, containing three objects.
Your other line in contrast:
($data | ConvertFrom-Json) | Where-Object { $_.Name -eq 'banana' }
Well, to make it short, does what you expect it to do. Why? Because the round brackets break the pipeline. Due to the brackets, everything inside the brackets will be completely evaluated, before something gets piped further. After your brackets are evaluated, there is an array, that will be piped further. A whole array will be piped element by element. So in this case, Where-Object receives three single objects, like you expected it.
Another nice example is this:
You cannot overwrite a file that your are currently reading:
Get-Content test.txt | Set-Content test.txt
But you can overwrite a file after you finished reading it:
(Get-Content test.txt) | Set-Content test.txt

Get value from json variable using windows powershell 5.1

I've got a JSON like this
[
{
"Param1":true,
"Param2":0,
"Param3":"OK"
...
...
}
]
How can I get Param2 value, using powershell 5.1?
For now, I tried to get property names, but only get length
$jsondeconverted = $jsonOrig | ConvertFrom-Json
$jsonOrig .PsObject.Properties |
Select-Object -ExpandProperty Name |
ForEach-Object {
Write-Host "Key : " $_
Write-Host "Value : " $thisJSON."$_"
}
EDIT
This is how I get my json
$jsonvar = '['+$jsonvar+']'
$convertedJson = $jsonvar | ConvertTo-Json -Depth 10
$deconvertedJson = $convertedJson | ConvertFrom-Json
$deconvertedJson contains only length parameter and nothing more.
You need to look into the object ($jsondeconverted) rather than the string ($jsonOrig)
Based on your json Structure, you would access param2 in the following way $jsondeconverted[0].Param2
Verifiable complete example
$jsonorig = '[{"Param1":true,"Param2":0,"Param3":"OK"}]'
$jsondeconverted = $jsonorig | ConvertFrom-Json
$jsondeconverted[0].param2

How to search for a key and change the value of that?

sample.txt:
{"ip":"","port":0,"protocol":"udp","user":false,"test":false}
I want change the 'value' to a particular 'key' in the above dictionary.
For example: For 'port': I need to change '23', for 'protocol', I need to change 'tcp' etc. using Windows PowerShell.
Since you are working with JSON, lets use JSON!
$json = Get-Content .\sample.txt | ConvertFrom-Json
$json.port = 23
$json.protocol = 'tcp'
$json | ConvertTo-Json -Compress | Out-File .\sample.txt
First I read the file and lets powershell convert it from JSON to an object. (Line 1)
I can now edit this object. (Line 2-3)
Finally I convert it back to JSON and write it to the file. (Line 4)
Hope this helps.
Your sample data appears to be in JSON format, so you'd modify it by converting the JSON string to an object, change the properties, then convert the object back to a JSON string, like this:
$file = 'C:\path\to\sample.txt'
(Get-Content $file -Raw) | ConvertFrom-Json | ForEach-Object {
$_.port = 23
$_.protocol = 'tcp'
$_ # echo current object to feed it back into the pipeline
} | ConvertTo-Json -Compress | Set-Content $file
On PowerShell v2 or earlier you need to run (Get-Content $file) | Out-String to emulate the parameter -Raw that was introduced with v3.

Issues with Powershell Import-CSV

Main Script
$Computers = Get-Content .\computers.txt
If ( test-path .\log.txt ) {
$Log_Successful = Import-CSV .\log.txt | Where-Object {$_.Result -eq "Succesful"}
} ELSE {
Add-Content "Computer Name,Is On,Attempts,Result,Time,Date"
}
$Log_Successful | format-table -autosize
Issues:
Log_Successful."Computer Name" works fine, but if i change 4 to read as the following
$Log_Successful = Import-CSV .\log.txt | Where-Object {$_.Result -eq "Failed"}
Log_Successful."Computer Name" no longer works... Any ideas why?
Dataset
Computer Name,Is On,Attempts,Result,Time,Date
52qkkgw-94210jv,False,1,Failed,9:48 AM,10/28/2012
HELLBOMBS-PC,False,1,Successful,9:48 AM,10/28/2012
52qkkgw-94210dv,False,1,Failed,9:48 AM,10/28/2012
In case of "Successful" a single object is returned. It contains the property "Computer Name". In case of "Failed" an array of two objects is returned. It (the array itself) does not contain the property "Computer Name". In PowerShell v3 in some cases it is possible to use notation $array.SomePropertyOfContainedObject but in PowerShell v2 it is an error always. That is what you probably see.
You should iterate through the array of result objects, e.g. foreach($log in $Log_Successful) {...} and access properties of the $log objects.
And the last tip. In order to ensure that the result of Import-Csv call is always an array (not null or a single object) use the #() operator.
The code after fixes would be:
$logs = #(Import-Csv ... | where ...)
# $logs is an array, e.g. you can use $logs.Count
# process logs
foreach($log in $logs) {
# use $log."Computer Name"
}
I'm not sure if this is the problem but you have a typo, in Where-Object you compare against "Succesful" and the value in the file is "Successful" (missing 's').
Anyway, what's not working?