2

I have a powershell question, I need to convert this piece of code to Json

$Dimensions = @(
    @{
        name  = 'num_vm'
        value = '100'
    },
    @{
        name  = 'days'
        value = '10'
    },
    @{
        name  = 'months'
        value = '12'
    }
)

For ($i=0;$i -lt $Dimensions.length;$i++)
{
 $bodymessage = @{'resourceId' = $resourceUsageId; 'quantity' = "$Dimensions[$i].value"; 'dimension' = "$Dimensions[$i].name"; 'effectiveStartTime' = $lastHourMinusFiveMinutes; 'planId' = 'plan_meter' }
    $body += @{
          request = 
            @($bodymessage)} `
              |ConvertTo-Json -Depth 5
  
                       
   

}

$body

what I'm hoping, is it can dynamically create the JSON output according to the dimension input, but the result I got is this

{
    "request":  [
                    {
                        "resourceId":  null,
                        "quantity":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[0].value",
                        "planId":  "plan_meter",
                        "dimension":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[0].name",
                        "effectiveStartTime":  null
                    }
                ]
}{
    "request":  [
                    {
                        "resourceId":  null,
                        "quantity":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[1].value",
                        "planId":  "plan_meter",
                        "dimension":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[1].name",
                        "effectiveStartTime":  null
                    }
                ]
}{
    "request":  [
                    {
                        "resourceId":  null,
                        "quantity":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[2].value",
                        "planId":  "plan_meter",
                        "dimension":  "System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[2].name",
                        "effectiveStartTime":  null
                    }
                ]
}

how can i get rid of System.Collections.Hashtable System.Collections.Hashtable System.Collections.Hashtable[0].value? and displaying with real value?

Roger Chen
  • 233
  • 3
  • 15
  • 3
    Remove the quotes around `"$Dimensions[$i].value"` and `"$Dimensions[$i].name"`. Also adding to an array with `+=` is wasteful as the entire array needs to be recreated in memory each time. Remove `$body += ` and instead capture with `$body = for ($i=0; $i -lt $Dimensions.Count; $i++) {..}` – Theo Aug 30 '21 at 13:25
  • To add to Theo's helpful comment and Bender the Greatest's helpful answer: As for how `"$Dimensions[$i].value"` is expanded (interpolated): [this answer](https://stackoverflow.com/a/40445998/45375) explains the rules of interpolation in PowerShell's _expandable strings_. – mklement0 Aug 30 '21 at 14:33

1 Answers1

2

The main issue is how you're assigning the hashtable element values within a string. Fix it by removing the quotes like so (formatted multiline for readability):

$bodymessage = @{
  resourceId = $resourceUsageId;
  quantity = $Dimensions[$i].value; # Removed the quotes here
  dimension = $Dimensions[$i].name; # Removed the quotes here
  effectiveStartTime = $lastHourMinusFiveMinutes;
  planId = 'plan_meter';
}

Note: I've also removed the single-quotes ' around the key names since they are not needed in this context. You only need to quote key names if non-alphanumeric characters are part of the key name, and you are assigning the key name as a literal string.


Why did this happen?

This happens because of how variable expansion within strings works. The following string you originally had:

"$Dimensions[$i].value"

will see $Dimensions get expanded (its ToString() function is implicitly called), not $Dimensions[$i].value. This is because variable parsing starts at the dollar-sign $ and stops at the first character which can't normally be part of a variable name. This will be most special characters, excepting the colon :.


However, if you are trying to force a string value (and you may not be), you can perform a sub-expression within the string to evaluate the members of an object, including array-accessors and object properties. You can also perform more complex expressions as well, but for your case below you could leave the quotes and use $() to get the result you want:

"$($Dimensions[$i].value)"

The $() tells the parser to "run this expression and put the result into the string". Again, whatever object is returned will implicitly have ToString() run on it when it gets inserted into the final string, so whatever output $Dimensions[$i].value.ToString() produces will be your string value.

codewario
  • 19,553
  • 20
  • 90
  • 159