Back to basics: Hashtables

One of the most usefull features in PowerShell are arrays, i already talked about them in a previous post. Today i’ll write about their sister: Hashtables.

Hashtables are really awesome for your daily scripting work, in many scripts they are at the center becauseyou can access item not  only with the index, but by whatever label you want. Imagine building your parameters in only one object and pushing it to the cmdlet, its fucking more readable and practical for you. A friend of mine, Carlo, calls it “Splatting“. Also, you can also use hashtables formatting your fields and output them with Format-T*. We’ll see more examples at the end of this post.

It’s kinda easy to use, to let’s start quickly.

How to create a Hashtable ?

Like always in PowerShell you will have many ways to create your hashtable. The first is to use @{}.

# The easiest way
$MyHash = @{Test=1,5;"Test 2"="This is not a test"}
PS F:\PowerShell> $MyHash = @{Test=1,5;"Test 2"="This is not a test"}
PS F:\PowerShell> $MyHash

Name                           Value
----                           -----
Test                           {1, 5}
Test 2                         This is not a test

Look the created object  and available methods.

PS F:\PowerShell> $MyHash | Get-Member


   TypeName : System.Collections.Hashtable

Name              MemberType            Definition
----              ----------            ----------
Add               Method                void Add(System.Object key, System.Object value), void IDictionary.Add(Syste...
Clear             Method                void Clear(), void IDictionary.Clear()
Clone             Method                System.Object Clone(), System.Object ICloneable.Clone()
Contains          Method                bool Contains(System.Object key), bool IDictionary.Contains(System.Object key)
ContainsKey       Method                bool ContainsKey(System.Object key)
ContainsValue     Method                bool ContainsValue(System.Object value)
CopyTo            Method                void CopyTo(array array, int arrayIndex), void ICollection.CopyTo(array arra...
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator(), System.Collections...
GetHashCode       Method                int GetHashCode()
GetObjectData     Method                void GetObjectData(System.Runtime.Serialization.SerializationInfo info, Syst...
GetType           Method                type GetType()
OnDeserialization Method                void OnDeserialization(System.Object sender), void IDeserializationCallback....
Remove            Method                void Remove(System.Object key), void IDictionary.Remove(System.Object key)
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;}

We can access methods like theses in arrays (Add, Clone, Remove). But there is more, we’ll take a look later in this article.

If you like the path to complexity (or at least write more code)…

PS F:\PowerShell> $NewHash = New-Object System.Collections.Hashtable
PS F:\PowerShell> $NewHash | Get-Member | select typename -Unique

TypeName
--------
System.Collections.Hashtable

Either you use this or the previous one, unlike arrays, you will have an unique Object type to work with.

Add rows to hashtables

Alright now we have a hashtable, let’s see how adding labels/values.

PS F:\PowerShell> $MyHash["Test 3"] = 42
PS F:\PowerShell> $MyHash

Name                           Value
----                           -----
Test 2                         This is not a test
Test 3                         42
Test                           {1, 5}

This way is good when you have multiple words in your label, another way to add a row, is this one

PS F:\PowerShell> $MyHash.Addsomevalue = 1664
PS F:\PowerShell> $MyHash

Name                           Value
----                           -----
Addsomevalue                   1664
Test 2                         This is not a test
Test 3                         42
Test                           {1, 5}

As rows are always composed with a label and the associated value, if we want to use the Add method this is what to do.

PS F:\PowerShell> $MyHash.Add("TestAdd","CantWaitNewStarWars")
PS F:\PowerShell> $MyHash

Name                           Value
----                           -----
Addsomevalue                   1664
Test 2                         This is not a test
Test 3                         42
TestAdd                        CantWaitNewStarWars
Test                           {1, 5}

 Remove rows in hashtables

We’ll use the remove method

PS F:\PowerShell> $MyHash.Remove("Test")
PS F:\PowerShell> $MyHash

Name                           Value                                                                                                               
----                           -----                                                                                                               
Addsomevalue                   1664                                                                                                                
Test 2                         This is not a test                                                                                                  
Test 3                         42                                                                                                                  
TestAdd                        CantWaitNewStarWars

Kinda easy isn’t it ? 🙂

Sort a hashtable

One thing to know about hashtables is their not ordered by default, it means if you wan a real order you have to use some tips !

The first possibility is to create your hashtable using [ordered] which will garanty the order supplied in the definition of your hashtable.

# Not ordered
$HashNotOrdered = @{Test="blah blah";"Test 2"="This is not a test";Test3=1}
$HashNotOrdered

# Ordered
$MyHashOrdered = [ordered]@{Test="blah blah";"Test 2"="This is not a test";Test3=1}
$MyHashOrdered
Name                           Value                                                                                                               
----                           -----                                                                                                               
Test3                          1                                                                                                                   
Test 2                         This is not a test                                                                                                  
Test                           blah blah                                                                                                           
Test                           blah blah                                                                                                           
Test 2                         This is not a test                                                                                                  
Test3                          1

Another method is to access elements, with the GetEnumerator method.

PS F:\PowerShell> $Hash = @{Test="blah blah";"Test 2"="This is not a test";Test3=1}
PS F:\PowerShell> $Hash.GetEnumerator() | Get-member


   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;}

The cool thing with this method as you see, is that you can sort your hashtable by name or by value,

PS F:\PowerShell> # Hash sorted by name
PS F:\PowerShell> $Hash = @{Test="blah blah";"Test 2"="This is not a test";Test3=1}
PS F:\PowerShell> $Hash.GetEnumerator() | Sort-Object Name
Name                           Value                                                                                                               
----                           -----                                                                                                               
Test                           blah blah                                                                                                           
Test 2                         This is not a test                                                                                                  
Test3                          1

And Hash sorted by value

PS F:\PowerShell> # Hash
PS F:\PowerShell> $Hash = @{Test="blah blah";"Test 2"="This is not a test";Test3=1}
PS F:\PowerShell> $Hash.GetEnumerator() | Sort-Object Value
Name                           Value                                                                                                               
----                           -----                                                                                                               
Test3                          1                                                                                                                   
Test                           blah blah                                                                                                           
Test 2                         This is not a test

 Playing with hashtables

Cmdlet parameters

You can compose arguments with a hashtable and call the variable with @variablename

PS F:\PowerShell> $params = @{Name="Notepad";whatif=$true}
PS F:\PowerShell> Stop-Process @params
WhatIf : Opération « Stop-Process » en cours sur la cible « notepad (2856) ».
WhatIf : Opération « Stop-Process » en cours sur la cible « notepad (3360) ».

All cmdlets accept splatting, so enjoy yourself. Another example building an object only with a hashtable.

PS F:\PowerShell> [psobject]$object = @{Name="PowerShell";
                      Arg="Really is awesome"}
PS F:\PowerShell> $object

Name                           Value                                                                                                               
----                           -----                                                                                                               
Arg                            Really is awesome                                                                                                   
Name                           PowerShell

All right, this is all for today, hope you find this usefull ! If you have any question, or if i made mistakes or forget something on technical facets of hashtables, please feel free to comment this article.

If you want to go further with hashtables and you do some advanced scripting, take a look at PSBoundParameters to play a little more 🙂