ConvertFrom-Json in Powershell v2 - json

Code
I have the following script, largely based off information on this site:
cls
if ($PSVersionTable.PSVersion.Major -lt 3) {
function ConvertTo-Json([psobject] $item){
[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") | out-null
$ser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
$hashed = #{}
$item.psobject.properties | %{ $hashed.($_.Name) = $_.Value }
write-output $ser.Serialize($hashed)
}
function ConvertFrom-Json([string] $json){
[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") | out-null
$ser = New-Object System.Web.Script.Serialization.JavaScriptSerializer
write-output (new-object -type PSObject -property $ser.DeserializeObject($json))
}
}
$jsonObj = (new-object -type psobject -property #{
MyDummyData = #{
Version = '1.0.4'
CreationDate = ("{0:yyyy-MM-ddTHH:mm:ss.fffZ}" -f ((Get-Date).ToUniversalTime()))
Demo = 'hello'
Recurse = #{
Hello = "hi"
Greetings = #{
what = "now"
}
}
}
})
"`n`nobj"
$jsonObj
"`n`nobj to json"
$jsonx = ConvertTo-Json($jsonObj)
$jsonx
"`n`njson to obj"
$x = ConvertFrom-Json($jsonx)
$x
"Compare"
$x -eq $jsonObj
Output
obj
MyDummyData
-----------
{Version, Demo, CreationDate, Recurse}
obj to json
{"MyDummyData":{"Version":"1.0.4","Demo":"hello","CreationDate":"2015-07-23T18:
59:04.265Z","Recurse":{"Greetings":{"what":"now"},"Hello":"hi"}}}
json to obj
{[Version, 1.0.4], [Demo, hello], [CreationDate, 2015-07-23T18:59:04.265Z], ...
Compare
False
Problem
When I test it ConvertTo-Json works perfectly.
However ConvertFrom-Json doesn't resolve to the object I started with, but rather gives me an object containing a number of name-value pairs.
Question
Can anyone spot what I've missed; or are the methods proposed on here only suitable in certain scenarios?
Related
Example of existing answer: PowerShell 2.0 ConvertFrom-Json and ConvertTo-Json implementation

Related

Adding JSON content to PSCustomObject - The property cannot be found on this object

Quite new to objects in PS.
I'm trying to create pscustomobject, adding JSON contents to it via ConvertFrom-JSON and then I'm trying to get contents from another JSON to be set on one of the properties ( nested hierarchy)
$combinedObject=#()
$props = #{
ServiceDefinitions = #()
DataCenters = #()
}
$combinedObject = New-Object -TypeName PSCustomObject -Property $props
$servicedefinitions = Get-ChildItem -Path .\ServiceDefinitions\ | Select Name
$datacenters = Get-ChildItem -Path .\DataCenters\ | Select Name
$environments = #("Production")
$env="TEST"
Foreach ($datacenter in $datacenters)
{
$datacenterdata = $null
write-host "new run"
write-host $datacenter.Name
$datacentername = $datacenter.Name
$datacenterdata = Get-Content -Path .\DataCenters\$datacentername\config.json -Raw
$datacenterformatteddata = $datacenterdata | ConvertFrom-Json -Depth 5
$combinedObject.DataCenters += $datacenterformatteddata
$combinedObject.DataCenters.$datacentername
}
Foreach ($datacenter in $datacenters)
{
$pods = $null
$datacetnername = $null
$datacentername = $datacenter.Name
$pods = Get-ChildItem -Path .\DataCenters\$datacentername\$env\Pod\ | Select Name
Foreach ($pod in $pods)
{
$podname = $pod.Name
$poddata = Get-Content -Path .\DataCenters\$datacentername\$env\Pod\$podname\config.json -Raw
#echo $combinedObject.DataCenters
write-host $datacentername
$podformatteddata = $poddata | ConvertFrom-Json -Depth 5
$combinedObject.DataCenters.$datacentername.pods += $podformatteddata
}
}
For each loop iterations I receive
The property 'pods' cannot be found on this object. Verify that the property exists and can be set.
I can query the pods but cannot set it, it looks to be of a system type System.Object[] do I need to convert it somehow to PSCustomObject for the contents of the next JSON file to be added to it?
Resolved by changing JSON from
pods:[] to
podlist:{ pods:[]}
and referencing
$combinedObject.DataCenters.$datacentername.podlist.pods
to set the value.

Powershell Parse Swagger Json

The following works to parse a Swagger json into resource, method, httptype but probably... the $path.Definition part is weirdly, how can i get $path.Definition to be an array not a string that i need to parse for the array symbol.
$json = Get-Content -Path "$PSScriptRoot/Test/example_swagger.json" | ConvertFrom-Json
$paths = Get-Member -InputObject $json.paths -MemberType NoteProperty
$result = ""
foreach($path in $paths) {
$elements = $path.Name.Substring(5).split("/") -join ","
$httpmethods = $path.Definition.Substring($path.Definition.IndexOf("#{"))
if ($httpmethods.Contains("get")) {
$result += $elements + ", GET" + "`n"
}
if ($httpmethods.Contains("post")) {
$result += $elements + ", POST" + "`n" #same methodnames different http methods
}
}
$result
As detailed in my answer to Iterating through a JSON file PowerShell, the output of ConvertFrom-Json is hard to iterate over. This makes "for each key in object" and "keys of object not known ahead of time" kinds of situations more difficult to handle, but not impossible.
You need a helper function:
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMember {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]#{Key = $key; Value = $obj."$key"}
}
}
with this, the approach gets a whole lot simpler:
$swagger = Get-Content -Path "example_swagger.json" -Encoding UTF8 -Raw | ConvertFrom-Json
$swagger.paths | Get-ObjectMember | ForEach-Object {
[pscustomobject]#{
path = $_.Key
methods = $_.Value | Get-ObjectMember | ForEach-Object Key
}
}
Applied to the default Swagger file from https://editor.swagger.io/ as a sample, this is printed
path methods
---- -------
/pet {post, put}
/pet/findByStatus get
/pet/findByTags get
/pet/{petId} {delete, get, post}
/pet/{petId}/uploadImage post
/store/inventory get
/store/order post
/store/order/{orderId} {delete, get}
/user post
/user/createWithArray post
/user/createWithList post
/user/login get
/user/logout get
/user/{username} {delete, get, put}

How to create JSON payload using power shell Foreach loop

Requirement: To send E-Mail via send grid account (Send Grid API) by attaching multiple attachments.
Description: I am able to create json payload and able to send with single attachment by hard coding attachment values. I am opening window forms dialog and able to select single/multiple files that needs to be attached.
Code:
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
#Filter = 'Documents (*.docx)|*.docx|SpreadSheet (*.xlsx)|*.xlsx'
Filter = 'All files (*.*)| *.*'
Title = 'Select File(s) for Attachments'
Multiselect = $true
}
$FileBrowser.ShowDialog() | Out-Null
$FilesEncodedContents = New-Object System.Collections.ArrayList
$AttachmentsjsonRequest = #()
if ($FileBrowser.FileNames.Count -gt 0) {
foreach ($file in $FileBrowser.FileNames) {
[string] $filerawContent = $null
$filedetails = Get-Item $file
$filerawContent = ConvertToBase64Encode $file
if (![string]::IsNullOrWhitespace($filerawContent)) {
$FilesEncodedContents.Add($filerawContent)
$obj = New-Object -TypeName PSObject
$obj | Add-Member -MemberType NoteProperty -Name filename -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content_id -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content -Value $filerawContent
$obj | Add-Member -MemberType NoteProperty -Name disposition -Value 'attachment'
$AttachmentsjsonRequest += $obj
}
}
}
Write-Host "$AttachmentsjsonRequest"
$headers = #{ }
$headers.Add("Authorization", "Bearer $ApiKey")
$headers.Add("Content-Type", "application/json")
$jsonRequest = [ordered]#{
personalizations = #(#{to = #(#{email = "$MailTo" })
subject = "$Subject"
})
from = #{email = "no-reply#xxx.com" }
attachments = "$AttachmentsjsonRequest"
content = #( #{ type = "text/plain"
value = "Sample Mail Body"
}
)
} | ConvertTo-Json -Depth 100
Write-Host $jsonRequest | ConvertTo-Json -Depth 100
Invoke-RestMethod -Uri "https://api.sendgrid.com/v3/mail/send" -Method Post -Headers
$headers -Body $jsonRequest
Write-Host "Mail Sent"
#region ConvertToBase64Encode
Function ConvertToBase64Encode([string] $AttachementFile) {
[string] $fileContentEncoded = $null
if (Test-Path $AttachementFile -PathType leaf) {
$fileContent = get-content $AttachementFile
$fileContentBytes = [System.Text.Encoding]::UTF8.GetBytes($fileContent)
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
$fileContentEncoded | set-content ((Get-Item -Path $AttachementFile).Name + ".b64")
}
else {
$fileContentEncoded = $null
Write-Host "File : $FileAttachment not exists,skipping and continue to add if any other
attachments uploaded"
}
return $fileContentEncoded
}
#endregion
Problem: [UPDATED]
Am getting below error after trying to upload single or multiple attachments
{"errors":[{"message":"Invalid type. Expected: array, given: string.","field":"attachments","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.attachments"}]} .
Reference Links :
Send Grid API Documentation:
https://sendgrid.com/docs/API_Reference/api_v3.html
My advice is to consider not building the JSON as a text, first build a Powshell object that you convert to JSON with ConvertTo-Json.
Using this method, arrays will be correctly represented in JSON. don't forget to set the -DEPTH param.
attachments array[object] An array of objects in which you can specify any attachments you want to include.
So in your Powershell object attachments is going to be a #().
of objects with content, type, filename, disposition, conten_id properties.
I realized error details in depth in late . It was giving hint in JSON payload "attachments" field is showing as string rather than array object which it is fixed by adding #(#()) to attachmentjsonrequest in "$jsonrequest" variable .
In Short: "attachmentjsonrequest is an array object which needs to convert to JSON payload by using #()
Thanks for suggesting to use array object.
attachments = #(#($AttachmentsjsonRequest))

Easy way to reference JSON arrays [duplicate]

I want to get a JSON representation of a Hashtable such as this:
#{Path="C:\temp"; Filter="*.js"}
ConvertTo-Json results in:
{
"Path": "C:\\temp",
"Filter": "*.js"
}
However, if you convert that JSON string back with ConvertFrom-Json you don't get a HashTable but a PSCustomObject.
So how can one reliably serialize the above Hashmap?
$json = #{Path="C:\temp"; Filter="*.js"} | ConvertTo-Json
$hashtable = #{}
(ConvertFrom-Json $json).psobject.properties | Foreach { $hashtable[$_.Name] = $_.Value }
Adapted from PSCustomObject to Hashtable
A little late to the discussion here, but in PowerShell 6 (Core) there is a -AsHashtable parameter in ConvertFrom-Json.
JavaScriptSerializer is available since .NET3.5 (may be installed on XP, included in Win7 and newer), it's several times faster than Convert-FromJSON and it properly parses nested objects, arrays etc.
function Parse-JsonFile([string]$file) {
$text = [IO.File]::ReadAllText($file)
$parser = New-Object Web.Script.Serialization.JavaScriptSerializer
$parser.MaxJsonLength = $text.length
Write-Output -NoEnumerate $parser.DeserializeObject($text)
}
The answer for this post is a great start, but is a bit naive when you start getting more complex json representations.
The code below will parse nested json arrays and json objects.
[CmdletBinding]
function Get-FromJson
{
param(
[Parameter(Mandatory=$true, Position=1)]
[string]$Path
)
function Get-Value {
param( $value )
$result = $null
if ( $value -is [System.Management.Automation.PSCustomObject] )
{
Write-Verbose "Get-Value: value is PSCustomObject"
$result = #{}
$value.psobject.properties | ForEach-Object {
$result[$_.Name] = Get-Value -value $_.Value
}
}
elseif ($value -is [System.Object[]])
{
$list = New-Object System.Collections.ArrayList
Write-Verbose "Get-Value: value is Array"
$value | ForEach-Object {
$list.Add((Get-Value -value $_)) | Out-Null
}
$result = $list
}
else
{
Write-Verbose "Get-Value: value is type: $($value.GetType())"
$result = $value
}
return $result
}
if (Test-Path $Path)
{
$json = Get-Content $Path -Raw
}
else
{
$json = '{}'
}
$hashtable = Get-Value -value (ConvertFrom-Json $json)
return $hashtable
}
I believe the solution presented in Converting JSON to a hashtable is closer to the PowerShell 6.0 implementation of ConvertFrom-Json
I tried with several JSON sources and I always got the right hashtable.
$mappings = #{
Letters = (
"A",
"B")
Numbers = (
"1",
"2",
"3")
Yes = 1
False = "0"
}
# TO JSON
$jsonMappings = $mappings | ConvertTo-JSON
$jsonMappings
# Back to hashtable
# In PowerShell 6.0 would be:
# | ConvertFrom-Json -AsHashtable
$jsonMappings | ConvertFrom-Json -As hashtable
you can write a function convert psobject to hashtable.
I wrote a answer here:enter link description here

Create Hashtable from JSON

I want to get a JSON representation of a Hashtable such as this:
#{Path="C:\temp"; Filter="*.js"}
ConvertTo-Json results in:
{
"Path": "C:\\temp",
"Filter": "*.js"
}
However, if you convert that JSON string back with ConvertFrom-Json you don't get a HashTable but a PSCustomObject.
So how can one reliably serialize the above Hashmap?
$json = #{Path="C:\temp"; Filter="*.js"} | ConvertTo-Json
$hashtable = #{}
(ConvertFrom-Json $json).psobject.properties | Foreach { $hashtable[$_.Name] = $_.Value }
Adapted from PSCustomObject to Hashtable
A little late to the discussion here, but in PowerShell 6 (Core) there is a -AsHashtable parameter in ConvertFrom-Json.
JavaScriptSerializer is available since .NET3.5 (may be installed on XP, included in Win7 and newer), it's several times faster than Convert-FromJSON and it properly parses nested objects, arrays etc.
function Parse-JsonFile([string]$file) {
$text = [IO.File]::ReadAllText($file)
$parser = New-Object Web.Script.Serialization.JavaScriptSerializer
$parser.MaxJsonLength = $text.length
Write-Output -NoEnumerate $parser.DeserializeObject($text)
}
The answer for this post is a great start, but is a bit naive when you start getting more complex json representations.
The code below will parse nested json arrays and json objects.
[CmdletBinding]
function Get-FromJson
{
param(
[Parameter(Mandatory=$true, Position=1)]
[string]$Path
)
function Get-Value {
param( $value )
$result = $null
if ( $value -is [System.Management.Automation.PSCustomObject] )
{
Write-Verbose "Get-Value: value is PSCustomObject"
$result = #{}
$value.psobject.properties | ForEach-Object {
$result[$_.Name] = Get-Value -value $_.Value
}
}
elseif ($value -is [System.Object[]])
{
$list = New-Object System.Collections.ArrayList
Write-Verbose "Get-Value: value is Array"
$value | ForEach-Object {
$list.Add((Get-Value -value $_)) | Out-Null
}
$result = $list
}
else
{
Write-Verbose "Get-Value: value is type: $($value.GetType())"
$result = $value
}
return $result
}
if (Test-Path $Path)
{
$json = Get-Content $Path -Raw
}
else
{
$json = '{}'
}
$hashtable = Get-Value -value (ConvertFrom-Json $json)
return $hashtable
}
I believe the solution presented in Converting JSON to a hashtable is closer to the PowerShell 6.0 implementation of ConvertFrom-Json
I tried with several JSON sources and I always got the right hashtable.
$mappings = #{
Letters = (
"A",
"B")
Numbers = (
"1",
"2",
"3")
Yes = 1
False = "0"
}
# TO JSON
$jsonMappings = $mappings | ConvertTo-JSON
$jsonMappings
# Back to hashtable
# In PowerShell 6.0 would be:
# | ConvertFrom-Json -AsHashtable
$jsonMappings | ConvertFrom-Json -As hashtable
you can write a function convert psobject to hashtable.
I wrote a answer here:enter link description here