Powershell V2 – CannotIndex error when working with arrays

Ever had the cannotindex runtime exception when working with powershell arrays?

I present the following situation:

Create three .txt files and verify their creation with get-childitem *.txt.

PS C:\Users\administrator.HOMELAB> echo 1 > 1.txt
PS C:\Users\administrator.HOMELAB> echo 2 > 2.txt
PS C:\Users\administrator.HOMELAB> echo 3 > 3.txt

PS C:\Users\administrator.HOMELAB> Get-ChildItem *.txt

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 1.txt
-a---        10/27/2013   7:12 PM          8 2.txt
-a---        10/27/2013   7:12 PM          8 3.txt

Now place the result of get-childitem in a variable called txt and query the different elements in the array.

PS C:\Users\administrator.HOMELAB> $txt = Get-ChildItem *.txt
PS C:\Users\administrator.HOMELAB> $txt[0]

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 1.txt

PS C:\Users\administrator.HOMELAB> $txt[1]

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 2.txt

PS C:\Users\administrator.HOMELAB> $txt[2]

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 3.txt

PS C:\Users\administrator.HOMELAB> $txt[-1]

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 3.txt

Everything seems to work fine. Now remove the first two files, only leaving 3.txt.

PS C:\Users\administrator.HOMELAB> del .\1.txt
PS C:\Users\administrator.HOMELAB> del .\2.txt

PS C:\Users\administrator.HOMELAB> Get-ChildItem *.txt

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 3.txt

Again place the result of get-childitem in a variable called txt and query the different elements in the array.

PS C:\Users\administrator.HOMELAB> $txt = Get-ChildItem *.txt
PS C:\Users\administrator.HOMELAB> $txt[0]
Unable to index into an object of type System.IO.FileInfo.
At line:1 char:6
+ $txt[ <<<< 0]
    + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
    + FullyQualifiedErrorId : CannotIndex

This time an error is thrown. What happened?

The unable to index into an object of type System.IO.FileInfo line gives an important clue. We are dealing with a different type of object than before.

On this occasion get-childitem *.txt returns only one result which seems to cause the $txt variable to become a System.IO.FileInfo object.

PS C:\Users\administrator.HOMELAB> Get-Member -InputObject $txt

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
Mode                      CodeProperty   System.String Mode{get=Mode;}
AppendText                Method         System.IO.StreamWriter AppendText()
CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(s...
[..removed for brevity..]

 

The solution is to enforce the creation of an array when creating $txt by using the following syntax:

PS C:\Users\administrator.HOMELAB> $txt = @(Get-ChildItem *.txt)

This time the $txt is a System.Object even when get-childitem returns only one result.

PS C:\Users\administrator.HOMELAB> Get-Member -InputObject $txt

   TypeName: System.Object[]

Name           MemberType    Definition
----           ----------    ----------
Count          AliasProperty Count = Length
Address        Method        System.Object&, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934...
Clone          Method        System.Object Clone()
[..removed for brevity..]

Querying elements in the array works as expected:

PS C:\Users\administrator.HOMELAB> $txt[0]

    Directory: C:\Users\administrator.HOMELAB

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        10/27/2013   7:12 PM          8 3.txt

PS C:\Users\administrator.HOMELAB>

The lesson here is: if you expect the results in an array make sure you create an array.

p.s. Powershell V3 seems to handle this more graciously.