Weekend Scripter: Sorting PowerShell Hash Tables

Doctor Scripto

Summary: Microsoft Scripting Guy, Ed Wilson, talks about sorting hash tables. Microsoft Scripting Guy, Ed Wilson, is here. Today is part of the Scripting Wife’s birthday weekend, and so we are heading out to see the Friesian horse keuring. She has watched the event via live streaming on the Internet, but never attended one in person…so off we go. This means I am up a bit early, sipping extra strong English Breakfast tea, and munching on a kiwi. I do not have enough time to make my usual bowl of Irish steel-cut oats this morning. While I wait for my tea to steep, I thought I would answer a question that I have received several times over the last few days, “How do I sort a hash table in Windows PowerShell?”

Dude, what’s the problem?

Suppose I create a hash table and store it in a variable called $a. Here is such a hash table:

$a = @{a=1;b=2;c=3;d=4} When I display the contents of the $a variable, I expect to see something like the following:

A 1

B 2

C 3 But unfortunately, this is not the case. Here is what actually happens:

PS C:> $a  

Name                           Value

—-                           —–

c                              3

d                              4

b                              2

a                              1 As you can see, they are not in order. Hey, no problem. All I need to do is to pipe the hash table to the Sort-Object cmdlet, and all should be groovy. So I do the following:

PS C:> $a | Sort-Object  

Name                           Value

—-                           —–

c                              3

d                              4

b                              2

a                              1 Bummer, that didn’t work. Maybe, I need to sort in a descending fashion. So I try the following:

PS C:> $a | Sort-Object -Descending  

Name                           Value

—-                           —–

c                              3

d                              4

b                              2

a                              1 Dude, it still didn’t work. Maybe I need to specify that I want to sort on the Name property. So I do this:

PS C:> $a | Sort-Object -Property name -Descending  

Name                           Value

—-                           —–

c                              3

d                              4

b                              2

a                              1 Nope, that didn’t work either. Maybe it is a bug?

So what is the problem?

I decide to use the Get-Member cmdlet to see if I can figure out what is happening. I take my last effort, add a pipeline character, and send the results to Get-Member. Here is what I get:

PS C:> $a | Sort-Object -Property name -Descending | gm  

   TypeName: System.Collections.Hash table  

Name              MemberType            Definition

—-              ———-            ———-

Add               Method                void Add(System.Object key, System.Object valu…

Clear             Method                void Clear(), void IDictionary.Clear()

Clone             Method                System.Object Clone(), System.Object ICloneabl…

Contains          Method                bool Contains(System.Object key), bool IDictio…

ContainsKey       Method                bool ContainsKey(System.Object key)

ContainsValue     Method                bool ContainsValue(System.Object value)

CopyTo            Method                void CopyTo(array array, int arrayIndex), void…

Equals            Method                bool Equals(System.Object obj)

GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEn…

GetHashCode       Method                int GetHashCode()

GetObjectData     Method                void GetObjectData(System.Runtime.Serializatio…

GetType           Method                type GetType()

OnDeserialization Method                void OnDeserialization(System.Object sender), …

Remove            Method                void Remove(System.Object key), void IDictiona…

ToString          Method                string ToString()

Item              ParameterizedProperty System.Object Item(System.Object key) {get;set;}

Count             Property              int Count {get;}

IsFixedSize       Property              bool IsFixedSize {get;}

IsReadOnly        Property              bool IsReadOnly {get;}

IsSynchronized    Property              bool IsSynchronized {get;}

Keys              Property              System.Collections.ICollection Keys {get;}

SyncRoot          Property              System.Object SyncRoot {get;}

Values            Property              System.Collections.ICollection Values {get;} I can see that I have a hash table object. Remember that Windows PowerShell pipelines objects. So what is happening is that Sort-Object is receive one big, fat, juicy hash table object, and there is nothing for it to sort.

The fix

What I need to do is to figure out a way to break down the big hash table object into individual entries. Then Sort-Object can sort by name or by value—whatever I specify. To do this, I use the GetEnumerator() method from the hash table object. This will basically permit my Sort-Object cmdlet to see the individual entries. Here is what I come up with:

PS C:> $a.GetEnumerator() | sort -Property name  

Name                           Value

—-                           —–

a                              1

b                              2

c                              3

d                              4 Yea! It worked. What do I have now that Sort-Object is working with? I use Get-Member, and I can see that I now have DictionaryEntry objects. Here is the command:

PS C:> $a.GetEnumerator() | sort -Property name | gm  

   TypeName: System.Collections.DictionaryEntry  

Name        MemberType    Definition

—-        ———-    ———-

Name        AliasProperty Name = Key

Equals      Method        bool Equals(System.Object obj)

GetHashCode Method        int GetHashCode()

GetType     Method        type GetType()

ToString    Method        string ToString()

Key         Property      System.Object Key {get;set;}

Value       Property      System.Object Value {get;set;} That is all there is to sorting hash tables. Looks like the Scripting Wife is ready to head out to the keuring. Have a great day, and I will talk to you tomorrow. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. Ed Wilson, Microsoft Scripting Guy 


Discussion is closed.

Feedback usabilla icon