I am new to PowerShell, learning it on the fly coming from Python background.
I am pulling data from another tool where the data is retrieved through a REST call.
METERS variable is stored in this format in the source.
{
"500 HR": 500,
"1000 HR": 1000,
"2000 HR": 2000
}
PowerShell code
#REST call to source
$meter=@{}
Foreach ($item in $origresult.Items) {
$result = (Invoke-RestMethod -Uri $url -Headers $headers -Method GET -ContentType application/json -ErrorVariable RespErr)
$meter.Add($item.Name,$result.Value)
}
Write-Host ($meter | Out-String) -ForegroundColor Red
This is the Output
Name Value
---- -----
LastUploaded 2020-12-29T06:38:02
IsEnabled 1
METERS {...
ORGID WHS
How do I retrieve METERS and traverse through the dictionary? I tried this so far. Python spoiled me with its simple data structures, PowerShell is not so straightforward unless there is a simpler way to do this.
$mymeters = $meter.METERS | ConvertFrom-Json
Write-Host ($mymeters | Out-String) -ForegroundColor Yellow
Output
500 HR : 500
1000 HR : 1000
2000 HR : 2000
Here are somethings I have tried so far -
$mymeters = [ordered]@{}
" Here is the item $mymeters.Get_Item(500 HR)" #my silly attempt!
# Looping is a no go either - it says specialized ordered dictionary
foreach ($ind in $mymeters) {
" --> $ind"
}
Output
Here is the item System.Collections.Specialized.OrderedDictionary.Get_Item(500 HR)
--> System.Collections.Specialized.OrderedDictionary
I might be missing something real basic but I am unable to figure it out on my own! Any help is really appreciated. All I want is to traverse on the METERS hashtable/dictionary and call a function.
Before getting into the meat of it, let's review a few PowerShell syntax basics and see if we can re-use some of your Pythonic intuition :)
Just like in Python, you can reference the properties of an object by name using the .
member access operator - for non-contiguous names, use quotes:
$mymeters = $meter.METERS | ConvertFrom-Json
$mymeters.'500 HR' # evaluates to `500`
String literals in PowerShell comes in two distinct flavours:
'Hello World!'
)
''
(literal single-quote)"Hello World!"
)
$variable
tokens and $()
subexpressions will occur unless explicitly escaped - `
is the escape character, and common sequences you'd expect in most C-like languages (`n
, `t
, `r
, etc.) are natively recognized.Arbitrary expressions (like $dictionary.get_Item('some key')
) will not be evaluated as-is, however.
To get around that, we can either use the -f
string format operator:
$mymeters = [ordered]@{}
"Here is item '500 HR': {0}" -f $mymeters['500 HR']
-f
should feel familiar if your used to Python3's f
strings, but with a caveat - PowerShell's -f
operator is a thin wrapper around String.Format()
, and String.Format()
only supports 0-based placeholders - '{0} {1}' -f 1,2
is valid but '{} {}' -f 1,2
is not.
Another option is to wrap the expression in a $()
sub-expression operator inside a double-quoted string literal:
$mymeters = [ordered]@{}
"Here is item '500 HR': $($mymeters['500 HR'])"
Take note that dictionaries in PowerShell supports keyed index access with []
- just like Python :)
Not unlike Python, PowerShell (and .NET in general) has powerful introspection capabilities as well.
Dynamically discovering and iterating the properties of any object is as simple as referencing a special member named psobject
:
foreach($propertyMetadataEntry in $someObject.psobject.Properties){
"Property: {0,-20} = {1}" -f $propertyMetadataEntry.Name,$propertyMetadataEntry.Value
}
Or in your case:
$mymeters = $meter.METERS | ConvertFrom-Json
foreach($meterReading in $mymeters.psobject.Properties){
"Meter: {0,-20} = {1}" -f $meterReading.Name,$meterReading.Value
# do whatever else you please with $meterReading here :)
}
This will work for any scalar object (like the object returned by ConvertFrom-Json
or Invoke-RestMethod
).
For iterating over the entries in a dictionary, you need to explicitly call .GetEnumerator()
:
$dictionary = [ordered]@{ A = 1; B = 2; C =3 }
foreach($keyValuePair in $dictionary.GetEnumerator()){
"Dictionary Entry: {0} = {1}" -f $keyValuePair.Key,$keyValuePair.Value
}