Better PoSH: Avoid Using += for Arrays

Share on:

I've found myself hanging around some PowerShell chats lately, and I've been picking up on a lot of neat tricks to write better code. This one comes my way via Adam Cook from his blog post on his awesome new function Get-CMUnusedSources (seriously, if you're a ConfigMgr shop, check it out).

Since PowerShell is one of those languages we learn as we read other's code and hack things together (at least to start), it's easy to pick up on ways of doing things that are quick, but might not be the best idea in terms of performance. Most of the time it's insignificant as it'll barely matter on smaller scripts, but it's always a good idea in this bloggers opinion to get into good habits for when you do start writing larger and more complex scripts.

Let's start with a script that takes a folder, collects the files, and then adds each file to a list.

1$windowsFiles = Get-ChildItem $env:windir\system32 -ErrorAction SilentlyContinue
2
3$fileList = @()
4
5Measure-Command {
6    ForEach($file in $windowsFiles) {
7        $fileList += $file.FullName
8    }
9}

What's happening here after I collect the files with Get-ChildItem is that I'm then looping over the results to update the array. It may seem like I'm just updating the same array over and over again, but what's really happening is that I'm making a copy of the array and adding one item. Then I do this for every single file in $windowsFiles, which takes a very long time. In fact, we can prove that our array isn't dynamic (and so cannot be directly updated) by trying to add a new item to it:

1$fileList.add("test")

Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."

Instead, as Andy Svints explains in his blog post, we should use an ArrayList when possible. Here is the same snippet above written

1$windowsFiles = Get-ChildItem $env:windir\system32 -ErrorAction SilentlyContinue
2
3$fileList = New-Object System.Collections.ArrayList
4
5Measure-Command {
6    ForEach($file in $windowsFiles) {
7        $fileList.Add($file.FullName)
8    }
9}

The performance impact is amazing. While constantly recreating the static array took over 2,700ms to add about 9,500 items, the dynamic ArrayList took just 14ms.



No comments