Hashtables in PowerShell (strings that start with @) (complete guide)
September 4, 2024
Table of Contents
1. What are Hashtables in PowerShell
2. What are hashtables used for?
3. Syntax for creating hashtables
4. Why the order of keys is not maintained in the hashtable. How to create an ordered hashtable
5. How to output the contents of a hashtable
6. The .keys and .values properties
7. Getting values by key from a hashtable
8. Adding and removing keys and values
9. How to clear the contents of a hashtable
10. Iterating over hashtable keys and values
11. Object types in hashtables
13. How to properly copy a hash table. The .Clone() method
14. How to count the number of entries in a hashtable
15. How to check if certain keys or values exist in a hashtable
16. Using hashtables to pass arguments to a cmdlet
16.2 Splatting with optional parameters
16.3 Multiple hashtables with options for one cmdlet
16.5 Substituting arguments into programs outside of PowerShell
17. Using hashtables to format output
18. How to create a hashtable from a string. ConvertFrom-StringData cmdlet
19. How to convert a hashtable to JSON
20. How to convert JSON to hashtable
1. What are Hashtables in PowerShell
A hashtable in PowerShell is a string containing name = value pairs, this string is enclosed in {} (curly braces) and starts with the “@” character.
The syntax of a hashtable is:
@{ NAME = VALUE; [ NAME = VALUE; ] ...}
Or:
@{ NAME = VALUE [NAME = VALUE ] … }
An example of creating a hashtable:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"}
If you are familiar with other programming languages, hashtables in PowerShell are similar to a data type such as dictionaries in Python or arrays with string keys in PHP (an associative array).
2. What are hashtables used for?
1) Storing data
First of all, hashtables are used to store data. Hashtables differ from arrays in that each stored value has a specific (and unique) key.
2) Cmdlet options
Hashtables are quite interesting in PowerShell because they can be used for more than just storing data. You've probably seen examples of hash tables being used as strings that collect arguments before passing them to a cmdlet. You've probably seen hashtables in this capacity in various PowerShell tutorials.
For example, you might have seen something like this:
$Options = @{ Path = "/home/mial/test" Recurse = $True Filter = "*.php" Exclude = "html" } Get-ChildItem @Options
This creates a hash table, which is then passed to the cmdlet.
In fact, the commands shown above are a complete analogy of the following command:
Get-ChildItem -Path /home/mial/test -Recurse -Filter "*.php" -Exclude "html"
With a large number of arguments, this is really convenient and more visual.
3) Formatting output
The following commands show how hashtables are used to format output:
Get-ChildItem | Format-Table Mode, LastWriteTime, Length, @{Label="Имя"; Expression={$_.Name}} Get-ChildItem | Format-Table @{Label="Режим"; Expression={$_.Mode}}, @{Label="Последняя запись в"; Expression={$_.LastWriteTime}}, @{Label="Размер"; Expression={$_.Length}}, @{Label="Имя"; Expression={$_.Name}}
4) Converting to JSON
Hash tables can be converted to a string in JSON format.
All these examples of using hash tables will be discussed later in this article.
3. Syntax for creating hashtables
Hash table syntax:
@{ NAME = VALUE; [NAME = VALUE ] ...}
That is, the string begins with the “@” symbol and is enclosed in curly brackets. The “name” and “value” pairs are separated by the “=” (equal) sign. The “;” (semicolon) is used as a name=value pair separator.
The newline character can also be used as a name=value pair separator:
@{ NAME = VALUE [NAME = VALUE ] … }
So the following two commands are identical:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $hash = @{ Number = 1 Shape = "Square" Color = "Blue" }
Note that keys are not quoted, but values are. More specifically, values (if they are strings) must always be quoted. Keys must also be quoted if they contain spaces.
Note: When accessing a hash table value by key, if the key is a string, it must always be placed in quotation marks (regardless of the presence of spaces), for example:
$hash["Number"]
To be able to perform various actions with the hash table, assign its value to a variable.
If desired, you can create an empty hash table:
$hash = @{}
4. Why the order of keys is not maintained in the hashtable. How to create an ordered hashtable
If you iterate over the values of the hashtable (how to do this will be shown below), you will notice that the order in which the keys with values are added and the order in which they are iterated over do not match.
However, you can create an ordered hashtable by adding the string “[ordered]” before the “@” symbols, that is:
[ordered]@{ NAME = VALUE ; [ NAME = VALUE ] ...}
Or using a newline character as a separator:
$hash = [ordered]@{ Number = 1 Shape = "Square" Color = "Blue" }
Note that the “[ordered]” property must be specified when creating the table, it cannot be specified for an already created table.
Example of creating an empty ordered hash table:
$hash = [ordered]@{}
5. How to output the contents of a hashtable
To display the contents of a hashtable, specify the name of the variable in which it is stored:
$hash
6. The .keys and .values properties
Hash tables have .keys and .values properties. Use dot notation to display all keys or all values.
$hash.keys
Output:
Number Shape Color
Display all values of the hash table:
$hash.values
Output:
1 Square Blue
Note the .keys property – it will come in handy when iterating over all values of the hash table.
7. Getting values by key from a hashtable
Hashtables are not arrays, so you cannot use an integer as an index into a hash table, but you can use a key name to get its value in a hash table. If the key is a string value, enclose the key name in quotation marks.
For example:
$hash["Number"] 1
Each key name is also a property of the hash table, and its value is the value of the property of the key name. Use the following format to display property values.
Example:
$hashtable.KEY VALUE
Examples:
$hash.Number 1 $hash.Color Blue
8. Adding and removing keys and values
To add keys and values to a hash table, use the following command format.
$hash["KEY"] = "VALUE"
For example, to add a key of “Time” with a value of “Now” to a hashtable, use the following statement format.
$hash["Time"] = "Now"
You can also add keys and values to a hashtable using the Add() method of the System.Collections.Hashtable object. The Add() method has the following syntax:
Add(Key, Value)
For example, to add a key of Time with a value of Now to a hash table, use the following statement format.
$hash.Add("Time", "Now")
You can also add keys and values to a hash table by using the addition operator (+) to append the hashtable to an existing hashtable. For example, the following statement adds the key of Time with a value of Now to the hashtable in the $hash variable.
$hash = $hash + @{Time="Now"}
You can also add values that are stored in variables.
$t = "Today" $now = (Get-Date) $hash.Add($t, $now)
You cannot use the subtraction operator to remove a key-value pair from a hashtable, but you can use the Remove() method of the Hashtable object. The Remove() method takes a key as a value.
The Remove method has the following syntax:
Remove(Key)
For example, to remove the key-value pair Time=Now from the hashtable in the $hash variable value, enter:
$hash.Remove("Time")
9. How to clear the contents of a hashtable
You can clear the contents of a hash table by simply assigning it an empty value:
$hash = @{}
Or you can use the .clear() method:
$hash.clear()
Note that these methods of clearing a hash table are not equivalent. Details on the difference are described in Section 13. How to properly copy a hash table. The .Clone() method.
10. Iterating over hashtable keys and values
You can iterate over the keys in a hash table to process the values in multiple ways. Each of the examples in this section has identical output. They iterate over the $hash variable, which contains the following hash table:
$hash = [ordered]@{ Number = 1; Shape = "Square"; Color = "Blue"}
Note: In these examples, $hash is defined as an ordered dictionary to ensure that the output is always in the same order. The examples below work the same for regular, unordered hash tables, but the output order will be unpredictable.
Each example below returns the same output – a message for each key and its value:
The value of 'Number' is: 1 The value of 'Shape' is: Square The value of 'Color' is: Blue
This example uses a foreach block to iterate over the keys.
foreach ($Key in $hash.Keys) { "The value of '$Key' is: $($hash[$Key])" }
This example uses ForEach-Object to iterate over the keys.
$hash.Keys | ForEach-Object { "The value of '$_' is: $($hash[$_])" }
This example uses the GetEnumerator method to send each key-value pair through the pipeline to the ForEach-Object.
$hash.GetEnumerator() | ForEach-Object { "The value of '$($_.Key)' is: $($_.Value)" }
This example uses the GetEnumerator and ForEach methods to iterate over each key-value pair.
$hash.GetEnumerator().ForEach({"The value of '$($_.Key)' is: $($_.Value)"})
11. Object types in hashtables
The keys and values in a hash table can be of any .NET object type, and a single hash table can contain keys and values of multiple types.
12. Sorting keys and values
The items in a hash table are inherently unordered. The key-value pairs may appear in a different order each time you display them.
Although you can't sort hash tables, you can use the hash table GetEnumerator method to enumerate the keys and values, and then use the Sort-Object cmdlet to sort the enumerated values for display.
For example, the following commands iterate over the keys and values in the hash table in the $p variable, and then sort the keys alphabetically.
$p.GetEnumerator() | Sort-Object -Property key Name Value ---- ----- Hash2 {[a, 1], [b, 2], [c, 3]} Notepad System.Diagnostics.Process (Notepad) PowerShell System.Diagnostics.Process (pwsh) WinRM Running
The following command uses the same procedure to sort the hash valuesin descending order.
$p.GetEnumerator() | Sort-Object -Property Value -Descending Name Value ---- ----- PowerShell System.Diagnostics.Process (pwsh) Notepad System.Diagnostics.Process (Notepad) Hash2 {[a, 1], [b, 2], [c, 3]} WinRM Running
13. How to properly copy a hash table. The .Clone() method
Consider the following example, in which the contents of the $hash variable (the hashtable) are assigned to another variable, $another. Then the contents of $hash are cleared. What should we see when we print the $another variable?
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash $hash.Clear() $another
The hash table is supposed to be printed, but the $another variable is empty.
The thing is that the $another variable is assigned a reference to the memory where the hashtable is stored; and if the hashtable is deleted, the value of the second variable becomes empty.
The same thing happens when changes are made to the original hashtable – a copy of this hashtable in another variable mirrors all changes.
To avoid this – to save the value of the copied hashtable even if the initial variable is cleared or modified, use the .Clone() method:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash.Clone() $hash.Clear() $another
In this case, when displaying the contents of the $another variable, the hash table will be shown.
The same result can be achieved by choosing a different way to clear the initial variable. If you assign an empty value instead of the .Clear() method, the copied copies of the hashtable will be saved:
$hash = @{ Number = 1; Shape = "Square"; Color = "Blue"} $another = $hash $hash = @{} $another
14. How to count the number of entries in a hashtable
You can use the .Count property to find out how many entries are in a hashtable:
$hash.Count 3
15. How to check if certain keys or values exist in a hashtable
In most cases, you can simply check the value like this:
if( $person.age ){...}
This is simple, but it caused me a lot of bugs because I was missing one important detail in my logic. I started using it to check for the existence of a key. If the key value was $false or zero, the operator would unexpectedly return $false.
if( $person.age -ne $null ){...}
This solves the problem for zero values, but not for $null or non-existent keys.
In general, the previous methods are more suitable for checking if a value is empty or equal to $null. But if you need to check if a certain key is present, use the .ContainsKey() property. For example:
if( $person.ContainsKey('age') ){...}
We also have .ContainsValue() for the situation when you need to check if a certain value is in the hashtable without iterating over the entire contents of the hashtable.
16. Using hashtables to pass arguments to a cmdlet
16.1 Splatting basics
Let's return to the already mentioned method of using hashtables to list cmdlet options. Even if you don't plan to use this method in your commands, understanding splatting will help you read the scripts in PowerShell tutorials.
The idea is that instead of providing all the properties to the cmdlet in one line, you can first pack them into a hashtable. Then you can pass the hash table to the function in a special way. Here is an example of creating a DHCP scope in the normal way.
Add-DhcpServerV4Scope -Name 'TestNetwork' -StartRange '10.0.0.2' -EndRange '10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"
Without splatting, all of these things need to be specified on one line. The command line gets quite long and either scrolls off the screen or wraps around wherever it wants. Either way, it makes the command and options harder to understand.
Now compare this to the command using splatting.
$DHCPScope = @{ Name = 'TestNetwork' StartRange = '10.0.0.2' EndRange = '10.0.0.254' SubnetMask = '255.255.255.0' Description = 'Network for testlab A' LeaseDuration = (New-TimeSpan -Days 8) Type = "Both" } Add-DhcpServerV4Scope @DHCPScope
This command is exactly the same as the previous cmdlet. Just take a minute to appreciate how easy it is to read this example. It's the same command with all the same options and their values. The second variant is easier to understand and maintain in the future if you need to make changes to it.
So, here's what you need to pay attention to:
- A regular hashtable is created, in which you must follow the syntax rules (a new line is used to separate key=value pairs, string valuesare always placed in quotes)
- Note that the names of the cmdlet options are used as keys, but there is no hyphen before the option name
- The result of the cmdlet (including one launched with options) can be substituted as a value, in which case the cmdlet and its options must be placed in parentheses
- When passing the created hash table as arguments to the cmdlet, instead of the usual variable name preceded by the “$” symbol, the variable name preceded by the “@” symbol is passed.
16.2 Splatting with optional parameters
One of the most common ways I use splatting is to work with optional parameters that come from elsewhere in my script. Let's say I'm running the Get-CIMInstance cmdlet, which has an optional $Credential argument.
$CIMParams = @{ ClassName = 'Win32_Bios' ComputerName = $ComputerName } if($Credential) { $CIMParams.Credential = $Credential } Get-CIMInstance @CIMParams
I start by creating a hashtable with the required parameters. If $Credential exists, it's added to the hashtable.
Then the resulting hashtable (whether it has the Credential option set or not) is piped to the Get-CIMInstance cmdlet.
The code is quite clear and you can add other parameters or logic to it if you wish. The Get-CIMInstance function is called only once, regardless of the parameters passed to it.
16.3 Multiple hashtables with options for one cmdlet
You can combine multiple hash tables into the same cmdlet. If we return to the example above:
$Common = @{ SubnetMask = '255.255.255.0' LeaseDuration = (New-TimeSpan -Days 8) Type = "Both" } $DHCPScope = @{ Name = 'TestNetwork' StartRange = '10.0.0.2' EndRange = '10.0.0.254' Description = 'Network for testlab A' } Add-DhcpServerv4Scope @DHCPScope @Common
With this approach, you can create lists of options common to several cmdlets. And options unique to certain cmdlets can be put into a separate hash table. This can further increase the readability of the source code.
16.4 Splatting for clean code
There's nothing wrong with isolating one parameter if it makes your code cleaner.
$log = @{Path = '.\logfile.log'} Add-Content "logging this command" @log
16.5 Substituting arguments into programs outside of PowerShell
Splatting also works with some executables that use the /param:value syntax. For example, Robocopy.exe has these parameters.
The result is that you can create a hash table and pass it along with other arguments to robocopy:
$robo = @{R=1;W=1;MT=8} robocopy source destination @robo
I don't know how useful this is, but I found it interesting.
17. Using hashtables to format output
There are several cmdlets that support using hash tables to create custom or computed properties. This can usually be seen with Select-Object and Format-Table. Hashtables have a special syntax that looks like this when fully expanded.
$property = @{ name = 'totalSpaceGB' expression = { ($_.used + $_.free) / 1GB } }
“name” is how the cmdlet will label this column, and “expression” is the script block that is executed to insert into this column, where “$_” is the value of the object passed through the pipe (“|”).
Here is the script in action:
$drives = Get-PSDrive | Where Used $drives | Select-Object -Property name, $property
Sample output:
Name totalSpaceGB ---- ------------ C 118.35 Temp 118.35 Y 915.46 Z 1832.70
I put the custom output format in a variable, but it could easily be defined in the string, and you can shorten “name” to “n” and “expression” to “e” while you're at it.
$drives | Select-Object -property name, @{n='totalSpaceGB';e={($_.used + $_.free) / 1GB}}
18. How to create a hashtable from a string. ConvertFrom-StringData cmdlet
The ConvertFrom-StringData cmdlet converts a string or the following string of key-value pairs into a hash table.
The following example shows how to create the custom messages string from the previous example here and how to use ConvertFrom-StringData to convert them from a string to a hash table.
The following command creates a string of key-value pairs here and then stores it in the $string variable.
$string = @" Msg1 = Type "Windows". Msg2 = She said, "Hello, World." Msg3 = Enter an alias (or "nickname"). "@
This command uses the ConvertFrom-StringData cmdlet to convert the string here to a hash table.
ConvertFrom-StringData $string Name Value ---- ----- Msg3 Enter an alias (or "nickname"). Msg2 She said, "Hello, World." Msg1 Type "Windows".
See also:
Get-Help about_Quoting_Rules -Full
19. How to convert a hashtable to JSON
You can use the ConvertTo-JSON cmdlet to convert a hashtable to JSON format:
$hash | ConvertTo-JSON
20. How to convert JSON to hashtable
Using the ConvertFrom-Json cmdlet with the -AsHashtable option, you can convert a JSON string to a hashtable:
Example:
'{ "a": "b" }' | ConvertFrom-Json -AsHashtable
Output:
Name Value ---- ----- a b
Related articles:
- How to remove the header from the output table in PowerShell and leave only the data (86.3%)
- Basics of launching and using command line utilities in Windows (65.8%)
- How to clear the terminal window in PowerShell. Analog of clear (65.8%)
- How to find large files in PowerShell (using Get-Childitem) (65.8%)
- PowerShell: how to find only folders with Get-ChildItem (65.8%)
- How to configure the network interface to use a dynamic IP address (DHCP) in PowerShell (RANDOM - 52.2%)