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.