Skip to content

PowerShell Hash Tables

How to declare, access, modify, and loop through PowerShell hash tables (dictionaries) using @{} syntax, key-value pairs, and methods like .Add(), .Remove(), and .GetEnumerator() for efficient data management.

A hash table (also known as a dictionary or associative array) is a compact data structure that stores data as key-value pairs. Under the hood, PowerShell hash tables are built on the .NET System.Collections.Hashtable class. Unlike standard arrays indexed by sequential numbers, hash tables allow you to look up values using unique descriptive keys (such as strings or identifiers), enabling fast lookups without scanning the entire collection.

The most common operations on hash tables in PowerShell are explained below.

Declaring Hash Tables (@{})

Hash tables are declared using the @{} syntax. Key-value pairs are separated by semicolons (;) on a single line or placed on separate lines without semicolons.

Example of Hash Table Declarationpowershell
$ServerConfig = @{ Hostname = "web01"; IP = "192.168.1.50"; Port = 443 }

$DatabaseConfig = @{
    ServerName  = "sql-prod-01"
    Database    = "ProductionDB"
    MaxPoolSize = 100
    Encryption  = $true
}

$DatabaseConfig.GetType().FullName
Outputplaintext
System.Collections.Hashtable

Hash table keys can be declared as unquoted identifiers (barewords) if they contain no whitespace or special characters. If a key includes spaces or hyphens, wrap it in quotation marks (e.g., 'Max-Pool-Size' = 100).

Another example using a user profile:

Example of User Hash Tablepowershell
$user = @{
    Name = "Tom"
    Age  = 30
    Role = "Administrator"
}

$user
Outputplaintext
Name                           Value
----                           -----
Role                           Administrator
Age                            30
Name                           Tom

where:

  • Each Key = Value pair is separated by a newline or semicolon.
  • Keys are typically strings, but can be other data types as well.

Key-Value Access

You can access and inspect values stored in a hash table using either property dot notation or the array index operator ([]).

Property and Indexer Syntax

Example of Key-Value Accesspowershell
$Server = @{
    Name  = "AppServer01"
    Role  = "ApplicationHost"
    Cores = 8
}

$Server.Name

$Server["Role"]
Outputplaintext
AppServer01
ApplicationHost
  • Dot Notation ($hash.Key): Convenient and clean; ideal when keys are known, fixed identifiers without spaces.
  • Indexer Notation ($hash['Key'] or $hash[$variable]): Necessary when the key contains spaces, special characters, or is stored inside another variable.

Checking Key Existence

Querying a non-existent key returns $null without generating an error. To verify whether a key or value actually exists in the collection, use the built-in boolean inspection methods:

Example of ContainsKey and ContainsValuepowershell
$Server.ContainsKey("Cores")
$Server.ContainsValue("ActiveDirectory")
Outputplaintext
True
False

Adding and Modifying Keys

Hash tables are dynamic and mutable, allowing you to add, modify, or delete key-value pairs at runtime.

You can add entries via direct assignment or by using the .Add() method:

Example of Adding and Modifying Keyspowershell
$Config = @{
    Environment = "Staging"
    Timeout     = 30
}

$Config["MaxRetries"] = 3
$Config.Environment   = "Production"

$Config.Add("EnableLog", $true)

$Config

where:

  • $Config["MaxRetries"] = 3 creates a new key MaxRetries.
  • $Config.Environment = "Production" overwrites the existing Environment value.
  • $Config.Add(...) safely inserts a new key but will throw a runtime exception if the key is already present.
Outputplaintext
Name                           Value
----                           -----
Environment                    Production
Timeout                        30
EnableLog                      True
MaxRetries                     3

Another example adding multiple keys to a user object:

Example of Adding Keys to a Userpowershell
$user = @{ Name = "Tom" }
$user["Department"] = "IT"
$user.Add("Email", "tutorialreference@example.com")
$user
Outputplaintext
Name                           Value
----                           -----
Email                          tutorialreference@example.com
Department                     IT
Name                           Tom

where:

  • Assigning to a new key with bracket notation ($user["Department"] = ...) creates the key if it doesn't already exist.
  • The .Add() method achieves the same result but throws an error if the key already exists.

Removing Keys

Use the .Remove() method to delete an individual key-value pair, or .Clear() to empty the entire table:

Example of Removing Keyspowershell
$Config = @{ Environment = "Production"; Timeout = 30; MaxRetries = 3 }

$Config.Remove("Timeout")

$Config.ContainsKey("Timeout")
Outputplaintext
False

Removing a key from a user object:

Example of Removing an Email Keypowershell
$user = @{ Name = "Tom"; Department = "IT"; Email = "tutorialreference@example.com" }
$user.Remove("Email")
$user
Outputplaintext
Name                           Value
----                           -----
Department                     IT
Name                           Tom

Looping Through Hash Tables

Unlike arrays, passing a hash table directly to the pipeline emits the entire hash table as a single object. To process each key-value pair individually, you must enumerate its keys or entries.

1. Enumerating Keys with .Keys

Example of Looping Through Keyspowershell
$Services = @{ Web = "nginx"; DB = "mongod"; Cache = "redis" }

foreach ($key in $Services.Keys) {
    Write-Output "Role: $key maps to Service: $($Services[$key])"
}
Outputplaintext
Role: Web maps to Service: nginx
Role: DB maps to Service: mongod
Role: Cache maps to Service: redis

2. Enumerating Entries with .GetEnumerator()

To pipe key-value pairs through pipeline cmdlets (Where-Object, ForEach-Object, Sort-Object), call the .GetEnumerator() method. This streams each pair as a DictionaryEntry object with .Key and .Value properties:

Example of GetEnumeratorpowershell
$user = @{ Name = "Tom"; Age = 30; Role = "Administrator" }

foreach ($entry in $user.GetEnumerator()) {
    Write-Output "$($entry.Key): $($entry.Value)"
}

where:

  • .GetEnumerator() exposes each key-value pair as an object with .Key and .Value properties.
  • Looping directly over $user without .GetEnumerator() iterates over the keys only in most contexts, so .GetEnumerator() is the safer, explicit approach.
Outputplaintext
Role: Administrator
Age: 30
Name: Tom

3. Filtering Entries Through the Pipeline

Example of Filtering Hash Table Entriespowershell
$PortMap = @{
    HTTP  = 80
    HTTPS = 443
    SSH   = 22
    RDP   = 3389
}

$PortMap.GetEnumerator() |
    Where-Object { $_.Value -gt 100 } |
    Sort-Object -Property Value

where:

  • .GetEnumerator() unrolls the hash table into distinct stream elements.
  • $_.Key represents the current port identifier.
  • $_.Value represents the numeric port number.
Outputplaintext
Name                           Value
----                           -----
HTTPS                          443
RDP                            3389

Ordered Hash Tables ([ordered]@{})

Standard hash tables use a hashing algorithm that does not guarantee insertion order. When enumerating keys, the output order often differs from the declaration order.

To preserve the exact sequence in which keys were declared, prefix the literal with the [ordered] type accelerator. This instantiates an underlying System.Collections.Specialized.OrderedDictionary:

Example of Ordered vs Standard Hash Tablepowershell
$StandardHash = @{
    First  = 1
    Second = 2
    Third  = 3
}

$OrderedHash = [ordered]@{
    First  = 1
    Second = 2
    Third  = 3
}

Write-Output "--- Standard Keys ---"
$StandardHash.Keys -join ", "

Write-Output "--- Ordered Keys ---"
$OrderedHash.Keys -join ", "

where [ordered]@{} instructs the parser to maintain key sequence upon creation.

Outputplaintext
--- Standard Keys ---
First, Third, Second
--- Ordered Keys ---
First, Second, Third

A practical configuration example:

Example of Ordered Configpowershell
$config = [ordered]@{
    Server   = "WEB01"
    Port     = 8080
    Protocol = "HTTPS"
}

$config
Outputplaintext
Name                           Value
----                           -----
Server                         WEB01
Port                           8080
Protocol                       HTTPS

Practical Example: Parameter Splatting and Server Configuration

A primary use of hash tables in production administration is splatting. Splatting allows you to define a cmdlet's parameters and values inside a hash table and pass them cleanly using the @ symbol instead of long, single-line command invocations.

The following script builds an ordered system configuration map and demonstrates parameter splatting:

splatting-demo.ps1powershell
$AuditProfile = [ordered]@{
    TargetRole   = "WebFrontend"
    Environment  = "Production"
    CheckDate    = (Get-Date -Format "yyyy-MM-dd")
    StatusReport = "Compliant"
}

$FileParams = @{
    Path        = "$PSScriptRoot\system-audit.json"
    Value       = ($AuditProfile | ConvertTo-Json)
    Force       = $true
    ErrorAction = "Stop"
}

Set-Content @FileParams

if (Test-Path -Path $FileParams.Path) {
    [PSCustomObject]@{
        DestinationFile = $FileParams.Path
        ProfileWritten  = $AuditProfile.TargetRole
        ConfigEntries   = $AuditProfile.Count
    }
}

where:

  • $AuditProfile stores structured operational configuration preserving layout order.
  • $FileParams is a hash table matching the parameter names of Set-Content (-Path, -Value, -Force, -ErrorAction).
  • @FileParams (splatting syntax) unpacks the key-value pairs directly into the cmdlet's parameters.
  • Test-Path validates target file generation.

Execute the script from the console:

Consolepowershell
pwsh ./splatting-demo.ps1
Outputplaintext
DestinationFile                       ProfileWritten ConfigEntries
---------------                       -------------- -------------
C:\Scripts\system-audit.json          WebFrontend                4
Navigation