Summary: Learn about creating an array of arrays in Windows PowerShell, and see how to store numerical data and rich objects in elements.
Microsoft Scripting Guy, Ed Wilson, is here. Yesterday in Charlotte, North Carolina in the United States, it was 60 degrees Fahrenheit (that is 15 degrees Celsius according to my unit conversion module). I was bragging about this to my friend, George, who lives in Ottawa, Canada. Today it is 32 degrees Fahrenheit (0 degrees Celsius—I don’t need a unit conversion module to do that one), and there is frost on the ground. I guess that is what I get for bragging.
Anyway, the Scripting Wife and I are back in Charlotte, after our quick trip to Phoenix, Arizona to speak at the Arizona PowerShell Users Group meeting. The event was great, and they are the perfect hosts. In fact, we are planning an International PowerShell Users Group Day in conjunction with them, which should happen in the spring of 2012. Stay tuned for more information on this exciting event.
Note: This is the fifth post in a series of blog posts that are devoted to discussing working with arrays in Windows PowerShell.
- In the first post, Learn Simple Ways to Handle Windows PowerShell Arrays, I discussed creating arrays, indexing into arrays, and two techniques for walking through an array.
- In the second post, Add, Modify, Verify, and Sort Your PowerShell Array, I discussed adding, modifying, or verifying values in a Windows PowerShell array, and two easy techniques for sorting the array.
- In the third post, Find the Index Number of a Value in a PowerShell Array, I talked about working with arrays to determine the index number of a given value. In addition, I covered working with one half of the array at a time.
- Yesterday, I answered a question that was sent to scripter@microsoft.com about reading a CSV file and building distinguished names on the fly by using array notation. The Read a CSV File and Build Distinguished Names on the Fly by Using PowerShell post was really cool, and it presented a practical way to use arrays.
Creating an array of arrays
One of the cool things to do with an array is to create an array that contains other arrays. In Windows PowerShell this is super easy. It is as easy to create an array of arrays as it is to create a single dimensional array. Here are the steps to create an array of arrays:
- Create an array and store it in a variable.
- Create additional arrays, and store them in variables as well.
- Use the previously created arrays and separate them with the comma operator.
- Assign the arrays to a variable.
The following code creates four arrays and stores the arrays in variables. It then assigns each of the newly created arrays to a different element in a new array named $array.
PS C:\> $a = 1..5
PS C:\> $b = 6..10
PS C:\> $c = 11..15
PS C:\> $d = 16..20
PS C:\> $array = $a,$b,$c,$d
Accessing elements in an array of arrays
To access items from an array of arrays, use the square-bracketed “array” notation. For example, to see the first array of items, which are stored in element 0, use [0]. This code is shown here.
$array[0]
What is cool is that element 0 contains an array, so an array returns in response to the command. In the following command, I return the array previously stored in element 0. To save space in the output, I join the elements of the array with a space between each element. Here is the command to display the array that is stored in element 0 and to return the elements on a single line.
PS C:\> $array[0] -join " "
1 2 3 4 5
Each of the other arrays that I stored in the other elements of $array are accessed in the same manner. The following code displays the information that is contained in the remaining elements of the $array array.
PS C:\> $array[1] -join " "
6 7 8 9 10
PS C:\> $array[2] -join " "
11 12 13 14 15
PS C:\> $array[3] -join " "
16 17 18 19 20
If I want to access a specific element from one of the arrays that is stored in one of the elements of the $array array, I again use the square bracket (array) notation. This time, I also specify the specific element from the array that is contained in the element. Therefore, to access element 1 in the $b array (stored in element 1 of $array), I use the notation that is shown here.
$array[1][1]
To access the third element of the array, which is stored in the third element of $array, the syntax is as shown here.
$array[3][3]
The following image shows the code and the output from creating four arrays and storing them in variables a-d, creating an array that holds the four arrays, displaying the values from each element, and then accessing element 1,1 and element 3,3.
One of the fun things to do, instead of just storing numbers in arrays, is to use the array for temporary storage. For example, in the following code, I store the results of three different WMI queries into three different variables. I then create three different arrays with cherry-picked properties from each of the stored WMI results. Next, I create an array of arrays by building a new array.
$comp = gwmi win32_computersystem
$os = gwmi win32_operatingsystem
$bios = gwmi win32_bios
$a = $comp.UserName, $comp.DNSHostName, $comp.Domain
$b = $os.caption, $os.buildnumber, $os.OSArchitecture
$c = $bios.name, $bios.description, $bios.manufacturer
$array = $a,$b,$c
When I have my array of arrays, I can index into any of the values that I need to access. A few of the elements are shown here.
PS C:\> $array[0]
IAMMRED\ed
newMrEd
iammred.net
PS C:\> $array[0][1]
newMrEd
PS C:\> $array[1]
Microsoft Windows 7 Ultimate
7601
64-bit
PS C:\> $array[1][0]
Microsoft Windows 7 Ultimate
PS C:\> $array[2][1]
BIOS Date: 05/04/11 17:11:33 Ver: 04.06.04
The commands to store three different WMI queries in three different variables, build up an array of arrays, and access different elements of the arrays are shown in the following image.
One thing that has intriguing possibilities is to store rich objects in an array. In the following example, I store the results of Get-Service, Get-Process, and Get-Date in their own variables. Next, I create an array of these objects.
$a = Get-Service
$b = Get-Process
$c = get-date
$array = $a,$b,$c
When I have the array of objects stored, I can index into them just like anything else.
PS C:\> $array[2]
Thursday, December 01, 2011 5:31:12 PM
Because there is only one DateTime object, if I attempt to go any deeper with this object, an error arises. The command and the associated error are shown here.
PS C:\> $array[2][1]
Unable to index into an object of type System.DateTime.
At line:1 char:11
+ $array[2][ <<<< 1]
+ CategoryInfo : InvalidOperation: (1:Int32) [], RuntimeException
+ FullyQualifiedErrorId : CannotIndex
But with the processes and services in the array elements, we have a collection of arrays. I can access them directly. I illustrate this here.
PS C:\> $array[1][0]
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
671 41 31700 38604 187 100.79 7284 AnalogRec13
In fact, I can even use dotted notation to access individual property values from individual processes. This technique is shown here.
PS C:\> $array[1][0].id
7284
Well, that is all there is to using and working with arrays. Tomorrow, I will talk about hash tables. Hope to see you then.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy