Creating json payload -- where to start

I have recently started working on an attempt to do some automations and most of the payloads have been pretty straight forward. Although this one seems a bit more complex and i am not sure how to setup the array prior to converting it to json to get the expected format correct. The goal is to produce a payload that will create the aws account connection in a backup tool. (netbackup)

Here is what the expected format with an example is:

configurationRequest

{
    "data": {
        "id": "string",
        "type": "plugininstance",
        "attributes": {
            "cloudpointHostname": "string",
            "configurationAttributes": [
                {
                    "name": "string",
                    "singlevalue": "string",
                    "multivalue": [
                        "string"
                    ]
                }
            ]
        }
    }
}

Example -

POST https://cloudpointhost/netbackup/config/snapshotproviders/configuredplugins/aws/instances

configurationRequest

{
    "data": {
        "id": "ConfigurationName",
        "type": "plugininstance",
        "attributes": {
            "configurationAttributes": [
                {
                    "name": "accesskey",
                    "singlevalue": "AccessKeyHere"
                },
                {
                    "name": "secretkey",
                    "singlevalue": "SecretKeyHere"
                },
                {
                    "name": "regions",
                    "multivalue": [
                        "ap-northeast-1",
                        "ap-northeast-2"
                    ]
                }
            ]
        }
    }
}

Here is my current code.

$AccountList = Import-Csv $CSVFilename 
foreach ($Account in $AccountList) {
$JSON = @{
awsid = $Account.aws_account_id
awsalias = $Account.aws_account_alias
id = $Account.aws_account_name
type = "aws"
accesskey = $Account.veritascloudpoint_aws_iam_access_key_id
secretkey = $Account.veritascloudpoint_aws_iam_access_key_secret
regions = $Account.regions.Split(',').Trim() -as [String[]]

} | ConvertTo-Json



$JSON
}

Here is my sample file:

aws_account_id,aws_account_alias,aws_account_name,veritascloudpoint_aws_iam_access_key_id,veritascloudpoint_aws_iam_access_key_secret,regions
1111,uat,UAT ENV,key,skey,us-east-1
2222,ops,OPS ENV,key,skey,“eu-west-1, us-east-1”

 

Thanks for any help in advance.

Using your sample format…

More clearly-formatted in JSON form:

"configurationRequest": {
    "data": {
        "id": "string",
        "type": "plugininstance",
        "attributes": {
            "cloudpointHostname": "string",
            "configurationAttributes": [
                {
                    "name": "string",
                    "singlevalue": "string",
                    "multivalue": [
                        "string"
                    ]
                }
            ]
        }
    }
}

And when you translate this to PowerShell, there’s really only two rules. One, [ ] denotes an array. Two, { } denotes a dictionary, with named keys. Typically this will be done with a hashtable. Here’s one way of putting it together:

$ConfigurationRequest = @{
    data = @{
        id = "string"
        type = "plugininstance"
        attributes = @{
            cloudpointHostname = "string"
            configurationAttributes = @(
                @{
                    name = "string"
                    singlevalue = "string"
                    multivalue  = @(
                        "string"
                    )
                }
            )
        }
    }
}

See the similarities? These data structures are intrinsically very similar. However, importantly, your last bit of data there is intrinsically very different. It’s a flat table. This payload you’re looking for has 2-3 levels of nested items, which you’re going to have a mighty difficult time properly representing in that CSV tabular format.

The best you’ll be able to do is take the most important portions of the data and store those, then manually reconstruct your data object piece by piece. It would be a lot easier to just store it as hashtables or PSCustomObjects (basically just add [PSCustomObject] immediately before every @{) with properties intact in an actual JSON file.

When sending such a request to a server, the Invoke-RestMethod cmdlet is very efficient at dealing with API endpoints like this that work primarily with JSON or XML, and will happily convert back and forth between objects and hashtables in memory, and JSON to communicate with the API directly, often without you ever really needing to work directly with the JSON. :slight_smile:

Thank you for the detail. I have been working on this and here is what i have so far but i catn get bast the configurationAttribute showing as system.collections.hashtable when i convert to json.

 

Here is the code:

$ConfigurationRequest = @{
data = @{
id = $Account.aws_account_alias
type = "plugininstance"
attributes = @{
cloudpointHostname = "led36461.wic.west.com"
configurationAttributes = @(
@{
name = $Account.veritascloudpoint_aws_iam_access_key_id
singlevalue = $Account.veritascloudpoint_aws_iam_access_key_secret
multivalue = @(
$Account.regions.Split(',').Trim() -as [String[]]
)
}
)
}
}
}
$ConfigurationRequest|ConvertTo-Json

And here is the output i get:

 

 C:\> $ConfigurationRequest|ConvertTo-Json
{
"data": {
"attributes": {
"configurationAttributes": "System.Collections.Hashtable",
"cloudpointHostname": "led36461.wic.west.com"
},
"id": "wdc-svc-ops",
"type": "plugininstance"
}
}

Thoughts??

The ConvertTo-Json Cmdlet has a -Depth parameter that specifies how many levels of the contained object should be included when converting to JSON. The default is 2. Your JSON payload looks to have more levels that the default. Try using the -Depth parameter when converting to JSON.

$ConfigurationRequest |ConvertTo-Json -Depth 4

pwshliquori

That worked great. Thanks for that.

So the vendor provided me an updated syntax. But i am not following the above form Joel on how i would adjust the configurationatrributes section with multiple attributes:

 

{

  "data": {

    "id": "PluginName",     <--- Name that you would like to give to this Plugin configuration

    "type": "plugininstance",    <--- This should remain as “plugininstance”

    "attributes": {

      "configurationAttributes": [

        {

          "name": "accesskey",   <--- This will remain as “accesskey”. It also denotes that this plugin uses AWS AccessKey as the credential

          "singlevalue": "ACCESSKEY_VALUE"   <--- AccessKey value that you got from AWS.

        },

        {

          "name": "secretkey",   <--- This will remain as “secretkey”.

          "singlevalue": "SECRETKEY_VALUE"  <--- SecretKey value that you got from AWS.

        },

        {

          "name": "regions",  <--- This will remain as “regions”. This let's you specify all the regions that you want under this plugin.

          "multivalue": [

            "region1",  <--- AWS Region name as per Supported region list*.

            "region2",

            "region3"

          ]

        }

      ]

    }

  }

}

Are you trying to convert this from JSON back to PowerShell?

Kind of. The admin guide for the API shows the json example but I need to build that from powershell . And to do that I need to figure out how that needs to look from and object perspective.

You really don’t need to if you are invoking the API from PowerShell. Just use a here-string and use just the JSON payload directly.

$here = @'
{

  "data": {

    "id": "PluginName",     < --- Name that you would like to give to this Plugin configuration

    "type": "plugininstance",    < --- This should remain as “plugininstance”

    "attributes": {

      "configurationAttributes": [

        {

          "name": "accesskey",   < --- This will remain as “accesskey”. It also denotes that this plugin uses AWS AccessKey as the credential

          "singlevalue": "ACCESSKEY_VALUE"   < --- AccessKey value that you got from AWS.

        },

        {

          "name": "secretkey",   < --- This will remain as “secretkey”.

          "singlevalue": "SECRETKEY_VALUE"  < --- SecretKey value that you got from AWS.

        },

        {

          "name": "regions",  < --- This will remain as “regions”. This let's you specify all the regions that you want under this plugin.

          "multivalue": [

            "region1",  < --- AWS Region name as per Supported region list*.

            "region2",

            "region3"

          ]

        }

      ]

    }

  }

}
'@

Then if you are using Invoke-RestMethod, just use $here as the Body parameter. Does that make sense? Does that help at all?

pwshliquori

It does I will play with that some. I should still be able to loop through replacing what I need to make that work with my loop.

Yes. And you can also use variables within the here-strings by using ${var}, but you need to use double quotes:

$here = @"
${var}
"@

pwshliquori

You can easily merge hashtables, effectively combining whatever properties you need like so:
Consider i want to add more items to key3, so I would do so like this:

[pre]
$Table = [ordered]@{
‘key1’ = ‘value1’
‘key2’ = ‘value2’
‘key3’ = @(
@{
“subkey3” = “subkey3 value”
}
)
}

$AddToKey3 = @{
‘subkey4’ = ‘subkey4 value’
‘subkey5’ = @(
@{‘sub-add1’ = ‘sub-add value’ }
@{‘sub-add2’ = ‘sub-add 2 value’ }
)
}

$table.key3 += $AddToKey3

$Table | ConvertTo-Json -Depth 4 -Compress
[/pre]

I would consider minifying your code with the -Compress switch of `Convertto-Json` if it does not need to be human readable.

I have been working with the $here method and thats working well. The one problem i have is when i need to populate this section

 

          "name": "regions",  
          "multivalue": [
            "us-east-1",  
            "us-east-2",
            "us-west-1",
            "us-west-2"
          ]

That comes form a var out of a csv file in the larger script

$CSVFilename = 'C:\users\nbritton\desktop\Book3-test.csv' #input for aws accounts


$AccountList = Import-Csv $CSVFilename 
foreach ($Account in $AccountList) {

$awsalias = $Account.aws_account_name
$awsid = $Account.aws_account_id
$awsid = $Account.aws_account_name
$awstype = "aws"
$awsaccesskey = $Account.veritascloudpoint_aws_iam_access_key_id
$awssecretkey = $Account.veritascloudpoint_aws_iam_access_key_secret
$awsregions = $Account.regions.Split(',').Trim() -as [String[]]

}

$here = @"
{
  "data": {
    "id": "$awsalias",     
    "type": "plugininstance",    
    "attributes": {
      "configurationAttributes": [
        {
          "name": "accesskey",   
          "singlevalue": "$awsaccesskey"   
        },
        {
          "name": "secretkey",   
          "singlevalue": "$awssecretkey"  
        },
        {
          "name": "regions",  
          "multivalue": [
            "us-east-1",  
            "us-east-2",
            "us-west-1",
            "us-west-2"
          ]
        }
      ]
    }
  }
}
"@

 

How can i display that var so it would be in the correct syntax that json is expecting?

 

 

Why is there red dots?

Why is there red dots?

It’s a forums thing. I always have to manually specify my pre tags:

[pre]
Function Test {
this is indented without dots
}
[/pre]