How to get child object from PSObject using dot notation string - powershell

providing I have the following JSON
{
"firstName": "Frank",
"lastName": "Smith",
"age": "25",
"address": {
"streetAddress": "21 3rd st",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
I need to be able to update a value using dotted notation.
$path = "C:\somePath\test.json"
$node = "address.streetAddress" # should also work with "phoneNumber[0].number"
$value = "21 Jump St."
$config = Get-Content -Path $path -Raw | ConvertFrom-Json
$config.$node = $value
Write-Host $config.$node
#Set-Content $path $($config | ConvertTo-Json)
The problem I'm getting is that the property cannot be found.
Exception setting "address.streetAddress": "The property 'address.streetAddress' cannot be found on this object. Verify that the property exists and can be set."
What do I need to do to be able to pass in dotted notation, and update the appropriate value?

While you can put a single property name in a variable and use that to access the property, you can't do that for multiple, dotted properties. You can work around this by using Invoke-Expression:
Invoke-Expression "`$config.$node = `$value"

Shortest way around it is:
$config.$($node) = $value
Level of nesting does not matter, You can do this:
$config.$($node).$($subnode).$($subSubNode) = $value
You can also refer to properties in objects like this:
$config.$($node.nodename)=$value

Related

Get email address from a hash table / array

my question is rather simple for an experienced PowerShell programmer, but I have hard time to get the solution as a novice. I need to extract the emailAddresses and businessPhones from this object (this is returned by Graph Explorer). In code I am using Get-MgUserContact cmdlet to get the contact from user mailbox...
Graph Explorer:
{
"value": [
{
"id": "",
"parentFolderId": "",
"homePhones": [],
"businessPhones": [
"+1 002 224 512"
],
"emailAddresses": [
{
"name": "First Name",
"address": "Firstname.Laastname#mycompany.com"
}
],
"businessAddress": {}
}
]
}
Any idea/solution would be very helpful.
Tried to get the value of <emailAddresses.address>
$mailbox="SomeUser#myCompany.com"
$Contacts = Get-MgUserContact -UserId $mailbox
foreach($contact in $Contacts){
$FolderID = $contacts.parentFolderId
$contactID = $contact.Id
$a = $contact.EmailAddresses
$a
}
It returns:
Address Name
Firstname.Lastname#myCompany.com Firstname Lastname

Convert JSON-String to proper Object in Powershell

I spend 3 hours debugging, but I don't get the rootcause.
I have text (in JSON Format) in a variable. I convert it with "Convert-From-JSON" to an actual object. I was hoping that I can then work with the properties of the object. But it does not work :( It seems that the conversion only gives me two tables (status and data). What am I doing wrong?
My code:
$results = {
"status": "FINISHED",
"data": {
"results": [
{
"id": "11565C230500",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
},
{
"id": "22739L5F16243",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
},
{
"id": "3304332724004",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
}
]
}
}
Now putting it as Object:
$resultObject = ConvertFrom-JSON -InputObject $result
Now trying to retrieve:
$resultObject.id | where {$_.id -eq '11565C230500'}
As it is now, you define $results as script block where it should be a string:
$results = #'
{
"status": "FINISHED",
"data": {
"results": [{
"id": "11565C230500",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
},
{
"id": "22739L5F16243",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
},
{
"id": "3304332724004",
"custom": {
"image": "XXXX",
"name": "XXXX",
"articleNumber": "4032423423505"
}
}
]
}
}
'#
Now you can convert it from the JSON string
$resultObject = $results | ConvertFrom-Json
Then, to parse out the nested property, you need to follow the data structure:
$resultObject.data.results | Where-Object {$_.id -eq '11565C230500'}
will give you this:
id custom
-- ------
11565C230500 #{image=XXXX; name=XXXX; articleNumber=4032423423505}
If you want to get the articleNumber from the custom object that contains, dig deeper still:
($resultObject.data.results | Where-Object {$_.id -eq '11565C230500'}).custom.articleNumber
which will return 4032423423505
Assuming the json is single quoted in that example, otherwise it's a scriptblock, and "$results" is used in place of "$result", the id property is underneath data.results. You couldn't examine the id property with where-object if you already expanded it. That's an alternate form of where-object. I'm expanding the "custom" property with the foreach-object alias "%". Note one id number is shorter. Beware convertto-json's default depth of 2.
$results = '{"status":"FINISHED","data":{"results":[
{"id":"11565C230500", "custom":{"image":"XXXX","name":"XXXX","articleNumber":"4032423423505"}},
{"id":"22739L5F16243","custom":{"image":"XXXX","name":"XXXX","articleNumber":"4032423423505"}},
{"id":"3304332724004","custom":{"image":"XXXX","name":"XXXX","articleNumber":"4032423423505"}}
]}}'
$resultObject = ConvertFrom-JSON -InputObject $results
$resultObject.data.results | where id -eq 11565C230500
id custom
-- ------
11565C230500 #{image=XXXX; name=XXXX; articleNumber=4032423423505}
$resultobject.data.results | where id -eq 11565C230500 | % custom
image name articleNumber
----- ---- -------------
XXXX XXXX 4032423423505

Parse JSON output into a CSV file using Powershell

I'm using PowerShell to extract data via an API and would like to parse the JSON into a CSV file. How would I parse each of the JSON results into a CSV structure like this:
$Date, $app, $pagename, $range1, $range1_value
$Date, $app, $pagename, $range2, $range2_value
$Date, $app, $pagename, $range3, $range3_value
The JSON looks like this:
{
"fields": [
{
"label": "app",
"field": "app",
"type": "string"
},
{
"label": "pagename",
"field": "pagename",
"type": "string"
},
{
"label": "range1",
"field": "count(*)",
"type": "integer",
"aggregation": "filter"
},
{
"label": "range2",
"field": "count(*)",
"type": "integer",
"aggregation": "filter"
},
{
"label": "range3",
"field": "count(*)",
"type": "integer",
"aggregation": "filter"
}
],
"results": [
[
"application1",
"loginpage",
41425,
41266,
18869
],
[
"application2",
"loginpage",
7424,
7113,
2905
]
],
"moreData": false,
"schema": "record"
}
I've tried various methods (e.g. Convertto-JSON and Convertfrom-JSON) but I don't seem to be able to connect the 'fields' and 'results' together into a hashtable. I was hoping I could create it as a $JSON object and then iterate through each result like $JSON[0..1].
Let's start by parsing your input data!
Use a for loop to iterate over the individual array items in the results values, then use the index to resolve the type and label name from the fields list:
# Convert from json
$data = $jsonString |ConvertFrom-Json
# Set up a type table for easy conversion
$typeTable = #{'integer' = [int]}
# Iterate over each row in the results
$results = foreach($values in $data.results){
# Create dictionary to hold property values for the row
$Properties = [ordered]#{}
for($index = 0; $index -lt $data.fields.Count; $index++){
# Resolve field metadata by index
$field = $data.fields[$index]
# Take type mappings into account and write to $Properties dictionary
if($typeTable.ContainsKey($field.type)){
$Properties[$field.label] = $values[$index] -as $typeTable[$field.type]
}
else{
$Properties[$field.label] = $values[$index]
}
}
# Output structured object
[PSCustomObject]$Properties
}
Now that we have nice objects we can work with, we can use Select-Object and Export-Csv to create the desired output format:
$results |Select-Object #{Name='Date';Expression={Get-Date -Format yyyyMMdd}},app,pagename,#{Name='2000';Expression={'2000'}},range3 |Export-Csv -Path .\path\to\output.csv -NoTypeInformation

Have PowerShell pass results to Pentaho

I have a PowerShell script that processes a json string. My goal is to have this pass a resultset to Pentaho so I can process it and put it in a database table.
My PowerShell script works as expected outside of Pentaho. I can parse the files and get the information I need without any issues. It's when I try to pass those values is when Pentaho returns goofy results.
Here is my script
$scriptMode = 'GetFileInfo'
$json = '{
"building": [
{
"buildingname": "NAPA Auto Parts",
"files": [{
"sheets": [{
"name": "BATTERY",
"results": [{
"filename": "BATTERY - 1679568711.xlsx",
"sku": "1679568711"
}
]
}
],
"name": "2.15.19.xlsx",
"status": "processed",
"fileId": "c586bba6-4382-42c4-9c29-bffc6f7fe0b6"
}, {
"name": "Oct-Nov 2018 11.30.18.xlsx",
"errors": ["Unknown sheet name: TOILET PLUNGER"],
"status": "failed",
"fileId": "afa7c43f-26dc-421c-b2eb-45ad1e899c42"
}
]
},
{
"buildingname": "O''Reily Auto Parts",
"files": [{
"sheets": [{
"name": "ALTERNATOR",
"results": [{
"filename": "ALTERNATOR - 6.3.19 1629453444.xlsx",
"sku": "1629453444"
}
]
}, {
"name": "OIL FILTER",
"results": [{
"filename": "OIL FILTER - 6.3.19 1629453444.xlsx",
"sku": "1629453444"
}
]
}
],
"name": "6.3.19.xlsx",
"status": "processed",
"fileId": "647089fe-9592-4e2b-984f-831c4acd4d9c"
}
]
}
]
}'
$psdata = ConvertFrom-Json -InputObject $json
IF ($scriptMode -eq "GetFileInfo") {
$psdata.building | foreach-Object {
foreach ($File in $_.files)
{
[PSCustomObject]#{
BuildingName = $_.buildingname
FileName = $File.name
fileId = $File.fileId
Status = $File.status}
}
}
}
ElseIF ($scriptMode -eq "GetErrorInfo") {
$psdata.building | foreach-Object {
foreach ($File in $_.files)
{
[PSCustomObject]#{
BuildingName = $_.buildingname
Errors = $File.errors
SheetName = $File.sheets.name
fileId = $File.fileId} | Where-Object {$_.errors -ne $null}
}
}
}
And here's how I have my transformation setup. I have a table input query that will set the run command for PowerShell based on what I want the script to do (either get file info or get error info).
Then I have the "Execute a process" step run the PowerShell command
This is what is returned in Pentaho vs what PowerShell returns
I'm expecting the results to be returned exactly as PowerShell returns them. I'm hoping I can accomplish this without exporting the data to another format. We have had nothing but issues with the Json Input step in Pentaho, so we chose PowerShell over the "Modified Javascript Value" step in Pentaho.
Any idea how I can get this to return a result set (like a SQL query would return) back to Pentaho?
Most likely your result set is returning the entire thing, just not "tabled" as you expected, it's probably returning the entire table all summed up in one long text format, but still having all the line breaks / column breaks.
Try using Split steps in your pentaho flow to work on the returned String. First off, try using a "Split field to rows" with the delimiter as "${line.separator}".
From there all you to do is pretty much split the whole thing until it is a table in pentaho.

Json to CSV select second level columns

I have a json in the below format, where some columns are at 2nd level. I want to the column at the second level to be at the first level in CSV
{
"ApiKey": "123",
"BasicDetails": {
"ClientID": "1234",
"CompanyName": "C1",
"ContactName": "",
"EmailAddress": "",
"Country": "United Kingdom",
"TimeZone": "(GMT+00:00)"
}}
Required Output is:
APIKey, ClientID, CompanyName, ContactName, EmailAddress,Country,Timezone
123,1234,C1,,,United Kingdom,(GMT+00:00)
I have tried:
(GET-Content F:/my.json -RAW | ConvertFrom-Json)|Select Columns|Export-CSV F:/my.csv
EDIT
Actual Json:
{
"ApiKey": "123",
"BasicDetails": {
"ClientID": "1234",
"CompanyName": "C1",
"ContactName": "",
"EmailAddress": "",
"Country": "United Kingdom",
"TimeZone": "(GMT+00:00)"
}
"BillingDetails": {
"CurrentTier": "0 - 500",
"CurrentMonthlyRate": 9.0000,
"MarkupPercentage": 0,
"MonthlyScheme": "Basic",
"Currency": "USD",
"ClientPays": false
}}
I need Belling Detail columns, Basic Details column and API key at one level
This should work for a all JSON files with a depth of two (which you requested):
$tempObject = #{}
(GET-Content F:/my.json -RAW | convertfrom-json).PsObject.Properties | ForEach-Object {
if ($_.TypeNameOfValue -eq 'System.Management.Automation.PSCustomObject')
{
$_.Value.PsObject.Properties | ForEach-Object {
$tempObject += #{$_.Name = $_.Value}
}
}
else
{
$tempObject += #{$_.Name = $_.Value}
}
}
[PsCustomObject]$tempObject | Export-CSV F:/my.csv
Tricky question. Depends very much if you are looking for a solution for your specific case or a more general approach.
For the first, go with Martin Brandl's answer.
Else, there is also ConvertTo-FlatObject:
https://gallery.technet.microsoft.com/ConvertTo-FlatObject-396a6e0a