How-to: Use Hash Tables in PowerShell

Hash Tables (also known as Associative arrays or Dictionaries) are a type of array that allows the storage of paired Keys and Values, rather like a simple database table.

Unlike normal arrays where you refer to each element via a numeric index, the keys of a hash table can be strings. The Key values do still need to be unique, if you try to add the same key twice PowerShell will return an error ("item has already been added").

The built-in properties of a hash table include .Keys .Values and .Count

Create a Hash Table

Create an empty Hash Table, be aware that if a hash table with that name already exists this will re-initialise it, removing any stored values.

$Hash_array_name = @{}

Create a Hash table and immediately populate it with some values:

$array_name = @{key1 = item1; key2 = item2;...}

Note that unlike Arrays which use normal () parentheses, a Hash table must be created using curly brackets { }
A useful mnemonic to remember this is to think of the H in Hash with it's horizontal bar }H{ and compare with the bracket {H}

Example:

$usa_states = @{
   CA = "California"
   NY = "New York"
  "IL" = "Illinois"
  "NH" = "New Hampshire"
}

Notice that placing quotes around the key is optional (unless the key contains spaces).
Each key/value pair must either be placed on a separate line or separated with a semicolon delimiter.

$usa_states = @{ CA = "California" ; NY = "New York" ; "IL" = "Illinois" ; "NH" = "New Hampshire" }

Add items to a Hash Table

This is done using the .Add() method, this will not overwrite an existing entry.

$usa_states.Add("GA", "Georgia")

You can add new items to either an empty hash table or one thats already been pre-populated with some values.

The key (in this case 'GA') has to be unique.

Edit items in a Hash Table

This is done using the .Set_Item() method:

$usa_states.Set_Item("GA", "Georgia")

This is actually the default action so you can also do:

$usa_states."GA" = "Georgia"

If the entry does not already exist it will be automatically added.

Combine Hash Tables

This is done by adding the hash variables with the + method, or appending with +=

$world_states = $usa_states + $india_states

Remove items from a Hash Table

This is done using the .Remove() method.

$usa_states.Remove("GA")

Retrieve items from a Hash Table

To display all contents just use the variable name:

$usa_states

Return just New York (the quotes are only needed here if the key contains spaces):

$usa_states.'NY'

Alternatively to return just New York:

$usa_states['NY']

Using a hash table as a lookup/decode for a variable:

$usa_states[$state]

or via the pipeline:

... | ForEach-object { $usa_states[$_.state] }...

To retrieve two or more key values, pass them as a comma separated array:

$usa_states['NY','IL']

If you prefer, you can make the array definition explicit with @( )

$usa_states[@('NY','IL','NH')]

Ordered Hash Table

By default, hashtables aren't ordered (or sorted). This often doesn't matter when you use a key to access specific values.
To have the properties stay in the order that you define them, use the ordered keyword.

$usa_states = [ordered]@{
    CA = "California" ; NY = "New York" ; "IL" = "Illinois"
}

Now when you enumerate the keys and values, they stay in that order. Note this does not have to be alphabetical.
This requires PowerShell 3.0 or greater and will create a [System.Collections.Specialized.OrderedDictionary] object.
A standard hashtable is a [System.Collections.Hashtable] object.

Loop through all the keys/values in a Hash Table

There are 3 main ways to do this:

1) Loop through all keys with ForEach-Object:

$usa_states.keys | ForEach-Object {
    Write-Output "Key = $_"
    Write-Output "Value = $($usa_states[$_])"
    Write-Output '----------'
}

An alternative way to display the output from the above is to format it with the -f operator:

$message = '{0} key has the value {1}' -f $_, $usa_states[$_]

2) Loop through all keys with ForEach:

ForEach ($state in $usa_states.Keys) {
    Write-Output "Key = $state"
    Write-Output "Value = $($usa_states["$state"])"
    Write-Output '----------'
}

3) Unwrap the hash table object with GetEnumerator() This passes each key/value pair through the pipeline:

$usa_states.GetEnumerator() | ForEach-Object{
    Write-Output "Key = $($_.key)"
    Write-Output "Value = $($_.value)"
}

GetEnumerator

A hash table is a single PowerShell object, to sort, filter or work with the pipeline you can unwrap this object into it’s individual elements with the GetEnumerator() method.

$usa_states.GetEnumerator() | Sort-Object Name

When unwrapped with GetEnumerator, the hash table returns a collection of (DictionaryEntry) objects, so they must be processed by cmdlets that can accept a collection, or alternatively pass the objects individually via ForEach.

$hashtable.GetEnumerator() | ForEach-Object { … }
or
ForEach($item in $hashtable.GetEnumerator()) {Echo $item … }
ForEach($item in $hashtable.KEYS.GetEnumerator()) {Echo $item … }

Export a Hash table to a CSV file

To export the contents of a hash table (rather than information about the hashtable object) use the GetEnumerator() method,

Unlike a Custom PowerShell object, a hash table always contains just a Key and Value, so Select those and pass to Export-CSV:

$hashtable.GetEnumerator() | Select Key, Value | Export-CSV -path c:\temp\hash.csv -NoTypeInformation

If your hash table contains any dates, ensure they are in a standard format, like ISO 8601 (yyyy-MM-dd) so the CSV file will be easy to import into a spreadsheet program.

Searching for specific items

A simple test can be made with -eq

If ($usa_states.NY -eq 'New York') {Echo 'OK'}

You can test if a key exists with:

If ($usa_states.NY) {Echo 'OK'}

However be careful, if NY is set to zero or $Null, that test will fail and return $false as if the key didn’t exist at all.

There are also the .ContainsKey or .ContainsValue methods, which allow partial matches:

$usa_states.ContainsKey('NY')
$usa_states.ContainsValue('New')

Using @ as a SPLAT operator

Splatting expands a hash table into a set of command line parameters.

First use @ to create a hashtable containing parameters to a cmdlet:

PS C:\> $stuff = @{path = "c:\demo"; Recurse= $true}

Then use @ to SPLAT the parameters:

PS C:\> dir @stuff

That will in effect run: dir -Path c:\demo -Recurse:$true
The paired keys and values become cmdlet parameters and values:

PS C:\> $params = @{year = 1980; Month = 5; day = 31}
PS C:\> get-date @params

The @ character is also used to create here strings.

Store an Array inside a Hash table

An array can be stored as part of a hash table.
This is possible because hash tables use the semi-colon as key-value pair separators, while Arrays use a comma.

First create some arrays:

$arrNY = @('Albany', 'Jamestown', 'New York', 'Niagara Falls')
$arrCA = @('Alhambra', 'Berkeley', "Fresno", "Los Angeles")

Then copy the arrays into the hash table:

$state_towns=@{
  NY = $arrNY
  CA = $arrCA
}

You can then display the Hash table, one of the arrays or an array element:

PS C:\> $state_towns
PS C:\> $state_towns.NY
PS C:\> $state_towns.NY[2]

This means that the comma-separated output of many cmdlets like Get-Process or Get-ChildItem can be stored directly in a hash table.
Some more examples from Roger Cormier [MSFT] here.

“Nor shall you by your presence make afraid, The kingfisher, who looks down dreamily, At his own shadow gorgeously array'd” ~ Sir Edmund William Gosse

Related PowerShell Cmdlets

PowerShell Arrays
ConvertFrom-StringData - Convert strings (or a here string) to a hashtable.
get-help about_hash_tables
Variables - Create/read variables.
Everything about hash tables - PowerShell Explained.
PowerShell Hash Table Quirks - The Scripting Guys.


 
Copyright © 1999-2024 SS64.com
Some rights reserved