Now let me show you a few other tricks here with hash tables.
Let me create an array, $j, and just give it a single
entry of name with the value of foo.
Now,
later on, I decide, you know what, I want to add another
entry called name with the value of bar,
maybe not realizing what I have already done. And PowerShell
will complain because a hash table key has to be unique, and I
already have an entry for name.
One thing you can do is to test if the hash table already
contains that key, and you can do that with a method of the
hash table. So I pipe $j to Get‑Member.
I know there are methods that have contains in the name.
There's Contains, ContainsKey, which basically do the
same thing, and then ContainsValue.
These will give you a boolean result,
basically true or false, if the key exists or if the value already exists in
the hash table. So I can do $j.ContainsKey('name'), and sure enough, it does,
and I'll get the same result if I use Contains.
So here's how we might use this in a more practical
perspective. I'm going to run Get‑Process. And for every
process object that comes through the pipeline,
I'm going to do something. Now before I do something,
I'm going to initialize an empty hash table,
$p.
Now as every object comes through the pipeline,
I'm first going to test, hey,
does $p already contain an entry using the name of the process as the key?
If it does,
then I'm going to update the value with the working
set value of the current process.
I'm using the += sign to increment and update the value.
So the hash table will have a key for the process name, and the value will be
the sum of the working set value of the process object.
Otherwise, if $p does not contain the name of the process,
then I will just go ahead and add it to the hash table and then add
the current working set to my starting point.
So when I run this, $p now has this information. I have the
process name and then the working set size.
So using that contains method allowed me to nicely and
easily update the hash table as I needed to.
Now here's, though, another place where something may trip you up.
I then decide, you know what, I want to sort that
output on the name of the process.
So we try something like that, and we go, hey, that did not work.
This is where things like Get‑Member become very important.
If I take $p and pipe it to Get‑Member, you can see that PowerShell is getting
a System.Collection.Hashtable object from $p. It's not a process object, and
it's not the entry for the process object, so it doesn't know about that name
property. We can see it's not listed there. Instead, what you need to do is do
something called GetEnumerator.
So I'm going to take GetEnumerator.
This is a method on the hash table.
If I pipe this to Get‑Member to show you, you can see
now this is a different object type,
a System.Collections.DictionaryEntry. And look at the properties, Key and Value.
And I believe starting in PowerShell 7, they added an
AliasProperty of Name for the Key.
Now what you need to do is this, so I take $p GetEnumerator. I can
still use my Sort‑Object, but the property that I want is Name or Key
if I want to use the actual value. Here,
I'm just using the AliasProperty.
Now I get the results that I expect, and it sorts the way that I expect
because I'm using the proper property name now that I know what type of
object PowerShell is getting in the pipeline.
I can do $p GetEnumerator and filter and say, hey, get me all the
ones where the value is greater than 250 megabytes. And see, I've got
one entry listed there. So knowing how to use GetEnumerator is
important. If you are using a hash table and you're not getting the
results you are expecting, it may be because you need to use this GetEnumerator method.