Powershell Convert to JSON - json

I want to convert the data in the following script to JSON, can anyone let me know how to include [] in the JSON using powershell.
My script:
$URL = " http://localhost:4200/api/testinglabproject/test-run"
$projectShortName = "NES"
$testPlanName = "TestManager"
$deviceName = "testt"
$nodeManagerResourceName = "nm-4c2f1575-00fd-4363-b88a-2fb3cf587223"
$hostname = "DSTW8Y2.bla.is.abc.com"
$resourceName = "hs-515a8129-1aa0-4a14-847b-210022fe9cd7"
$hardwareSolutionType = "testt"
$emailId = "abc#gmail.com"
$data = #{
projectShortName=$projectShortName
testPlanName=$testPlanName
hardwareSolution=#{
hardwareSolutionItemList =
#{deviceName = $deviceName
nodeManagerResourceName =$nodeManagerResourceName
hostname = $hostname}
hardwareSolutionMetadataList = "[]"
resourceName = $resourceName
hardwareSolutionType = $hardwareSolutionType
}
emailId = $emailId
}
$jsondata = $data | ConvertTo-Json -Depth 3
Write-Host $jsondata
The resulting JSON should be like this:
{
"projectShortName": <projectShortName>,
"testPlanName": <planName>,
"hardwareSolution": {
"hardwareSolutionItemList": [{"deviceName": <deviceName>,
"nodeManagerResourceName": <NodeManagerResourceName>,
"hostname": <hostName>}],
"hardwareSolutionMetadataList": [],
"resourceName": <HardwareSolutionResourceName>,
"hardwareSolutionType": <hwstName>
},
"emailId": <emailID>
}

I stripped all those superfluous variables and replaced the string "[]" with an actual PowerShell array #() for the hardwareSolutionMetadataList key:
$data = #{
testPlanName = "TestManager"
projectShortName = "NES"
hardwareSolution = #{
hardwareSolutionItemList = #{
deviceName = "testt"
nodeManagerResourceName = "nm-4c2f1575-00fd-4363-b88a-2fb3cf587223"
hostname = "DSTW8Y2.bla.is.abc.com"
}
hardwareSolutionMetadataList = #()
resourceName = "hs-515a8129-1aa0-4a14-847b-210022fe9cd7"
hardwareSolutionType = "testt"
}
emailId = "abc#gmail.com"
}
$jsondata = $data | ConvertTo-Json -Depth 3
Write-Host $jsondata
PowerShell's idea of JSON formatting is a bit odd, but structurally it's OK.
{
"hardwareSolution": {
"hardwareSolutionItemList": {
"deviceName": "testt",
"hostname": "DSTW8Y2.bla.is.abc.com",
"nodeManagerResourceName": "nm-4c2f1575-00fd-4363-b88a-2fb3cf587223"
},
"resourceName": "hs-515a8129-1aa0-4a14-847b-210022fe9cd7",
"hardwareSolutionMetadataList": [
],
"hardwareSolutionType": "testt"
},
"testPlanName": "TestManager",
"emailId": "abc#gmail.com",
"projectShortName": "NES"
}
You can use the -Compress parameter to remove the whitespace for uploading the JSON somewhere.
{"hardwareSolution":{"hardwareSolutionItemList":{"deviceName":"testt","hostname":"DSTW8Y2.bla.is.abc.com","nodeManagerResourceName":"nm-4c2f1575-00fd-4363-b88a-2fb3cf587223"},"resourceName":"hs-515a8129-1aa0-4a14-847b-210022fe9cd7","hardwareSolutionMetadataList":[],"hardwareSolutionType":"testt"},"testPlanName":"TestManager","emailId":"abc#gmail.com","projectShortName":"NES"}

Related

Powershell: How to create a JSON in the GeoJSON structure

I'm having problems creating a GeoJSON file. I'm looping through video files extracting info such as datetaken, name, coordinates, etc. I want to write this data to a JSON file so I can plot them on googlemaps. But I'm stuck. I can't get the lat/lng in the correct json format.
The GeoJSON structure is as follows:
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "Lost Islands"
}
]}
My code, no matter what I try, generates the following or something similar.
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": "System.Collections.Hashtable"
},
"properties": {
"name": "Lost Island"
}
]}
My code (simplified for here):
cls
$dirName = "C:\temp"
$filter = "*.mp4"
$jsonBase = #{}
$features = New-Object System.Collections.ArrayList
$coordinatesList = New-Object System.Collections.ArrayList
$coordinates = New-Object System.Collections.ArrayList
$geometry = New-Object System.Collections.ArrayList
Get-ChildItem $dirName -include $filter -recurse -File | foreach {
$lat = 10.12345
$lng = 20.12345
$vidDate = "2022-09-11T12:00:00.000000Z"
$coordinatesList = New-Object System.Collections.ArrayList
$coordinatesList.Add(#{$lat=$lng;})
$coordinates = New-Object System.Collections.ArrayList
$coordinates.Add(#{"coordinates"=$coordinatesList})
$geometry = #{}
$geometry.Add("coordinates",$coordinates)
$geometry.Add("type","Point")
$features.Add(#{"geometry"=$geometry;
"type" = "Feature";
"properties" = #{"fileName"=($_).Name;"pathToFile"=($_).FullName;"takenDate"=$vidDate;}
})
}
$jsonBase.Add("features",$features)
$jsonstring = $jsonBase | ConvertTo-Json -Depth 3
Write-Host $jsonstring
Any thoughts on where I'm going wrong?
Thanks to mclayton for spotting the depth mistake.
I still had to make a small change to get it in the correct format. Here's the final code:
cls
$dirName = "C:\temp"
$filter = "*.mp4"
$jsonBase = #{}
$features = New-Object System.Collections.ArrayList
$geometry = New-Object System.Collections.ArrayList
Get-ChildItem $dirName -include $filter -recurse -File | foreach {
$lat = 10.12345
$lng = 20.12345
$vidDate = "2022-09-11T12:00:00.000000Z"
$geometry = #{}
$geometry.Add("coordinates",($lat,$lng))
$geometry.Add("type","Point")
$features.Add(#{"geometry"=$geometry;
"type" = "Feature";
"properties" = #{"fileName"=($_).Name;"pathToFile"=($_).FullName;"takenDate"=$vidDate;}
})
}
$jsonBase.Add("features",$features)
$jsonstring = $jsonBase | ConvertTo-Json -Depth 10
Write-Host $jsonstring
The issue is in this line:
$coordinatesList.Add(#{ $lat = $lng })
$lat will become a double type Key on your hashtable and ConvertTo-Json only allows string type keys, probably you got this error but didn't notice it:
$lat = 10.12345
$lng = 20.12345
#{ $lat = $lng } | ConvertTo-Json
Errors with
The type 'System.Collections.Hashtable' is not supported for serialization or deserialization of a dictionary. Keys must be strings.
But also, looking at your expected Json, you most likely wanted coordinates to be an array instead of a key / value pair. Here is a streamlined version of your code:
#{
features = #(Get-ChildItem $dirName -Filter $filter -Recurse -File | ForEach-Object {
$lat = 10.12345
$lng = 20.12345
$vidDate = "2022-09-11T12:00:00.000000Z"
[ordered]#{
type = 'Feature'
geometry = [ordered]#{
type = 'Point'
coordinates = $lat, $lng # Should be Array Here
}
properties = [ordered]#{
fileName = $_.Name
pathToFile = $_.FullName
takenDate = $vidDate
}
}
}
)} | ConvertTo-Json -Depth 99

Dynamically Build JSON - PowerShell

I am writing a PowerShell function to build the JSON that will be passed to an API. I am using PowerShell 5.
The API expects a certain format and an example is below.
{
“task”: {
“status”: {
“name”: “Resolved”
},
“owner”: {
“name”: “User”
},
“comment”: “Test”
}
}
The structure of the JSON is stored in nested hash tables then piped to ConvertTo-Json and I am passing the data values through parameters.
$baseTask = #{
task = #{
comment = $Comment;
status = #{
name = $Status;
owner = #{
name = $Owner;
}
}
}
I want the function to be as dynamic as possible so I have the identifier as mandatory and then all other parameters as optional.
Param(
[Parameter(Mandatory=$true)]
$TaskID,
$Comment,
$Status,
$Owner
)
If the parameter is NULL I want to remove that element from the definition so that it doesn’t pass NULL to the API. I have the logic below.
If([String]::IsNullOrEmpty($Comment)) {
$baseTask.task.Remove(‘comment’)
}
If([String]::IsNullOrEmpty($Status)) {
$baseTask.task.Remove(‘status’)
}
If([String]::IsNullOrEmpty($Owner)) {
$baseTask.task.Remove(‘owner’)
}
This works; however if I have 50 parameters then I am going to have a lot of repetition with the null checks so I feel there must be a more dynamic way to do this ideally with some sort of loop.
I thought about a hash table with mapping between variable name and command to run, but I can’t find a way to get the name of the variable during execution.
Any help would be much appreciated.
You may check to see which parameters were not used by comparing the bound parameters against all available parameters for your command and then use this to remove the different elements from your hash table.
function New-DynamicJson {
Param(
[Parameter(Mandatory = $true)]
$TaskID,
$Comment,
$Status,
$Owner
)
$baseTask = #{
task = [ordered]#{
Id = $TaskID;
comment = $Comment;
status = #{
name = $Status;
}
owner = #{
name = $Owner;
}
}
}
$commonParams = 'Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable',
'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable'
$MyInvocation.MyCommand.Parameters.Keys.Where({ $_ -notin $commonParams }) |
Where-Object { $_ -notin $PSBoundParameters.Keys } |
ForEach-Object { $baseTask.task.Remove($_) }
$baseTask | ConvertTo-Json
}
Output
PS> New-DynamicJson -TaskID 103 -Comment 'some comment'
{
"task": {
"Id": 103,
"comment": "some comment"
}
}
(Thank you mklement0 for the suggestion to use $MyInvocation instead of $PSCmdlet.MyInvocation which also makes the solution work in non-advanced functions)
You can take something like that with care.
The idea is to convert names ('status') to paths where it should be ('status.name') and then get a hashtable like
'id' = 22
'status.name' = 'new'
'comment' = 'text'
'owner.name' = 'user'
and convert it to multi-layered hashtable based on "dot" separator then:
$baseTask = #{
task = #{
comment = $Comment;
status = #{
name = $Status;
owner = #{
name = $Owner;
}
}
}
And then to JSON
The example below is an example and should be used with caution as it HAS some problems.
function test {
[CMDLetBinding()]
Param(
[Parameter(Mandatory=$true)]
$TaskID,
$Comment,
$Status,
$Owner
)
$paramList = #{}
$params = $PSCmdlet.MyInvocation.BoundParameters
foreach ($paramName in $params.Keys) {
switch -Exact ($paramName) {
'TaskID' { $paramList['id'] = $params[$paramName] }
'Comment' { $paramList['comment'] = $params[$paramName] }
'Status' { $paramList['status.name'] = $params[$paramName] }
'Owner' { $paramList['owner.name'] = $params[$paramName] }
}
}
$replaced = 0
do {
$replaced = 0
$keys = #($paramList.Keys)
foreach ($key in $keys) {
$dotPos = $key.LastIndexOf('.')
if ($dotPos -gt 0) {
$value = $paramList[$key]
if (-not $value.GetType().IsValueType) {
if ($value.Clone -ne $null) {
$value = $value.Clone()
}
}
$subKey = $key.Substring($dotPos + 1)
$newKey = $key.Substring(0, $dotPos)
$paramList.Remove($key) | Out-Null
$newVal = #{$subKey=$value}
$paramList.Add($newKey, $newVal)
$replaced++
}
}
} while ($replaced -gt 0)
return $paramList
}
test -TaskID 123 -Status 'New' -Comment 'Test' -Owner 'user' | ConvertTo-Json -Depth 10 -Compress:$false

"message": "Illegal string offset 'product_id'", In Laravel RESTfull API

Am developing Laravel RESTful API for saving array of Json object into DB using php associative array and this is the error am getting.;
"message": "Illegal string offset 'product_id'",
"exception": "ErrorException",
...
This is the array of JSON object am trying to save in Mysql DB
"userId": "1",
"userName": "Dan",
"userEmail": "dan#gmail.com"
"product": [
{
"product_id": "31",
"product_name": "Orange",
"product_price": "USD 0.5"
}
]
}
This is the php function for save Json object into DB.
$userId = $request -> input('userId');
$userName = $request ->input('userName');
$userEmail = $request ->input('userEmail');
$data = array(
"userId"=>$userId,
"userName"=>$userName,
"userEmail"=>$userEmail
);
$user = User::create($data);
if($order){
//Storing the received JSON in $json.
$json = file_get_contents('php://input');
// Decode the received JSON and store into $obj
$obj = json_decode($json,true);
foreach($obj as $product){
$product_id = $product['product_id'];
$product_name = $product['product_name'];
$product_price = $product['product_price'];
$product = array(
"product_id" => $product_id,
"product_name" => $product_name,
"product_price" => $product_price
);
DB::table('products')->insert($product);
}
if($product){
// On query success it will print below message.
$MSG = 'Data Successfully Submitted.' ;
// Converting the message into JSON format.
$json = json_encode($MSG);
// Echo the message.
echo $json ;
}
else{
echo 'Try Again';
}
Guys where am I making mistake. Thank you in advance!

Curl and powershell json woes

I'm still having issues with getting json working with the curl command in powershell.
even a simple request to POST something into elastic fails miserably with the error
Unexpected character ('D' (code 68)): was expecting double-quote to start field name
I've stripped the script down to the basics just to try and test curl and json and still get failures
$curlExe = "h:\powershell\esb\elastic\curl\curl.exe"
$elasticdata = #{
timereceived = "test"
timesent = "testing"
name = "anon"
status = 0
}
$curldata = $elasticdata | convertto-json -Compress
$elasticoutput = "h:\powershell\esb\elastic\elastic.txt"
$elastichost = "http://localhost:9200/newtest20/filecopy/?pretty"
$elasticheader = "content-type: application/json"
$elamethod = "POST"
$curlargs = $elastichost,
'-X',$elamethod,
'-d',$curldata,
'-H',$elasticheader
& $curlexe #curlargs
If your server is running Powershell 2.0 you will not have Invoke-webRequestbut ConvertTo-Json will also be missing.
I also encountered this issue in the past and I made these functions to workaround that issue
function Invoke-WebRequest([string] $Url, [string] $Method, $BodyObject)
{
$request = [System.Net.WebRequest]::Create($Url)
$request.Method = $Method
$request.ContentType = "application/json"
if ($Method -eq "POST")
{
try
{
$body = ConvertTo-Json20 -InputObject $BodyObject
$requestStream = $request.GetRequestStream()
$streamWriter = New-Object System.IO.StreamWriter($requestStream)
$streamWriter.Write($body)
}
finally
{
if ($null -ne $streamWriter) { $streamWriter.Dispose() }
if ($null -ne $requestStream) { $requestStream.Dispose() }
}
}
$response = $request.GetResponse()
if ($response.StatusCode -ne [System.Net.HttpStatusCode]::OK)
{
throw "ERROR Could not $Method url [$Url]"
}
return $response
}
function ConvertTo-Json20($InputObject){
Add-Type -Assembly System.Web.Extensions
$jsonSerializer = New-Object System.Web.Script.Serialization.JavascriptSerializer
return $jsonSerializer.Serialize($InputObject)
}

Post PowerShell JSON into ElasticSearch

I'm trying to push some data into ElasticSearch via PowerShell. I'm converting the data into JSON, then trying both Invoke-WebRequest and Invoke-RestMethod, but always get errors on malformed data or content-type not supported. I haven't created the index as I believe it will create it for me.
Anyone able to assist on what I'm missing/doing wrong?
Example code:
$data = #()
$CustomObject = [pscustomobject]#{
SqlInstance = "myserver1"
Database = "mydb"
Schema = "versioning"
Name = "DataVersionHistory"
IndexSpaceUsed = 0
DataSpaceUsed = 0
RowCount = 0
};
$data += $CustomObject;
$CustomObject = [pscustomobject]#{
SqlInstance = "myserver1"
Database = "mydb"
Schema = "versioning"
Name = "VersionHistory"
IndexSpaceUsed = 10
DataSpaceUsed = 25
RowCount = 3000
};
$data += $CustomObject;
$myJson = ConvertTo-Json -InputObject $data ;
Invoke-RestMethod -Uri http://localhost:9200/myindex/mytype/_bulk?pretty `
-Method POST -Body $myJson -ContentType "application/json"
Bulk request is not actual json. You should use following notation:
curl -XPOST 'localhost:9200/_bulk?pretty' -H 'Content-Type: application/json' -d'
{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "type1", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "type1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
'
$data = #()
$CustomObject = [pscustomobject]#{
SqlInstance = "myserver1"
Database = "mydb"
Schema = "versioning"
Name = "DataVersionHistory"
IndexSpaceUsed = 0
DataSpaceUsed = 0
RowCount = 0
};
$data += $CustomObject;
$CustomObject = [pscustomobject]#{
SqlInstance = "myserver1"
Database = "mydb"
Schema = "versioning"
Name = "VersionHistory"
IndexSpaceUsed = 10
DataSpaceUsed = 25
RowCount = 3000
};
$data += $CustomObject
At this point you have a collection of objects contained in the array $data.
NOTE: for the bulk API the final line of the json data must end with a newline character \n. So I am using a here-string to append the newline char \n to each json element.
also notice that i removed pretty print. this is to play nice with the bulk api.
doc_as_upsert ensures that if the doc exists leave it alone, if not add as new.
$json_col = #()
$data |
ForEach-Object {
#convert object to json
$json_element = #{doc = $_; doc_as_upsert = $true}
| ConvertTo-Json -Depth 1 -Compress
#construt here string with literal \n
$json_col += #"
$json_element\n
"#
}
Invoke-RestMethod -Method Post -Uri "http://localhost:9200/myindex/mytype/_bulk?" -Body $json_col -ErrorAction Stop