PowerShell Quick Tip: When you store an array, make sure it is an array

It is not uncommon to want to store the results of a command in an array so that you can refer to the contents of that array later in your script.  This is often done by simply assigning the results of a command to a variable.  For example, if you were importing the contents of a csv file into an array you might do it like this:

$collection = Import-Csv C:\newusers.csv

Commands like this will work forever as long as you have a csv file in the appropriate location.  Occasionally though you may find that a script containing this command just stops working.  It might not make sense to you at the time because the script hasn’t changed, so what’s the problem?

The problem is that in the above command there is no guarantee that $collection will actually store an array of objects because there is no guarantee that Import-Csv will return more than one object.  In fact, there is no guarantee that Import-Csv will return any objects at all.  If the C:\newusers.csv file is generated by some other tool, it is possible that it might contain 0, 1 or more entries.  When it contains 0 or 1 entries, the $collection variable will either be $null or it will contain one object representing the single entry in the C:\newusers.csv file, respectively.  If further down in your script you’re always treating $collection as if it is an array and using indices to access elements in the array, your script will suddenly start failing with errors.

Fortunately there is a way to ensure that the results of any command are stored in an array.  All you need to do is wrap the command that returns the object(s) in array enclosures, like this:

$collection = @(Import-Csv C:\newusers.csv)

If you take this approach in your script and then later when you run your script C:\newusers.csv only contains one entry or perhaps doesn’t contain any entries at all, your $collection variable will still be an array so that you can check the size using the Count property ($collection.Count), access individual values using indices (e.g. $collection[0]), etc.  This is a much safer practice to take when writing your scripts so that you can make sure that you have an array when you store an array.

Of course if you are dealing with very large collections of objects that aren’t already loaded in memory an even better practice is to avoid storing the entire collection in memory altogether by using pipelines and cmdlets like ForEach-Object to process the items in the collection, but I wanted to make sure you were aware of how you should properly handle and store arrays in variables in your scripts so that you’re not facing a script long after it has been written and asking yourself why it suddenly stopped working.  There are plenty of other reasons why a script could stop working at some point but at least now you’re armed with the knowledge required to avoid one of those possibilities.

Kirk out.

Share this post:

Advertisements

12 thoughts on “PowerShell Quick Tip: When you store an array, make sure it is an array

  1. Thank you for this very insightful post! I was struggling with this exact issue as I was getting a PSCustomObject instead of an Array when doing a ConvertFrom-csv. My code was working fine until I had only a single record returned which led to the PSCustomObject rather than an array. Thanks again!

    Like

    1. Glad it helped Brad. This issue trips up many people until they learn the trick about using array enclosures to force items to be treated as arrays. I was explaining it to someone else just a few days ago. Fortunately it gets better in PowerShell 3 — you don’t even need the array enclosures there, even if you have only one item, because PowerShell will recognize when you’re expecting something to be an array (for the most part at least). I’ll still be using my array enclosures trick in that version though because it makes for more robust scripts, and it’s a lot easier to see the assumptions being made.

      Like

  2. If you use a conditional to populate, then you also need to declare your variable type explicitly. Eg: [array] $csv = if ($condition) { @(Import-CSV a.csv) } else { @(Import-CSV b.csv) }

    Like

    1. Thanks for highlighting that point. Note though, that you can also wrap the entire condition in an array enclosure, thereby eliminating the need to declare your variable type.

      e.g. $myArray = @(if ($true) {gsv wuauserv} else {gsv bits})

      Kirk out.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s