Fun With PowerShell Hash Tables

Introduction

Hash tables are powerful, flexible items. In some languages, hash tables are also called dictionaries. In this post we’ll start with a few basics, then get into some fun things you can do with hash tables.

A quick note, some documentation calls them a hash table, others read hashtable, one word. For this post I’ll use the two word hash table, but it’s the same thing no matter what documentation or blog you read.

For all of the examples, we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.1.3, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.

To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of an array variable (or any variable) by highlighting it and using F8/F5.

Hash Table Basics

To create a hash table you will need to use the @{} syntax to create a set of key / value pairs.

$hash = @{'Key'                 = 'Value'
          'PowerShell'          = 'PowerShell.com'
          'Arcane Code'         = 'arcanecode.com'
          'Pluralsight'         = 'pluralsight.com'
          'GitHub - ArcaneCode' = 'github.com/arcanecode'
         }
$hash                  # Display all values

Result:
Name                           Value
----                           -----
Arcane Code                    arcanecode.com
Key                            Value
Pluralsight                    pluralsight.com
PowerShell                     PowerShell.com
GitHub - ArcaneCode            github.com/arcanecode

In this example I lined up the equal signs because, in my humble opinion, it’s easier to read. But it’s not required.

Similar to an array, you can use positional notation to retrieve a value, only instead of a numeric value you pass in the key.

$hash['PowerShell']

Result:
PowerShell.com

The hash table manifests each key as a property. This means instead of positional notation you can instead use . (dot) notation.

$hash.PowerShell

Result:
PowerShell.com

But Arcane, you may ask, some of those keys have spaces in them. How does that work?

Well all you have to do is put the key in quotes.

$hash.'Arcane Code'

Result:
arcanecode.com

Well that was fun, but what about updating a value for a key? All you have to do is assign the new value.

$hash.'Arcane Code' = 'ArcaneCode.me'
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

As you can see the value for the 'Arcane Code' key has changed from arcanecode.com to arcanecode.me.

In addition to updating, you will have times you want to add a new item to an array. Doing so isn’t intuitive, but it’s easy. Just use the hash table, provide the new key and assign the value to it.

$hash.Ubuntu = 'Ubuntu.com'
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
Ubuntu                         Ubuntu.com
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

Fun Properties and Methods of Hash Tables

Hash tables have a variety of useful properties and methods you can call. The first, Keys, will return a list of all the keys.

$hash.Keys

Result:
GitHub - ArcaneCode
Key
PowerShell
Pluralsight
Arcane Code
Ubuntu

As you might guess, there’s a corresponding property to return all the values.

$hash.Values

Result:
github.com/arcanecode
Value
PowerShell.com
pluralsight.com
arcanecode.me
Ubuntu.com

Just like the array data type, hash tables also have a Count property to let you know how many key/value pairs are in the table.

$hash.Count

Result:
6

Earlier in this post I showed how to add a new key/value pair. Before adding, it would probably be a good idea to check and see if it is already there. There is a ContainsKey method that will do that.

$hash.ContainsKey('Arcane Code')

Result:
True

This method will return either True or False depending on the presence of the key.

Likewise, there is a method to check to see if a value is present.

$hash.ContainsValue('pluralsight.com')

Result:
True

What if we’d wanted to use ContainsKey to see if a key was present, and if so we wanted to remove it? There is a Remove method that will delete a key/value pair from our hash table.

$hash.Remove('Ubuntu')
$hash

Result:
Name                           Value
----                           -----
GitHub - ArcaneCode            github.com/arcanecode
Key                            Value
PowerShell                     PowerShell.com
Pluralsight                    pluralsight.com
Arcane Code                    arcanecode.me

As you can see in the results, the key / value pair for the Ubuntu entry is now gone.

The final method we’ll look at in this section will allow us to remove all key / value pairs from the hash table.

$hash.Clear()
$hash

Result:
(Nothing is displayed because the hash table is empty)

Creating an Empty Hash Table

Much as with arrays, there are times you will want to create an empty hash table. You could then enter a loop that added new key / value pairs to the hash table.

To declare an empty hash table, you simply assign @{} to a variable.

$empty = @{}

Now you can assign values to it. Here we’ll do it in individual lines, but as I indicated this technique is most useful in a loop.

$empty['Pluralsight'] = 'pluralsight.com'
$empty['DataFabricator'] = 'datafabricator.com'
$empty

Result:
Name                           Value
----                           -----
Pluralsight                    pluralsight.com
DataFabricator                 datafabricator.com

Ordered Hash Tables

Let’s reset our hash table, then look at the output.

$hash = @{'Key'                 = 'Value'
          'PowerShell'          = 'PowerShell.com'
          'Arcane Code'         = 'arcanecode.com'
          'Pluralsight'         = 'pluralsight.com'
          'GitHub - ArcaneCode' = 'github.com/arcanecode'
         }
$hash

Result:
Name                           Value
----                           -----
Arcane Code                    arcanecode.com
Key                            Value
Pluralsight                    pluralsight.com
PowerShell                     PowerShell.com
GitHub - ArcaneCode            github.com/arcanecode

Look at the output carefully. The returned list is not in the same order we added them to the hash table. Most of the time you are referencing the hash table via a specific key, so the ordering isn’t a concern.

What if you needed them to be returned in the same order they were added in? Fortunately PowerShell has an [ordered] instruction you can place before declaring the hash table.

$hash = [ordered]@{
  'Key'                 = 'Value'
  'PowerShell'          = 'PowerShell.com'
  'Arcane Code'         = 'arcanecode.com'
  'Pluralsight'         = 'pluralsight.com'
  'GitHub - ArcaneCode' = 'github.com/arcanecode'
}
$hash

Result:
Name                           Value
----                           -----
Key                            Value
PowerShell                     PowerShell.com
Arcane Code                    arcanecode.com
Pluralsight                    pluralsight.com
GitHub - ArcaneCode            github.com/arcanecode

As you can see, the results are returned in the exact same order they were added to the hash table. This example also demonstrates you can begin the list of key / value pairs on the next line after the single squiggly bracket {.

Iterating (Looping) Over a Hash Table

It is possible to loop over the contents of a hash table. But it isn’t quite as intuitive as it is with arrays. If you were to use foreach($item in $hash) you’d get an error, because PowerShell isn’t sure if you want to loop over the keys, values, or something else.

Instead, the hash table has a special method called GetEnumerator which will allow you to iterate over the table, returning one key / value pair each time through the loop.

foreach($item in $hash.GetEnumerator())
{
  "$($item.Name) has a value of $($item.Value)"
}

Result:
Key has a value of Value
PowerShell has a value of PowerShell.com
Arcane Code has a value of arcanecode.com
Pluralsight has a value of pluralsight.com
GitHub - ArcaneCode has a value of github.com/arcanecode

This is the way I prefer to iterate over a hash table. Just my personal opinion, but I think the code is cleaner and easier to read. That said, there is a second method you may like better.

In it you loop over the Key values, then reference the value from the hash table, using the key as the position. Do notice that instead of using the key[] notation, you have to reference the Item method then pass the key into it.

foreach($key in $hash.Keys)
{
  "$key value is $($hash.Item($key))"
}

Result:
Key value is Value
PowerShell value is PowerShell.com
Arcane Code value is arcanecode.com
Pluralsight value is pluralsight.com
GitHub - ArcaneCode value is github.com/arcanecode

As you can see, the result is the same either way. Use which ever method makes the most sense for you.

Splatting

Right now you are probably asking yourself “Splatting? Hey Arcane, are you trying to confuse us with silly names?”

Fear not, splatting is a real thing. First, let’s start with an example. Here, we are going to take the output of GetChildItem and pipe it to a cmdlet called Join-String. If you aren’t familiar with it, Join-String will take a list of objects and join them to a single string.

Get-ChildItem -Directory D:\ |
  Join-String -Property Name -Separator ', '

Result:
Backups_Temp, CamtasiaWorkspace, Hyper-V, ISOs, Mobile Report Publisher

With splatting, we create a hash table, Each key is the name of a parameter that needs to be passed in, and the value is what we want to use for that parameter.

$splat = @{Property = 'Name'
           Separator = ', '
          }

Here you can see the Property and Separator parameter names were passed in as keys, and the values are what we want to pass in.

Now we can call our cmdlet, passing in the name of our hash table. Only, and this is important, instead of a $ we use an @ at the front of the name of our hash table.

Get-ChildItem -Directory D:\ | Join-String @splat

Result:
Backups_Temp, CamtasiaWorkspace, Hyper-V, ISOs, Mobile Report Publisher

Whenever PowerShell sees a @ in front of a name that corresponds to a hash table, it understand you are using a splat and expands each key / value pair into parameters. As you can see, it shortens the call to Join-String significantly.

What if we want to change the value of one of our parameters? That’s easy, we just assign a new value. The rest of the hash table remains the same.

$splat.Separator = ' - '
Get-ChildItem -Directory D:\ | Join-String @splat

Result:
"Backups_Temp" - "CamtasiaWorkspace" - "Hyper-V" - "ISOs" - "Mobile Report Publisher"

All of the parameters don’t have to be included in the splat. For example, Join-String has a switch that, when included, will wrap each item in single quotes.

$splat = @{Property = 'Name'
           Separator = ', '
          }

Get-ChildItem -Directory D:\ |
  Join-String @splat -SingleQuote

Result:
'Backups_Temp', 'CamtasiaWorkspace', 'Hyper-V', 'ISOs', 'Mobile Report Publisher'

Here I used a switch, but it could be another parameter with a value added after the splat.

What if you wanted to include the switch in the hash table though? Switches don’t have a value that is passed in.

That turns out to be a simple answer, just include the switch as a key, and for the value use either $True or $False.

$splat = @{Property = 'Name'
           Separator = ', '
           SingleQuote = $True
          }
Get-ChildItem -Directory D:\ | Join-String @splat

Result:
'Backups_Temp', 'CamtasiaWorkspace', 'Hyper-V', 'ISOs', 'Mobile Report Publisher'

You could also include the switch in the splat, but set the value to $False if you didn’t want to use single quoted every time.

While this example only had a few parameters, I’ve worked with some cmdlets that had a dozen or more parameters that were required to pass in. SQL Server’s cmdlets come to mind.

I often had scripts that had a dozen parameters, but the only one that changed with each call was the actual SQL command I was sending to the server. Using a splat let me reduce the amount of code significantly.

Conclusion

In this post, we saw a lot of fun things you can do with hash tables. A few were creating, updating, adding and removing values. We also covered iterating over a hash table, and even the very useful concept of splatting.

Now you can use these features in your own scripts where a hash table comes into play.

The demos in this course came from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.

If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight. At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.

Leave a comment