Array or no array in Powershell? Why using @(…) is a good idea.

Here’s a funny thing in Powershell:

PS C:\> cd C:\WINDOWS\system32
PS C:\WINDOWS\system32> (dir *.dll).GetType()

IsPublic IsSerial Name                           BaseType
-------- -------- ----                           --------
True     True     Object[]                       System.Array

PS C:\WINDOWS\system32> (dir kernel32.dll).GetType()

IsPublic IsSerial Name                           BaseType
-------- -------- ----                           --------
True     True     FileInfo                       System.IO.FileSystemInfo

PS C:\WINDOWS\system32>

See what’s happening? If dir (or actually Get-ChildItem) finds several items matching our criteria then it returns an array, which is what you’d expect. But if the cmdlet finds just a single item then that item is returned directly instead of being encapsulated into an array. If you’re unexperienced with Powershell then that’s probably not what you’re expecting.

For example, this script will not always work as expected:

if ((dir *.dll).Length -gt 1) { 'many items' }

If there is more than 1 matching item then all will be fine, but if exactly one item is found then that script will break. And worse, it will break without the user noticing since no exception is thrown. It will simply print out ‘many items’ in this case, even though there is just one item. To understand why, try this:

PS C:\WINDOWS\system32> (dir kernel32.dll).Length

What happens is that dir returns one item, of type FileInfo, which happens to have a property called Length which contains the size of the file. Thus we’re calling System.IO.FileInfo.Length instead of System.Array.Length… Very confusing!

Fortunately, there’s an easy way to make sure that you always get an array, namely the @(…) construct which does nothing if its expression evaluates to an array and if it doesn’t, encapsulates it into one.


PS C:\WINDOWS\system32> @(dir kernel32.dll).Length
PS C:\WINDOWS\system32> if (@(dir *.dll).Length -gt 1) { 'many items' }

To sum it up: Always use @(…) if you want to work with arrays! Note that this applies to all cmdlets, not just Get-Childitem!


Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.