Well, there is a mistake. (I just wrote a page on the PoshCode Wiki about this yesterday, and thereβs a connection error ).
Answers first, more questions later:
To get the consistent behavior of arrays with -f string formatting, you will need to make 100% sure that they are PSObjects objects. My suggestion is to do this when they are appointed. It is assumed that this will be done automatically using PowerShell, but for some reason this will not be done until you get access to the property or something (as described in this wiki page and the error ). For example, ( <##> is my invitation):
<##> $a = 1,2,3 <##> "$a" 1 2 3 <##> $OFS = "-" # Set the Output field separator <##> "$a" 1-2-3 <##> "{0}" -f $a 1 <##> $a.Length 3 <##> "{0}" -f $a 1-2-3 # You can enforce correct behavior by casting: <##> [PSObject]$b = 1,2,3 <##> "{0}" -f $a 1-2-3
Note that when you do this, they will NOT be expanded when passed to -f, but rather will be displayed correctly - just as they would if you put the variable in a string directly.
Why is case No. 3 not suffering the same fate as # 4? $ rhs should contain a nested array (, ("a", "a")), but its outer level expands ... somewhere ...
A simple version of the answer is that BOTH # 3 and # 4 are deployed. The difference is that in 4 the internal content is an array (even after the external array has been reversed):
$rhs = "a" | SquareAndWrap $rhs[0].GetType()
What happens to the different grouping operators in # 9-10? Why do they behave so randomly and why are they even needed?
As I said before, an array should be considered the only parameter in the format and should be output using PowerShell string formatting rules (i.e. separated by $OFS ) just as if you entered $ _ into the string directly ... so when PowerShell behaves correctly, $lhs -f $rhs will fail if $ lhs contains two-local holders.
Of course, we have already noticed that there is an error in it.
I don't see anything messy: @ () and $ () work the same for 9 and 10, as far as I can see (the main difference, in fact, is related to how ForEach expands the top-level array:
> $rhs = "a", "b" | SquareAndWrap > $rhs | % { $lhs -f @($_); " hi " } aa hi bb hi > $rhs | % { $lhs -f $($_); " hi " } aa hi bb hi
So, you see the error: @ () or $ () will cause the array to be passed as [object []] to the string format call instead of PSObject, which has special values ββin the string.
Why are failures in the case of the 10th degradation graceful as # 4?
This is basically the same mistake, in a different manifestation. Arrays should never appear as "System.Object []" in PowerShell unless you manually name your own .ToString () method or pass them directly to String.Format () ... the reason they do in # 4 is an error: PowerShell was unable to extend them as PSOjbects before passing them to a String.Format call.
This can be seen if you accessed the property of the array before passing it, or passed it to PSObject, as in my original exams. Technically, errors in # 10 are the correct conclusion: you only pass ONE thing (array) to string.format when it expected TWO. If you change $ lhs to "{0}", you will see an array formatted with $ OFS
It is interesting, however, what kind of behavior are you like and which, in your opinion, is correct , given my first example? I think that the output signal of $ OFS is correct, as opposed to expanding the array, as it happens if you @ (wrap) it or pass it [object []] (by the way, note what happens if you add it to [ int []] is another error behavior):
> "{0}" -f [object[]]$a 1 > "{0}, {1}" -f [object[]]$a
Iβm sure that many scripts were written unconsciously using this error, but it still seems clear to me that the deployment that happens with a simple example is NOT the right behavior, but because, on a call (inside the PowerShell core), .Net String.Format( "{0}", a ) ... $a is object[] , which is what String.Format is supposed to be like as a parameter to Params ...
I think this should be fixed. If there is a desire to preserve the "functionality" of array expansion, this should be done using the @splatting operator, right?