Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Baffled by v2 advanced functions

9 views
Skip to first unread message

Bern McCarty

unread,
Nov 23, 2009, 3:04:02 PM11/23/09
to
The below advanced function works as I would expect. But if you remove the
line of code that makes the nonsensical access to $MyArrayArgument.Length
then it longer works the same way. Why?

Example of the function in action:

Echo-ArgValue 'one','two'
$MyArrayArgument:one two

But when you take that line of code out it changes thus:

Echo-ArgValue 'one','two'
$MyArrayArgument:one

function Echo-ArgValue {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$true)]
[string[]]
$MyArrayArgument
)
[void]$MyArrayArgument.Length
write-host('$MyArrayArgument:{0}' -f $MyArrayArgument)
}

So what is the ideal way to get the desired (first) behavior?

--
Bern McCarty
Bentley Systems, Inc.

stej

unread,
Nov 24, 2009, 2:22:45 AM11/24/09
to
From my point of view (I'm programmer) you use the variable
incorrectly. Type of the variable is [string[]] but I assume that only
non-collection objects should be passed as argument to -f
If you try
write-host('$MyArrayArgument:{0}' -f ($MyArrayArgument -join ","))
it works.

However, I would be very curious what's the reason why the
[void...Length statement causes that it works.

Larry__Weiss

unread,
Nov 24, 2009, 11:17:16 AM11/24/09
to
What is function Echo-ArgValue is supposed to do?

- Larry

Bern McCarty

unread,
Nov 24, 2009, 2:29:01 PM11/24/09
to

It is supposed to demonstrate an apparent bug. Nothing more. I am very
surprised that the behavior of this script cmdlet changes dramatically based
on whether or not the Length property of the string[] cmdlet parameter is
accessed.

Two very different behaviors are observed. They cannot both be right can
they? If they are indeed both right, what is the explanation for that? If
not, which behavior is right and which one is the bug? If it is a bug then an
explanation of the bug could lead to learning how to better live with it.


--
Bern McCarty
Bentley Systems, Inc.


"Larry__Weiss" wrote:

> .
>

Robert Robelo

unread,
Nov 24, 2009, 5:03:23 PM11/24/09
to
The peculiarity is the way the Format operator treats an array passed to it.

[String[]]$x = 'a','b','c'
# $x is treated as the Array passed to the Format operator
'{0}' -f $x # outputs: a
'{0} {1}' -f $x # outputs: a b
'{0} {1} {2}' -f $x # outputs: a b c

# when an object's member is called -even a nonexistent one- PowerShell
# wraps the object in a [PSObject] in order to look for Extended Type
# System (ETS) information relevant to the object's type. Then the new
# object is treated as one element in the Array passed to the Format
# operator

Trace-Command ETS {$x.none} -PSHost
'{0}' -f $x # outputs: a b c

# to work around this Format operator oddity, the array you want to be
# treated as an element should be cast as a [PSObject]
[String[]]$x = 'a','b','c'
'{0}' -f $x # outputs: a
'{0}' -f [PSObject]$x # outputs: a b c


You could also write the function without the Format operator like this:

function Echo-ArgValue {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline=$true)]
[string[]]
$MyArrayArgument
)
write-host `$MyArrayArgument:$MyArrayArgument
}

Echo-ArgValue 'one','two'

--
Robert

Larry__Weiss

unread,
Nov 24, 2009, 6:26:15 PM11/24/09
to
I have simplified this down to the code below that seems to clearly show the
unexpected side-effect.

function show-bug {
$A = 'one','two'
'$A:{0}' -f $A
$A.length
'$A:{0}' -f $A
}

It is interesting that this variation also shows the bug

function show-bug {
$A = 'one','two'
'$A:{0}' -f $A
$A.xxxxxxxxxxxxxxxxx
'$A:{0}' -f $A
}

- Larry

Vadims Podans [MVP]

unread,
Nov 25, 2009, 11:49:48 AM11/25/09
to
this is expected behavior, because both lines uses the same pipeline and
your code is the same as:
$MyArrayArgument.Length, '{0}','{1}' -f $MyArrayArgument

you may check this in another way. Type in console this:
gps explorer
dir | ft

looks pretty well? Try this:
function test {
gps explorer
dir | ft
}

and call this function. This is the same as:
gps explorer; dir | ft
--
WBR, Vadims Podans
MVP: PowerShell
PowerShell blog - www.sysadmins.lv

"Bern McCarty" <Be...@newsgroups.nospam> rakstīja ziņojumā
"news:FDE48D2C-7335-4090...@microsoft.com"...

Larry__Weiss

unread,
Nov 25, 2009, 12:14:30 PM11/25/09
to
Execute this sequence at the command prompt.

$A = 'one','two'
'$A:{0}' -f $A
$A.xxxxxxxxxxxxxxxxx
'$A:{0}' -f $A

$A = 'one','two'
'$A:{0}' -f $A
$A.xxxxxxxxxxxxxxxxx
'$A:{0}' -f $A

I don't see how a pipeline is involved.

- Larry

Vadims Podans [MVP]

unread,
Nov 25, 2009, 1:36:59 PM11/25/09
to

ok, look here:

$A = 'one','two'
'$A:{0}' -f $A
# because $a is an array, formatter operator casts only first element to
{0}. Right now, next commands:

$A.xxxxxxxxxxxxxxxxx
'$A:{0}' -f $A
# will return $A:one two. Why? Because this is the same as:
$A.xxxxxxxxxxxxxxxxx, $A:{0} -f $A
# or just:
, $A:{0} -f $A
#and here is an answer.

--
WBR, Vadims Podans
MVP: PowerShell
PowerShell blog - www.sysadmins.lv

"Larry__Weiss" <l...@airmail.net> rakstīja ziņojumā
"news:u21uELfb...@TK2MSFTNGP06.phx.gbl"...

Larry__Weiss

unread,
Nov 25, 2009, 3:04:31 PM11/25/09
to

'$A:{0}' -f $A

should be equivalent to

[string]::Format('$A:{0}',$A)

And this sequence seems to work out more consistently to what I'd expect

$A = 'one','two'

[string]::Format('$A:{0}',$A)
$A.xxxxxxxxxxxxxxxxx
[string]::Format('$A:{0}',$A)

as executed below

PS C:> $A = 'one','two'
PS C:> [string]::Format('$A:{0}',$A)
$A:one
PS C:> $A.xxxxxxxxxxxxxxxxx
PS C:> [string]::Format('$A:{0}',$A)
$A:one
PS C:>

and again, coding it with

'$A:{0}' -f $A

I get

PS C:> $A = 'one','two'
PS C:> '$A:{0}' -f $A
$A:one
PS C:> $A.xxxxxxxxxxxxxxxxx
PS C:> '$A:{0}' -f $A
$A:one two
PS C:>

Am I right that these two are equivalent?
'$A:{0}' -f $A
[string]::Format('$A:{0}',$A)

stej

unread,
Nov 26, 2009, 2:35:35 AM11/26/09
to
Vadim, where can I find more about this pipelining? Or 'merging
commands together'?

I'm asking because (these are your examples) I didn't know that


$A.xxxxxxxxxxxxxxxxx
'$A:{0}' -f $A

is the same as
$A.xxxxxxxxxxxxxxxxx, $A:{0} -f $A

stej

Vadims Podans [MVP]

unread,
Nov 26, 2009, 4:55:39 PM11/26/09
to
Now I don't remeber where this was posted. Sorry :(

--
WBR, Vadims Podans
MVP: PowerShell
PowerShell blog - www.sysadmins.lv

"stej" <cerna...@seznam.cz> rakstīja ziņojumā
"news:96559512-7afd-4a6d...@l13g2000yqb.googlegroups.com"...

Larry__Weiss

unread,
Dec 2, 2009, 6:17:29 PM12/2/09
to
Consider the following sequence of commands

PS C:> $b = 7,8,9
PS C:> '[{0}]' -f $b
[7]
PS C:> '[{0}]' -f $b
[7]
PS C:> '[{0}]' -f $b.length
[3]
PS C:> '[{0}]' -f $b
[7 8 9]
PS C:> '[{0}]' -f $b
[7 8 9]
PS C:>

Why are the last two expansions of
'[{0}]' -f $b
not the same as the first two?

- Larry

Larry__Weiss

unread,
Dec 3, 2009, 8:03:48 PM12/3/09
to
I think I'm going to open a bug report on this at

https://connect.microsoft.com/powershell

- Larry

Larry__Weiss

unread,
Dec 3, 2009, 9:36:04 PM12/3/09
to
Here's an extra wrinkle

PS C:> $b = 7,8,9
PS C:> '[{0}]' -f $b
[7]

PS C:> '[{0}]' -f $b.length
[3]
PS C:> '[{0}]' -f $b
[7 8 9]

PS C:> $b = $b


PS C:> '[{0}]' -f $b
[7]
PS C:>

Stranger and stranger!

- Larry


Larry__Weiss wrote:
> I think I'm going to open a bug report on this at
> https://connect.microsoft.com/powershell
>

Larry__Weiss

unread,
Dec 3, 2009, 9:49:38 PM12/3/09
to
Another experiment I can't explain the why of:

PS C:> $b = 7,8,9

PS C:> '[{0}][{1}][{2}]' -f $b
[7][8][9]


PS C:> '[{0}]' -f $b.length
[3]

PS C:> '[{0}][{1}][{2}]' -f $b
Error formatting a string: Index (zero based) must be greater than or equal to
zero and less than the size of the argument list..
At line:1 char:21
+ '[{0}][{1}][{2}]' -f <<<< $b
+ CategoryInfo : InvalidOperation: (7 8 9:PSObject) [], RuntimeEx
ception
+ FullyQualifiedErrorId : FormatError

PS C:> '[{0}][{1}][{2}]' -f @($b)


[7][8][9]
PS C:>

- Larry

Larry__Weiss wrote:
> Here's an extra wrinkle
>
> PS C:> $b = 7,8,9
> PS C:> '[{0}]' -f $b
> [7]
> PS C:> '[{0}]' -f $b.length
> [3]
> PS C:> '[{0}]' -f $b
> [7 8 9]
> PS C:> $b = $b
> PS C:> '[{0}]' -f $b
> [7]
> PS C:>
>
> Stranger and stranger!
>
>

Larry__Weiss

unread,
Dec 4, 2009, 4:45:42 PM12/4/09
to
I opened a new bug issue at

https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=518276
"-f format operator bug when right-side value is an array variable"

Please leave feedback there if you can reproduce it, and/or, have comments to share.

Thx!

- Larry

Oisin (x0n) Grehan [MVP]

unread,
Dec 4, 2009, 9:04:58 PM12/4/09
to
> > not the same as the first two?- Hide quoted text -
>
> - Show quoted text -

Definitely a bug Larry.

PS C:\projects\powershell> $b = [int[]]@(1,2)

PS C:\projects\powershell> $b.gettype()

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

PS C:\projects\powershell> "{0}" -f $b
System.Int32[]

PS C:\projects\powershell> $b.length
2

PS C:\projects\powershell> "{0}" -f $b
1 2

Well spotted. I've notified the team and will report back.

-Oisin

www.nivot.org
PowerShell MVP

Larry__Weiss

unread,
Dec 4, 2009, 9:49:56 PM12/4/09
to

I opened a new bug issue that is related to this at


https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=518276
"-f format operator bug when right-side value is an array variable"

- Larry

Vadims Podans [MVP]

unread,
Dec 7, 2009, 4:58:07 AM12/7/09
to
voted. Now I see that this is a bug. Strange..

--
WBR, Vadims Podans
MVP: PowerShell
PowerShell blog - www.sysadmins.lv

"Larry__Weiss" <l...@airmail.net> rakstija zinojuma
"news:uTAzjWVd...@TK2MSFTNGP06.phx.gbl"...

Vadims Podans [MVP]

unread,
Dec 7, 2009, 4:59:01 AM12/7/09
to
This is another reason to not use -f operatur while it is not strongly
required.

--
WBR, Vadims Podans
MVP: PowerShell
PowerShell blog - www.sysadmins.lv

"Larry__Weiss" <l...@airmail.net> rakstija zinojuma
"news:uTAzjWVd...@TK2MSFTNGP06.phx.gbl"...

Joel (Jaykul) Bennett

unread,
Dec 8, 2009, 6:09:47 PM12/8/09
to
I voted for the bug too. But to clear things up, I think that what's
happening is the array is NOT being wrapped as a PSObject at first.
The BUG is the original behavior where $b is being splatted even
though the splat operator wasn't used. Consider:

> $a = 1,2,3

# THIS is what we expect when we put an array in a string in
PowerShell
> "$a"
1 2 3

# THIS is therefore a bug
> "{0}" -f $a
1

# So is this:
> "{0},{1}" -f $a,"one"
System.Object[],one

I originally posted a "workaround" to use @() as a fix -- it causes
the original behavior every time by splatting the array ... but I
realized afterward that THAT is the buggy behavior:

# This isn't the way arrays are supposed to get formatted:
> "{0},{1}" -f @($a),"one"
System.Object[],one

# THIS is the way arrays are supposed to get formatted:
> "{0},{1}" -f ([PSObject]$a),"one"
1 2 3,one


You can force this behavior by always casting arrays to [PSObject]
before using them. You can even strong type them too:

> [PSObject][Int[]]$a = 1,2,3
> "$a"
1 2 3
> $OFS = "-"
> "$a"
1-2-3
> "{0} {1}" -f $a, "GO!"
1-2-3 GO!

--
Joel "Jaykul" Bennett
http://HuddledMasses.org
Upstate NY PowerShell UserGroup:
http://upnypug.wordpress.com

Larry__Weiss

unread,
Dec 8, 2009, 6:41:40 PM12/8/09
to
According to my reading of my copy of Bruce Payette's book
"PowerShell in Action"

"{0}" -f $a
should be equivalent to
[string]::Format('{0}',$a)

And, in fact that's what I get:

PS C:> $a = 1,2,3
PS C:> "{0}" -f $a
1
PS C:> [string]::Format('{0}',$a)
1

Yet, using the cast to [PSObject]

PS C:> $a = 1,2,3
PS C:> "{0}" -f [PSObject]$a
1 2 3
PS C:> [string]::Format('{0}',[PSObject]$a)
1

Should that last command have output
1 2 3
as well ?

- Larry

0 new messages