Reference a hashtable that is an object in a Powershell variable

78 views Asked by At

I'm using az vm list-skus -l australiasoutheast | convertfrom-json to populate a variable (lets call it $skus) so I can use it in a PS script. When $skus is populated, it's contents look like:

apiVersions  :
capabilities : {@{name=MaxResourceVolumeMB; value=256000}, @{name=OSVhdSizeMB; value=1047552}, @{name=vCPUs; value=8}, @{name=MemoryPreservingMaintenanceSupported; value=False}…}
capacity     :
costs        :
family       : standardMSFamily
kind         :
locationInfo : {@{location=australiasoutheast; zoneDetails=System.Object[]; zones=System.Object[]}}
locations    : {australiasoutheast}
name         : Standard_M8-4ms
resourceType : virtualMachines
restrictions : {}
size         : M8-4ms
tier         : Standard

The capabilities and locatioinfo objects in the variable look like hashtables.

I can do $skus | select name, capabilities which outputs:

name                   capabilities
----                   ------------
Aligned                {@{name=MaximumPlatformFaultDomainCount; value=2}}
Classic                {@{name=MaximumPlatformFaultDomainCount; value=3}}
Premium_LRS            {@{name=MaxSizeGiB; value=4}, @{name=MinSizeGiB; value=0}, @{name=MaxIOps; value=120}, @{name=MinIOps; value=120}…}
Premium_LRS            {@{name=MaxSizeGiB; value=128}, @{name=MinSizeGiB; value=64}, @{name=MaxIOps; value=500}, @{name=MinIOps; value=500}…}
Premium_LRS            {@{name=MaxSizeGiB; value=256}, @{name=MinSizeGiB; value=128}, @{name=MaxIOps; value=1100}, @{name=MinIOps; value=1100}…}

How can I get to and extract the data I need from those hashtables?

I tried the usual select-object to try and get to it, but I can only get as far as the capabilities object, but I cannot reference anything inside that.

3

There are 3 answers

1
Venkat V On BEST ANSWER

How can I get to and extract the data I need from those hashtables?

To retrieve all capabilities from a hash table, use Select-Object to print the specific value from the capabilities parameter.

Here is the PowerShell script to reference the value from capabilities parameter.

$skus = az vm list-skus -l australiasoutheast | convertfrom-json
$skus | Where-Object { $_.Capabilities -ne $null } | ForEach-Object {
    $matchingCapability = $_.Capabilities | Where-Object { $_.Name -eq "OSVhdSizeMB" -and $_.Value -eq 1047552 }
    if ($matchingCapability -ne $null) {
        $_ | Select-Object Name, @{ Name = "Capabilities"; Expression = { $matchingCapability } }
    }
}

Output:

enter image description here

To display all values within capabilities, you can utilize the following cmdlet to print only name and values.

  $skus | Select-Object Name, @{ Name = "Capabilities"; Expression = { $_.Capabilities | ForEach-Object { $_.Name + ": " + $_.Value } } }

Output:

enter image description here

0
iRon On

Without knowing the exact structure and data of the object-graph, it is difficult to give you a specific answer (see also how to ask and providing a mvce) but based on this example (note that in here Value is actually the top node) and this Object-Graph tools set, I can give you a general view and answer:

{
  "value": [
{
  "resourceType": "virtualMachines",
  "locations": [
    "westus"
  ],
  "capabilities": [
    {
      "name": "MaxResourceVolumeMB",
      "value": "20480"
    },
    {
      "name": "OSVhdSizeMB",
      "value": "1047552"
    },
    {
      "name": "vCPUs",
      "value": "1"
    },
    {
      "name": "HyperVGenerations",
      "value": "V1"
    },
    {
      "name": "MemoryGB",
      "value": "0.75"
    },
    {
      "name": "MaxDataDiskCount",
      "value": "1"
    },
    {
      "name": "LowPriorityCapable",
      "value": "False"
    },
    {
      "name": "PremiumIO",
      "value": "False"
    },
    {
      "name": "vCPUsAvailable",
      "value": "1"
    },
    {
      "name": "ACUs",
      "value": "50"
    },
    {
      "name": "vCPUsPerCore",
      "value": "1"
    },
    {
      "name": "EphemeralOSDiskSupported",
      "value": "False"
    },
    {
      "name": "AcceleratedNetworkingEnabled",
      "value": "False"
    },
    {
      "name": "RdmaEnabled",
      "value": "False"
    },
    {
      "name": "MaxNetworkInterfaces",
      "value": "2"
    }
  ],
  "locationInfo": [
    {
      "location": "westus",
      "zones": [
        "2",
        "1"
      ],
      "zoneDetails": [
        {
          "name": [
            "2"
          ],
          "capabilities": [
            {
              "name": "UltraSSDAvailable",
              "value": "True"
            }
          ]
        }
      ]
    }
  ],
  "name": "Standard_A0",
  "tier": "Standard",
  "size": "A0",
  "family": "standardA0_A7Family"
},
{
  "resourceType": "virtualMachines",
  "locations": [
    "westus"
  ],
  "capabilities": [
    {
      "name": "MaxResourceVolumeMB",
      "value": "71680"
    },
    {
      "name": "OSVhdSizeMB",
      "value": "1047552"
    },
    {
      "name": "vCPUs",
      "value": "1"
    },
    {
      "name": "HyperVGenerations",
      "value": "V1"
    },
    {
      "name": "MemoryGB",
      "value": "1.75"
    },
    {
      "name": "MaxDataDiskCount",
      "value": "2"
    },
    {
      "name": "LowPriorityCapable",
      "value": "True"
    },
    {
      "name": "PremiumIO",
      "value": "False"
    },
    {
      "name": "vCPUsAvailable",
      "value": "1"
    },
    {
      "name": "ACUs",
      "value": "100"
    },
    {
      "name": "vCPUsPerCore",
      "value": "1"
    },
    {
      "name": "EphemeralOSDiskSupported",
      "value": "False"
    },
    {
      "name": "AcceleratedNetworkingEnabled",
      "value": "False"
    },
    {
      "name": "RdmaEnabled",
      "value": "False"
    },
    {
      "name": "MaxNetworkInterfaces",
      "value": "2"
    }
  ],
  "locationInfo": [
    {
      "location": "westus",
      "zones": [
        "1",
        "2",
        "3"
      ]
    }
  ],
  "name": "Standard_A1",
  "tier": "Standard",
  "size": "A1",
  "family": "standardA0_A7Family"
}
  ],
  "nextLink": null
}

# $Json = '<paste the above json snippet>'
$Skus = ConvertFrom-Json $Json

What is the path (reference) to each (leaf) node in this graph-object?

Install-Module -Name ObjectGraphTools
$Skus | Get-ChildNode -Recurse -Leaf

Path                                                          Name         Depth Value
----                                                          ----         ----- -----
value[0].resourceType                                         resourceType     3 virtualMachines
value[0].locations[0]                                         0                4 westus
value[0].capabilities[0].name                                 name             5 MaxResourceVolumeMB
value[0].capabilities[0].value                                value            5 20480
value[0].capabilities[1].name                                 name             5 OSVhdSizeMB
value[0].capabilities[1].value                                value            5 1047552
value[0].capabilities[2].name                                 name             5 vCPUs
value[0].capabilities[2].value                                value            5 1
...

Each path that is listed above might be used the get to the specific node in the object-graph, e.g.:

$Skus.value[0].capabilities[0].name

returns:

MaxResourceVolumeMB

As you probably want to do this programmatically (dynamically) you could consider to use the Invoke-Expression command to get to the value of this property:

$Path = 'value[0].capabilities[0].name'
Invoke-Expression "`$Skus.$Path"
MaxResourceVolumeMB

But as mentioned in this helpful related answer from mklement0:

for security reasons, Invoke-Expression (iex) is otherwise best avoided.

So, you might also consider to use the object-graph tools to safely get to the specific node:

$Path = 'value[0].capabilities[0].name'
$Skus | Get-Node $Path

This will give you a node (PSNode class) in return:

Path                          Name Depth Value
----                          ---- ----- -----
value[0].capabilities[0].name name     5 MaxResourceVolumeMB

Or for a differed, more advanced Extended Dot-Notation (Xdn) example:

$Skus | Get-Node value.name=Standard_A0..~Name=vCPUs..Value

Path                           Name  Depth Value
----                           ----  ----- -----
value[0].capabilities[2].value value     5 1

To get to the Value contained by the node:

$Node = $Skus | Get-Node $Path
$Node.Value
MaxResourceVolumeMB

The node value refers to the same value as you original object-graph. Meaning, you might simply change the value like this:

$Node.Value = 'Updated Value"

To confirm this, check your original $Skus object:

$Skus | ConvertTo-Json # or: $Node.RootNode.Value | ConvertTo-Json
0
meatpack On

I've solved it by following advice from the 2nd post, specifically, this line:

$skus | Select-Object Name, @{ Name = "Capabilities"; Expression = { $_.Capabilities | ForEach-Object { $_.Name + ": " + $_.Value } } }

First, I did an SKU dump:

$skus = az vm list-skus -l australiasoutheast | convertfrom-json

Then a quick output of the capabilities to a CSV:

$skus | Select-Object Name, @{ Name = "Capabilities"; Expression = { $_.Capabilities | ForEach-Object { $_.Name + ": " + $_.Value } } } | export-csv .\cap.csv -Force

Now I can see all of the capabilities, so I can pick and choose what I want extracted by modifying the original command:

$capabilities = $skus | Select-Object Name, @{ Name = "vCPUs"; Expression = { $_.Capabilities | Where {$_.Name -eq "vCPUs"} | ForEach-Object { $_.Value } } }, @{ Name = "MemoryGB"; Expression = { $_.Capabilities | Where {$_.Name -eq "MemoryGB"} | ForEach-Object { $_.Value } } }

Which then lets me do what I please using:

$capabilities

name                   vCPUs MemoryGB
----                   ----- --------
Standard_M416-208ms_v2 416   11400
Standard_M416-208s_v2  416   5700
Standard_M416ms_v2     416   11400
Standard_M416s_8_v2    416   7600
Standard_M64           64    1024
Standard_M64-16ms      64    1792
Standard_M64-32ms      64    1792
Standard_M64dms_v2     64    1792
Standard_M64ds_v2      64    1024
Standard_M64ls         64    512
Standard_M64m          64    1792
Standard_M64ms         64    1792
Standard_M64ms_v2      64    1792
Standard_M64s          64    1024
Standard_M64s_v2       64    1024
Standard_M8-2ms        8     218.75
Standard_M8-4ms        8     218.75
Standard_M8ms          8     218.75