Often times when writing PowerShell scripts, you need a way to store a set of items. One common way to achieve this is with an array or specific type known as an ArrayList. But what is an array anyway? An array is a data structure that is designed to store a collection of items. This can include both same and different types of items.
Not a reader? Watch this related video tutorial!Arrays are used in many different programming languages and PowerShell is no different. There are many ways to create, manipulate, and optimize arrays. In this article you will learn about ArrayLists, Arrays, and Collections as well as some best practices when applying them with PowerShell.
Prerequisites/Requirements
Since you’ll just be working with the PowerShell language itself, there are no environmental prerequisites. You just need to have a Windows PC with PowerShell. More specifically:
- Windows PowerShell 3 or later
- .NET Framework 4.5 or later
Want more tips like this? Check out my personal PowerShell blog at: https://nkasco.com/FriendsOfATA
Creating Arrays with PowerShell
There are many different ways to create arrays with PowerShell. Let’s assume you have a list of names that you need to process somehow as shown below.
John
Susie
Jim
Johnny
Carrie
Building Arrays via Comma-Separated Elements
The most basic way you can create an array is to simply assign known inputs, comma-separated, to a variable as shown below.
$BasicArray = "John", "Susie", "Jim", "Johnny", "Carrie"
If you run the GetType()
method available on all objects in PowerShell, you will see that you have successfully created an array as indicated by the BaseType
property shown below.
PS51> $BasicArray.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Using the Sub-Expression Operator
You can also create arrays in PowerShell via a sub-expression operator. This concept is commonly used when you don’t know how many items will be added to your array. The result can contain zero, or many items when created.
Notice below an array called $MyArray
has been created with zero elements inside.
#Create an empty array with the sub-expression operator
PS51> $MyArray = @()
PS51> $MyArray.count
0
Using the Range Operator
Arrays aren’t just relegated to storing strings as shown above. You can also create arrays with other object types like integers.
If you need an array of integers in sequential order, you can take a shortcut and use the range ..
operator. Below you can see an array was created with the integers 2 through 5 with a single line of code.
PS51> $NumberedArray = 2..5
PS51> $NumberedArray
2
3
4
5
Creating PowerShell ArrayList Collections
Using a PowerShell ArrayList is also a way in which you can store a list of items with PowerShell. The ArrayList class is part of the System.Collections namespace within .NET. By creating a new object of this type you can then store objects within an ArrayList.
Below you can see that you need to explicitly create an ArrayList object using the New-Object
cmdlet or by casting a standard array to an ArrayList object.
Notice that in this case the BaseType
is an object whereas the above examples have BaseTypes of Arrays which exhibit inheritance from the Object class. Ultimately, PowerShell is providing access to the .NET type system.
PS51> $MyArrayList = New-Object -TypeName "System.Collections.ArrayList"
# Casting an array as an ArrayList is also a viable option
PS51> $MyArrayList = [System.Collections.ArrayList]@()
PS51> $MyArrayList.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ArrayList System.Object
Adding Items To An Array
When creating an array, you can either define all of the elements at creation time or add them ad-hoc.
To add elements to an existing collection, you can use the +=
operator or the Add
method. But know that there are major differences to how they operate.
When you create a standard array with @()
, you’ll use the +=
operator but to add elements to an ArrayList, you’d use the Add
method. These methods differ in that the +=
operator actually destroys the existing array and creates a new one with the new item.
To demonstrate, you’ll see below you can reference the IsFixedSize
property for an array or ArrayList to know which is immutable and which is not.
PS51> $BasicArray.IsFixedSize
True
PS51> $MyArrayList.IsFixedSize
False
Since a basic array is a collection of fixed size, you cannot modify it.
Attempting to use the Add()
method with an array that is fixed size will result in an error due to the fixed size. Below you can see a few examples in which you can successfully add items to an array.
#Does NOT work
$BasicArray.Add("Nate")
#Works
$BasicArray += "Nate"
$MyArrayList.Add("Nate")
$MyArrayList += "Nate"
Removing Items From An Array
Now that you have a better understanding of how to add items to an array, let’s cover a few ways you can remove items from an array.
Since a basic array is fixed, you cannot remove items from them. Instead, you have to create an entirely new array. For example, you can remove a single element from an array by creating a conditional statement that only matches those elements you’d like to include. An example is shown below.
$NewBasicArray = $BasicArray -ne "Nate"
Since an ArrayList isn’t fixed, you can remove elements from them using the Remove()
method. This is one scenario in which using an ArrayList may benefit you if you plan to be frequently adding/removing items.
$MyArrayList.Remove("Nate")
Retrieving Specific Items From An Array or ArrayList
To retrieve specific items from an array or ArrayList you can use many different methods. Much like other objects in PowerShell, you can access all elements of an array by simply calling the object.
PS51> $BasicArray
John
Susie
Jim
Johnny
Carrie
Perhaps you need to only retrieve the first element, arrays will always have an origin of 0 representing the first element of the array. To retrieve the first element of an array, specify the index number in brackets as shown below.
PS51> $BasicArray[0]
John
Conversely, you can also reference indexes backwards by using a dash (negative indicator) to call the last X number of elements from the array. A common way to find the last element in an array is using -1
as shown below.
PS51> $BasicArray[-1]
Carrie
The range operator that you learned about above can also be used to retrieve objects of an array by following the same method of calling the elements. Let’s say you want to retrieve the first four names in the $BasicArray
array.
You can see below you can specify a range of indexes 0-3 which will return the first four elements.
PS51> $BasicArray[0..3]
John
Susie
Jim
Johnny
Optimizing Arrays with PowerShell
Now that you have a good foundation of how to create and manipulate arrays, which one should you use? To answer that, let’s walk through a few examples with the Measure-Command
cmdlet. Using the Measure-Command
cmdlet, you’ll better understand how long commands are taking to process elements as they are passed down the pipeline.
Generally speaking, if you have a small collection of objects you likely won’t notice much difference with how you manipulate your arrays. However, if you have a large collection of objects it is important to understand the differences to achieve optimal results.
Let’s apply what you just learned in the prior section about the difference between +=
and using the Add()
method with a loop of 50,000 items.
First, create an empty array and an empty ArrayList as shown below.
PS51> $MyArray = @()
PS51> $MyArrayList = [System.Collections.ArrayList]@()
Next, populate 50,000 elements in each collection using the range operator and a foreach loop as shown below.
@(0..50000).foreach({$MyArray += $_})
@(0..50000).foreach({$MyArrayList.Add($_)})
Finally, wrap your commands in an expression and pass that expression to the Measure-Command
cmdlet. By executing the expression with Measure-Command
, you can see how long each process actually takes to execute.
Keep in mind that as you learned before,
+=
actually creates a new array rather than appending to a fixed one.
PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArray += $_})}
Days : 0
Hours : 0
Minutes : 0
Seconds : 59
Milliseconds : 58
Ticks : 590585963
TotalDays : 0.000683548568287037
TotalHours : 0.0164051656388889
TotalMinutes : 0.984309938333333
TotalSeconds : 59.0585963
TotalMilliseconds : 59058.5963
PS51> Measure-Command -Expression {@(0..50000).foreach({$MyArrayList.Add($_)})}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 139
Ticks : 1399989
TotalDays : 1.62035763888889E-06
TotalHours : 3.88885833333333E-05
TotalMinutes : 0.002333315
TotalSeconds : 0.1399989
TotalMilliseconds : 139.9989
The result? Nearly 60 seconds versus 139 milliseconds!
As you can see, it is much faster to leverage an ArrayList for large collections rather than using a fixed-size array.
While this is a basic example, it stresses the importance of understanding what your code is doing during processing. If not properly understood, it can result in a poor user experience.
If you have any existing script that could benefit from using an ArrayList rather than an array, this would present a fantastic opportunity to make an overnight improvement!
Further Reading
Want more tips like this? Check out my personal PowerShell blog at: https://nkasco.com/FriendsOfATA.