Loading...
X

Hashtables in PowerShell (strings that start with @) (complete guide)

Table of Contents

1. What are Hashtables in PowerShell

2. What are hashtables used for?

1) Storing data

2) Cmdlet options

3) Formatting output

4) Converting to JSON

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

12. Sorting keys and values

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.1 Splatting basics

16.2 Splatting with optional parameters

16.3 Multiple hashtables with options for one cmdlet

16.4 Splatting for clean code

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 values​​in 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 values​​are 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


Leave Your Observation

Your email address will not be published. Required fields are marked *