December 6th, 2011

Add, Modify, Verify, and Sort Your PowerShell Array

Doctor Scripto
Scripter

Summary: Learn how to add, modify, or verify values in a Windows PowerShell array, and discover two easy techniques for sorting your array.

Hey, Scripting Guy! Question Hey, Scripting Guy! I get that arrays are really simple in Windows PowerShell, but it seems that they are so simple that no one ever seems to tell us how to work with them. For example, I need to know how to add items to an array or how to change an item that is in an array. I have searched all over the Internet, and I cannot seem to find a straight answer. I know you guys seem to love hash tables, but that seems to be a lot of overhead for a simple array. Can you help?

—PT

Hey, Scripting Guy! Answer Hello PT,

Microsoft Scripting Guy, Ed Wilson, is here. You are right. You are also right, and unfortunately, you are right—but I can help solve that problem. OK, maybe I had better explain a bit. You are right, arrays in Windows PowerShell are simple, and in fact, they are so simple that many people do not bother to talk about how simple they are. It is also true that Windows PowerShell loves hash tables, but the same is true for arrays. In fact, Windows PowerShell loves arrays so much that they are incredibly easy to use.

Note: This is part two of a multiple blog series about working with arrays and hash tables for data storage. In yesterday’s Hey, Scripting Guy! Blog, Learn Simple Ways to Handle Windows PowerShell Arrays, I discussed creating arrays, indexing into arrays, and two techniques for walking through an array.

Working with specific array elements

One of the interesting things about arrays in Windows PowerShell is they are able to hold different data types. For example, I can store numbers and strings in the same array as shown here.

PS C:\> $a = 1,2,3,”four”

PS C:\> $a

1

2

3

Four

Changing element values

If I need to change an element in array, I can index into the array by using the square bracket and the index number. To find the upper boundary, I use the GetUpperBound method, and when I have that value, I can easily find the element I need to modify. This technique is shown here.

PS C:\> $a.GetUpperBound(0)

3

PS C:\> $a[3] = 4

PS C:\> $a

1

2

3

4

Adding a new element to an existing array

If I want to add an element to an existing array, it might make sense to choose the next index number, and attempt to assign a value in the same way that I change an existing value. When I do this, however, Windows PowerShell generates an out of range error message. This command and error message are shown here.

PS C:\> $a[4] = 12

Array assignment failed because index ‘4’ was out of range.

At line:1 char:4

+ $a[ <<<< 4] = 12

    + CategoryInfo          : InvalidOperation: (4:Int32) [], RuntimeException

    + FullyQualifiedErrorId : IndexOutOfRange

The way to add a new element to an existing array is to use the += operator as shown here.

$a += 12

The commands to create an array, get the upper boundary of an array, change an element in an array, and add a new element to an array are shown here with their associated output.

Image of script

Searching for a specific value in an array

One question that comes up from time-to-time is, “How do I know whether a value is contained in an array?” The answer is, once again, rather easy, “Use the Contains operator”. The following two commands use the previously created $a array. In the first command, the number 12 is present, and the value True returns. In the second example, the array does not contain the number 14; and therefore, the returned value is False.

PS C:\> $a -contains 12

True

PS C:\> $a -contains 14

False

PS C:\>

Sorting an array

Now suppose I need to sort my array. There are actually two ways to do this. The first way to do this is to use the Sort-Object cmdlet (Sort is an alias for the Sort-Object cmdlet). The second way to sort an array is to use the static Sort method from the System.Array .NET Framework class.

Use Sort and the pipeline

The first technique I will discuss is also the easiest to use. It is the pipeline method. All that this technique requires is to pipe the array to the cmdlet. This technique is shown here.

PS C:\> [int[]]$a = 1,5,7,2,12,4

PS C:\> $a | Sort-Object

1

2

4

5

7

12

The thing to keep in mind is that this does not change the array, it merely changes the display output. If I want to modify the actual array, I need to write the results back to the original array. This technique is shown here.

PS C:\> $a = $a | sort

PS C:\> $a

1

2

4

5

7

12

The commands to create an array of integers, sort the results with the Sort-Object cmdlet, and write the results back to the array are shown in the following image.

Image of script

Use Get-Random to create a random array

One of my favorite tricks is to create an array of numbers by using the Get-Random cmdlet. To do this, I use Count to specify the number of values to select, and I use a range operator to create an array of numbers from which to choose. I then write the random values to a variable. This technique is shown here.

$rnd = Get-Random -Count 10 -InputObject (1..100000)

Use the static Sort method

To sort the random numbers, I use the Sort static method from the System.Array .NET Framework class. Because Sort is a static method, I need to use a double colon separator between the class name (in square brackets) and the method name. I supply the array of random numbers as an input value. This command is shown here.

[array]::sort($rnd)

What is really interesting is that the Sort static method, automatically writes the sorted values back to the array that is contained in the $rnd variable. The commands to create a random array of numbers, display those values, sort the array, and display the sorted list are shown in the following image.

Image of script

Measuring the difference in performance

“So, what is the difference between the two ways to sort arrays,” you may ask. The difference is that the pipeline way of sorting is probably more intuitive to Windows PowerShell users. The other difference is that the static Sort method from the System.Array class is way faster. To check this, I like to use the Measure-Command cmdlet. To ensure I have a large enough data set that will take a decent amount of time to sort, I create two random arrays by using the commands that are shown here.

$arrayA = Get-Random -Count 1000000 -InputObject (1..1000000)

$arrayB = Get-Random -Count 1000000 -InputObject (1..1000000)

Next, I use the Measure-Command cmdlet to measure the two ways of sorting arrays. The two commands are shown here.

Measure-Command -Expression { $arrayA = $arrayA | Sort-Object }

Measure-Command -Expression { [array]::Sort($arrayB) }

On my system (which is a fast computer), the first command takes a little over 40 seconds, whereas the second command takes a little more than 8 seconds. Therefore, the second command appears to be five times faster than the first command that uses the pipeline.

The commands that create the two random arrays use Measure-Command to check the speed of the two commands, and they display the first two numbers in each of the newly sorted arrays, as shown in the following image.

Image of script

Sorting arrays that contain multiple types

There is one more caveat when it comes to using the two sort methods. Because an array in Windows PowerShell can contain different types, the Sort-Object method may be the preferred way of sorting objects. This is because in using the default comparer, the Sort static method fails when the array contains different types.

In the following example, I create an array that contains both integers and strings. I then pipe the array to the Sort-Object cmdlet (using Sort as the alias). Next, I attempt to use the static Sort method from the System.Array class, and that generates an error message.

PS C:\> $array = 1,2,9,8,3,”four”,”tree”,”Cat”,”bat”

PS C:\> $array | sort

1

2

3

8

9

bat

Cat

four

tree

PS C:\> [array]::sort($array)

Exception calling “Sort” with “1” argument(s): “Failed to compare two elements in the array.”

At line:1 char:14

+ [array]::sort <<<< ($array)

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : DotNetMethodException

 

PS C:\>

Because an array can contain other objects (besides strings and integers), I decide to perform one additional test, and I therefore store an instance of the System.Diagnostics.Process .NET Framework class in the last element. This command is shown here.

PS C:\> $array = 1,2,9,8,3,”four”,”tree”,”Cat”,”bat”,(get-process winword)

PS C:\> $array

1

2

9

8

3

four

tree

Cat

bat

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

——-  ——    —–      —– —–   ——     — ———–

    463      62    41772      89736   369    39.17   4460 WINWORD

Next, I decide to sort the array. Once again, the Sort-Object cmdlet comes through with no problems. This output is shown here.

PS C:\> $array | sort

1

2

3

8

9

bat

Cat

four

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

——-  ——    —–      —– —–   ——     — ———–

    463      62    41772      89736   369    39.17   4460 WINWORD

tree

 

 

PS C:\>

 

PT, that is all there is to modifying values in an array, adding to an array, checking to see if an array contains a specific value, and sorting the array. Array Week will continue tomorrow when I will store different types of objects in an array (including other arrays). It will be fun and educational. See ya!

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 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.