Arrays and hash tables are two of the most common data structures available in modern scripting languages, and Windows PowerShell supports both of them. An array, which is sometimes referred to as a collection, stores a list of items. A hash table, which is sometimes called a dictionary or an associative array, stores a paired list of items. I'll show you how to create arrays and hash tables as well as how to access items in them.

Creating an Array

Arrays are useful when you want to store and retrieve a list or collection of items. One of the simplest ways to create an array is to use a PowerShell cmdlet that outputs more than one object. For example, just running the Get-ChildItem cmdlet outputs a list of items in the current location. This list of items can be captured in a variable. If the current location contains more than one item, the variable in which you store the list is an array. It's really that simple. For example, consider the following PowerShell command:

$list = Get-ChildItem $ENV:SystemRoot

After running this command, the variable $list now contains an array of FileInfo and DirectoryInfo objects.

Another way to create an array is to specify the items, separated by commas, and assign them to a variable:

$list = "A","B","C","1","2","3"

Accessing Items in an Array

There are three ways you can access the items in an array:

  • Use the foreach statement. PowerShell's foreach statement provides a convenient way to access each item in an array. For example, to output each item in the $list array, you'd run the command:
    foreach ( $item in $list ) { $item }
  • Use the ForEach-Object cmdlet. The ForEach-Object cmdlet takes an array as input from the pipeline and passes each item in the array to a script block for processing. The current item in the array is represented by the special $_ variable. To output each item in the $list array using the ForEach-Object command, you'd run the command:
    $list | ForEach-Object { $_ }
  • Use the for statement with the index number. Each item (or element) in an array can be referenced by number, starting with 0. For example, $list[0] refers to the first item in the array, $list[1] refers to the second item, and so forth. For example, to output each item in the array using the for statement and index number, you'd run the command:
    for ( $i = 0; $i -lt $list.Count; $i++ ) {
      $list[$i]
    }

Out of these three techniques, the for statement with the index number is used the least. The main reason is that the foreach statement and ForEach-Object cmdlet provide shorter ways to accomplish the same thing.

When learning about these three techniques, a common question is: What is the difference between using the foreach statement and the ForEach-Object cmdlet? The main difference is that when you use the foreach statement, you have to retrieve all the items in the array before you can access each item. In contrast, the ForEach-Object cmdlet takes advantage of PowerShell's pipeline to access one item at a time.

A trickier question to answer is: Which one should you use? The answer depends on the items in the array. If you have a relatively small list of items that don't take a long time to retrieve, the foreach statement will work just fine. If you have a large list of items or the items take a long time to retrieve (e.g., files on a remote file server), you'll probably want to use the ForEach-Object cmdlet. Another consideration concerns the Write-Progress cmdlet. If you want to use this cmdlet in a script to keep users informed about an operation's percentage of completion, you'll need to retrieve all the items first with the foreach statement so that you can calculate the percentage completed.

There's a potential point of confusion regarding the foreach statement versus the ForEach-Object cmdlet: The ForEach-Object cmdlet has the foreach keyword as an alias! Be aware that when you use the term foreach after the vertical pipe (|) character in a PowerShell pipeline, you're actually calling the ForEach-Object cmdlet.

Another potential point of confusion regarding arrays in general might arise if you're familiar with VBScript or JavaScript. In these two scripting languages, arrays and collections are actually different kinds of objects. However, in PowerShell, you can treat them as one and the same.

Creating a Hash Table

Hash tables are useful when you want to store and retrieve items by name. For example, you can use a hash table to store a list of servers and their associated IP addresses.

You can create a hash table by specifying the names and values between the @{ and } characters. For example, to create a hash table that contains the names of three servers and their IP addresses, you'd run a command like the following:

$hash = @{"server1" = "192.168.17.21";
  "server2" = "192.168.17.22";
  "server3" = "192.168.17.23"}

If you output this hash table (just type $hash at the PowerShell prompt and press Enter), you'll see output like that in Figure 1. Note that PowerShell outputs the Name column's values in an undefined order. One of the characteristics of a hash table is that the named items aren't in a specific order.

Figure 1: Hash Table Output

Accessing Items in a Hash Table

To access a value in a hash table, you can specify the hash table's name followed by the name associated with the value, enclosed in square brackets. Alternatively, you can put a period between the hash table's name and the name associated with the value. For example, for the $hash variable created earlier, any of the following commands will return the value 192.168.17.21:

$hash["server1"]
$hash.server1
$hash."server1"

Note that the quotes in the $hash["server1"] command are required. Without them, PowerShell wouldn't know how to resolve the token server1. However, if the server name is in a variable (e.g., $serverName), you could use the command:

$hash[$serverName]

Some PowerShell cmdlets use hash tables as values for parameters. For example, the Select-Object cmdlet uses hash tables to output calculated properties. To use a hash table to create a calculated property for Select-Object, it must have two paired values: Name, which specifies the calculated property's name, and Expression, which contains a script block that calculates the property. Take, for example, the command:

Get-ChildItem $ENV:SystemRoot | select-object Name,
  LastWriteTime, @{Name="Day";
  Expression={$_.LastWriteTime.DayOfWeek}}

In this case, Select-Object will output the name, last write time, and the day of the week for each file and directory in the Windows installation directory. As with ForEach-Object, the special $_ variable refers to the current object.

Knowing How to Use These Data Structures Is Important

Arrays and hash tables are two basic data structures that you need to understand in order to work effectively in PowerShell. Once you've mastered arrays and hash tables, you're on your way to becoming a PowerShell power user.