Can someone explain why this script throws an exception?
$byteArray = @(1,2,3)
write-Output ( "{0:X}{1:X}{2:X}" -f $byteArray )
write-Output ( $byteArray.Length -ge 3 )
write-Output ( "{0:X}{1:X}{2:X}" -f $byteArray )
Basically, I am creating an array of numbers, formatting the array and then checking its length and formatting it again.
The first format succeeds, but the second format throws an exception.
123
True
--------------------------------------------------------------------------------
POWERSHELL EXCEPTION
EXCEPTION TYPE:System.Management.Automation.RuntimeException
MESSAGE:Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argument list..
POSITION:
At line:4 char:36
+ write-Output ( "{0:X}{1:X}{2:X}" -f <<<< $byteArray )
--------------------------------------------------------------------------------
Count or Length or LongLength To determine how many items are in an array, use the Length property or its Count alias. Longlength is useful if the array contains more than 2,147,483,647 elements.
The array elements are accessed through the index. Array indices are 0-based; that is, they start from 0 to arrayRefVar. length-1.
Array subexpression operator @( )Returns the result of one or more statements as an array. The result is always an array of 0 or more objects. PowerShell Copy.
@{} in PowerShell defines a hashtable, a data structure for mapping unique keys to values (in other languages this data structure is called "dictionary" or "associative array"). @{} on its own defines an empty hashtable, that can then be filled with values, e.g. like this: $h = @{} $h['a'] = 'foo' $h['b'] = 'bar'
To add to the puzzle:
PS > $a = @(1,2,3)
PS > $b = $a
PS > [object]::ReferenceEquals($a, $b)
True
PS > $a.Length
3
PS > [object]::ReferenceEquals($a, $b)
True
PS > "{0:X}{1:X}{2:X}" -f $a
Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argum
ent list..
At line:1 char:21
+ "{0:X}{1:X}{2:X}" -f <<<< $a
PS > "{0:X}{1:X}{2:X}" -f $b
123
PS > $b.GetLength(0)
3
PS > "{0:X}{1:X}{2:X}" -f $b
123
PS > [object]::ReferenceEquals($a, $b)
True
I tend to agree with Jared that it's a quirk of the -f
operator seeing the variable as an object rather than an array, supported in part by this:
PS > $a = @(1,2,3)
PS > "{0:X}{1:X}{2:X}" -f $a
123
PS > "{0:X}{1:X}{2:X}" -f $a.PSObject
Error formatting a string: Index (zero based) must be greater than or equal to zero and less than the size of the argum
ent list..
At line:1 char:21
If the underlying object isn't acceptable as a parameter, then there must be something special about how $a
is originally stored that makes -f
happy. But that still doesn't explain why calling GetLength()
doesn't affect $b
's "arrayness" in the way that Length
(and Rank
) seem to.
As others have noted, using @()
does seem to work consistently.
That's definitely weird. As a workaround you can use
"{0:X}{1:X}{2:X}" -f @($byteArray)
which seems to work even after accessing members of $byteArray
.
Another possible workaround might be to save the formatted string to a variable and re-use it.
As for why it doesn't work after accessing the Length
property I have no idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With