How to add element to object

Welcome Forums General PowerShell Q&A How to add element to object

This topic contains 9 replies, has 2 voices, and was last updated by

 
Participant
2 months ago.

  • Author
    Posts
  • #166223

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    I have this use case of manipulating Azure object JSON templates.
    Take this example https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-site-to-site-vpn/azuredeploy.parameters.json which looks like

    {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "adminUsername": {
          "value": "GEN-UNIQUE"
        },
        "localGatewayIpAddress": {
          "value": "52.25.48.88"
        },
        "localAddressPrefix": {
          "value": "10.0.0.0/24"
        },
        "azureVNetAddressPrefix": {
          "value": "10.3.0.0/16"
        },
        "subnetPrefix": {
          "value": "10.3.0.0/24"
        },
        "gatewaySubnetPrefix": {
          "value": "10.3.200.0/29"
        },
        "sharedKey": {
          "value": "GEN-UNIQUE"
        },
        "adminPasswordOrKey": {
          "value": "GEN-SSH-PUB-KEY"
        }
      }
    }
    

    Now I can read it fine like this:

    $Uri = 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-site-to-site-vpn/azuredeploy.parameters.json'
    $myParamterSet = Invoke-WebRequest $Uri | ConvertFrom-Json
    

    and we can see the parameters like

    $myParamterSet.parameters
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    

    We can even change them like

    PS C:\scripts> $myParamterSet.parameters.adminUsername.value = 'bla1'
    
    PS C:\scripts> $myParamterSet.parameters
    
    adminUsername          : @{value=bla1}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    

    My question is how to add another parameter to this parameter set?
    For example, I want to add

    environment     : @{value=dev}
    

    Trying to add an element fails:

    PS C:\scripts> $myParamterSet.parameters += [PSCustomObject]@{environment='dev'}
    Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'.
    At line:1 char:1
    + $myParamterSet.parameters += [PSCustomObject]@{environment='dev'}
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound
    

    Get-Member shows that these parameters are PS Custom Objects:

    PS C:\scripts> $myParamterSet.parameters | Get-Member
    
    
       TypeName: System.Management.Automation.PSCustomObject
    
    Name                   MemberType   Definition                                                                             
    ----                   ----------   ----------                                                                             
    Equals                 Method       bool Equals(System.Object obj)                                                         
    GetHashCode            Method       int GetHashCode()                                                                      
    GetType                Method       type GetType()                                                                         
    ToString               Method       string ToString()                                                                      
    adminPasswordOrKey     NoteProperty System.Management.Automation.PSCustomObject adminPasswordOrKey=@{value=GEN-SSH-PUB-KEY}
    adminUsername          NoteProperty System.Management.Automation.PSCustomObject adminUsername=@{value=bla1}                
    azureVNetAddressPrefix NoteProperty System.Management.Automation.PSCustomObject azureVNetAddressPrefix=@{value=10.3.0.0/16}
    gatewaySubnetPrefix    NoteProperty System.Management.Automation.PSCustomObject gatewaySubnetPrefix=@{value=10.3.200.0/29} 
    localAddressPrefix     NoteProperty System.Management.Automation.PSCustomObject localAddressPrefix=@{value=10.0.0.0/24}    
    localGatewayIpAddress  NoteProperty System.Management.Automation.PSCustomObject localGatewayIpAddress=@{value=52.25.48.88} 
    sharedKey              NoteProperty System.Management.Automation.PSCustomObject sharedKey=@{value=GEN-UNIQUE}              
    subnetPrefix           NoteProperty System.Management.Automation.PSCustomObject subnetPrefix=@{value=10.3.0.0/24}   
    

    How do I add one more?

  • #166226

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    nvm, this works:

    $myParamterSet.parameters | Add-Member -MemberType NoteProperty -Name 'Environmnmet' -Value ([PSCustomObject]@{value='dev'})
    
  • #166244

    Participant
    Topics: 2
    Replies: 483
    Points: 1,151
    Helping Hand
    Rank: Community Hero

    You can also do:

    $myParameterSet.parameters = $myParameterSet.Parameters | Select-Object -Property @{ Name= 'Environmnmet'; Expression = {[PSCustomObject]@{value='dev'}} }

     

  • #166271

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    @Joel nice!
    Now I'm stuck at trying to add a child object.

    For example how do I add a node like:

            "ApplicationName": {
                "type": "string",
                "maxLength": 3,
                "metadata": {
                    "description": "some desc"
                }
            }
    

    where the resulting PS object looks like:

    $myParameterSet.parameters.ApplicationName
    
    type   maxLength metadata                
    ----   --------- --------                
    string         3 @{description=some desc}
    
  • #166483

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    @Joel,
    Actually, using Select does not work:

    $Uri = 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-site-to-site-vpn/azuredeploy.parameters.json'
    $myParameterSet = Invoke-WebRequest $Uri | ConvertFrom-Json
    $myParameterSet.parameters
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    
    $myParameterSet.parameters = $myParameterSet.Parameters | 
        Select-Object -Property @{ Name= 'add1'; Expression = {[PSCustomObject]@{value='dev1'}} }
    
    $myParameterSet.parameters
    
    add1         
    ----         
    @{value=dev1}
    
    
  • #166489

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    Whereas Add-Member works:

    $Uri = 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-site-to-site-vpn/azuredeploy.parameters.json'
    $myParameterSet = Invoke-WebRequest $Uri | ConvertFrom-Json
    $myParameterSet.parameters
    $myParameterSet.parameters | Add-Member -MemberType NoteProperty -Name 'Environmnmet' -Value ([PSCustomObject]@{value='dev'})
    $myParameterSet.parameters
    
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    Environmnmet           : @{value=dev}
    
  • #166495

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    I think I got it:

    $Uri = 'https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/201-site-to-site-vpn/azuredeploy.parameters.json'
    $myParameterSet = Invoke-WebRequest $Uri | ConvertFrom-Json
    $myParameterSet.parameters
    $myParameterSet.parameters | Add-Member -MemberType NoteProperty -Name 'ApplicationName' -Value ([PSCustomObject]@{})
    $myParameterSet.parameters
    $myParameterSet.parameters.ApplicationName | Add-Member -MemberType NoteProperty -Name 'type' -Value 'string'
    $myParameterSet.parameters.ApplicationName | Add-Member -MemberType NoteProperty -Name 'maxlength' -Value 3
    $myParameterSet.parameters.ApplicationName | Add-Member -MemberType NoteProperty -Name 'metadata' -Value ([PSCustomObject]@{description = 'my desc'})
    $myParameterSet.parameters
    $myParameterSet.parameters.ApplicationName
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    ApplicationName        : 
    
    adminUsername          : @{value=GEN-UNIQUE}
    localGatewayIpAddress  : @{value=52.25.48.88}
    localAddressPrefix     : @{value=10.0.0.0/24}
    azureVNetAddressPrefix : @{value=10.3.0.0/16}
    subnetPrefix           : @{value=10.3.0.0/24}
    gatewaySubnetPrefix    : @{value=10.3.200.0/29}
    sharedKey              : @{value=GEN-UNIQUE}
    adminPasswordOrKey     : @{value=GEN-SSH-PUB-KEY}
    ApplicationName        : @{type=string; maxlength=3; metadata=}
    
    type      : string
    maxlength : 3
    metadata  : @{description=my desc}
    

    The trick to creating a subnode is line 4 creating an empty PSCustomObject, otherwise line 6 fails

  • #166501

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    and when you spit it back out to JSON, it looks right (which is the whole point behind this exercise)

    $myParameterSet | ConvertTo-Json | Out-File .\test1.txt 
    notepad .\test1.txt
    
    {
        "$schema":  "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
        "contentVersion":  "1.0.0.0",
        "parameters":  {
                           "adminUsername":  {
                                                 "value":  "GEN-UNIQUE"
                                             },
                           "localGatewayIpAddress":  {
                                                         "value":  "52.25.48.88"
                                                     },
                           "localAddressPrefix":  {
                                                      "value":  "10.0.0.0/24"
                                                  },
                           "azureVNetAddressPrefix":  {
                                                          "value":  "10.3.0.0/16"
                                                      },
                           "subnetPrefix":  {
                                                "value":  "10.3.0.0/24"
                                            },
                           "gatewaySubnetPrefix":  {
                                                       "value":  "10.3.200.0/29"
                                                   },
                           "sharedKey":  {
                                             "value":  "GEN-UNIQUE"
                                         },
                           "adminPasswordOrKey":  {
                                                      "value":  "GEN-SSH-PUB-KEY"
                                                  },
                           "ApplicationName":  {
                                                   "type":  "string",
                                                   "maxlength":  3,
                                                   "metadata":  "@{description=my desc}"
                                               }
                       }
    }
    
  • #166537

    Participant
    Topics: 9
    Replies: 423
    Points: 676
    Helping Hand
    Rank: Major Contributor

    This is actually a bug in ConvertTo-Json version 3.1.0.0 out of the C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.PowerShell.Commands.Utility\v4.0_3.0.0.0__31bf3856ad364e35\Microsoft.PowerShell.Commands.Utility.dll

    Proof:

    @'
    {
        "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "ApplicationName": {
                "type": "string",
                "maxLength": 3,
                "metadata": {
                    "description": "my desc"
                }
            },
            "plan_name": {
                "type": "String"
            }
        },
        "variables": {
            "resourceNames": {
                "name": "EDSENDGRID06",
                "commonResourceGroup": "[tolower(concat(parameters('ApplicationName'),'-',parameters('Environment'),'-',parameters('shortlocation'),'-',parameters('tenant'),'-rgp-','01'))]"
            },
            "TemplateURLs": {
                "sendgrid": "[concat(parameters('artifacts_baseUri'),'/ArmTemplates/master/Public/lib/linkedTemplates/sendgrid.json')]"
            }
        }
    }
    '@ | ConvertFrom-Json | ConvertTo-Json
    

    This retuns:

    {
        "$schema":  "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
        "contentVersion":  "1.0.0.0",
        "parameters":  {
                           "ApplicationName":  {
                                                   "type":  "string",
                                                   "maxLength":  3,
                                                   "metadata":  "@{description=my desc}"
                                               },
                           "plan_name":  {
                                             "type":  "String"
                                         }
                       },
        "variables":  {
                          "resourceNames":  {
                                                "name":  "EDSENDGRID06",
                                                "commonResourceGroup":  "[tolower(concat(parameters(\u0027ApplicationName\u0027),\u0027-\u0027,parameters(\u0027Environ
    ment\u0027),\u0027-\u0027,parameters(\u0027shortlocation\u0027),\u0027-\u0027,parameters(\u0027tenant\u0027),\u0027-rgp-\u0027,\u002701\u0027))]"
                                            },
                          "TemplateURLs":  {
                                               "sendgrid":  "[concat(parameters(\u0027artifacts_baseUri\u0027),\u0027/ArmTemplates/master/Public/lib/linkedTemplates/se
    ndgrid.json\u0027)]"
                                           }
                      }
    }
    

    Note the messed up line 8 in the output compared to what it should be – lines 9,10,11 in the input

    I wrote a Fix-Json function to fix this – part of the AZSBTools PS module:

    $TempFile = New-TemporaryFile
    @'
    {
        "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
        "contentVersion": "1.0.0.0",
        "parameters": {
            "ApplicationName": {
                "type": "string",
                "maxLength": 3,
                "metadata": {
                    "description": "my desc"
                }
            },
            "plan_name": {
                "type": "String"
            }
        },
        "variables": {
            "resourceNames": {
                "name": "EDSENDGRID06",
                "commonResourceGroup": "[tolower(concat(parameters('ApplicationName'),'-',parameters('Environment'),'-',parameters('shortlocation'),'-',parameters('tenant'),'-rgp-','01'))]"
            },
            "TemplateURLs": {
                "sendgrid": "[concat(parameters('artifacts_baseUri'),'/ArmTemplates/master/Public/lib/linkedTemplates/sendgrid.json')]"
            }
        }
    }
    '@ | ConvertFrom-Json | ConvertTo-Json | Out-File $TempFile 
    Fix-Json $TempFile 
    

    Now the output looks like:

    {
        "$schema":  "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
        "contentVersion":  "1.0.0.0",
        "parameters":  {
                           "ApplicationName":  {
                                                   "type":  "string",
                                                   "maxLength":  3,
                                                   "metadata":  {
                                                       "description": "my desc"
                                                   }
                                               },
                           "plan_name":  {
                                             "type":  "String"
                                         }
                       },
        "variables":  {
                          "resourceNames":  {
                                                "name":  "EDSENDGRID06",
                                                "commonResourceGroup":  "[tolower(concat(parameters(\u0027ApplicationName\u0027),\u0027-\u0027,parameters(\u0027Environ
    ment\u0027),\u0027-\u0027,parameters(\u0027shortlocation\u0027),\u0027-\u0027,parameters(\u0027tenant\u0027),\u0027-rgp-\u0027,\u002701\u0027))]"
                                            },
                          "TemplateURLs":  {
                                               "sendgrid":  "[concat(parameters(\u0027artifacts_baseUri\u0027),\u0027/ArmTemplates/master/Public/lib/linkedTemplates/se
    ndgrid.json\u0027)]"
                                           }
                      }
    }
    
  • #166552

    Participant
    Topics: 2
    Replies: 483
    Points: 1,151
    Helping Hand
    Rank: Community Hero

    Ah, if you wanted to keep existing properties, you'd need to do Select-Object -Property *, @{ < # rest of the thing I posted before #> }

You must be logged in to reply to this topic.