What am I doing wrong in subexpression?

This topic contains 10 replies, has 4 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 1 year, 8 months ago.

  • Author
    Posts
  • #23759
    Profile photo of GS
    GS
    Participant

    I'm trying to use subexpression and it fails to materialize, what am I doing wrong?

    $a = "A", "AA"
    write-output "Length is $($a|Select -Property length)"

    I would expext output to contain something but it's empty and ends up as "Length is "

  • #23761
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Try Count, not Length. And you probably want -ExpandProperty, not -Property.

  • #23762
    Profile photo of Don Jones
    Don Jones
    Keymaster

    And sorry, that assumes you're wanting the number of objects in $a, not the length of the strings in $a. If you want the lengths of the strings, you may have to re-think a bit, as the output will be an array with the same number of integers (lengths) as the input array as string objects.

  • #23764
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Changing -Property to -ExpandProperty should work. The pipeline will enumerate the array and output the Length of each string. Those lengths will wind up being a space-separated list, by default, since you're then essentially casting an array to a string.

  • #23765
    Profile photo of GS
    GS
    Participant

    I tried length and it still does not work. If I just do write-output $return | Select -Property Length then it works fine, it's just if I wrap it as subexpression inside string where it stops working.

    PS C:\Users\g> $($a|Select -Property Length)
    
                                                                                                                                                                          Length
                                                                                                                                                                          ------
                                                                                                                                                                               1
                                                                                                                                                                               2
    
    
    PS C:\Users\g> "Length is $($a|Select -Property Length)"
    Length is  
    
    
    
    
  • #23769
    Profile photo of Don Jones
    Don Jones
    Keymaster

    It' important to understand that -Property causes Select-Object to still output OBJECTS having, in your case, just one property. PowerShell doesn't have a good way of casting that [b]collection of objects[/b] into a string, which s what the subexpression requires it to do. About the only time the shell will do that successfully is if the objects have a Name property; in v3 and later, there's a hardcoded behavior for that property.

    Our suggestion to use -Expand instead is because -Expand [b]extracts the contents of the specified property[/b], returning it as a simple value (that's not a technically accurate phrase, but roll with it). In this case, because Length contains integers, -Expand would return a list of plain integers, not objects having a Length property, which is what -Property was doing. PowerShell knows how to cast integers as strings, as the subexpression requires, and so it'll work. As Dave notes, you'll get a space-delimited list, because that's how PowerShell turns an array of something into a string list.

  • #23770
    Profile photo of Don Jones
    Don Jones
    Keymaster

    BTW, to really illustrate this, run the following from the console and pay close attention to the output of each:

    $a | Select -Property Length
    $a | Select -Expand Length
    

    See the difference? It's important, and it's one of the bigger "gotchas" in PowerShell. I think it's even in our "gotchas" ebook.

  • #23771
    Profile photo of GS
    GS
    Participant

    Thanks, this works.
    I wish sometimes Powershell would not be so much catering to be user friendly and fail consistently on this sort of castings instead. Confuses the hell out of anybody who did .NET coding before this crazy casts.

  • #23772
    Profile photo of Jaap Brasser
    Jaap Brasser
    Participant

    For me the -ExpandProperty option works fine, here is the code I used:

    $a = "A", "AA"
    write-output "Length is $($a|Select -ExpandProperty length)"
    Length is 1 2

    If you want the number of strings in your array you could use .Count for example:

    write-output "Length is $($a.count)"

    Alternatively you could also use the following notation:

    write-output "Length is $(,$a | Select -ExpandProperty Count)"
  • #23773
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Yeah, I hear that a lot ;). It's kind of an endemic difference between "programming language" and "shell." Which is why anytime someone calls PowerShell a "scripting language" I go suborbital. The technical term isn't "casting," because that would imply a strict set of casting rules and failures; I think the term is "munging."

  • #23774
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    For the most part, when you cast something to a string in PowerShell, it winds up just calling the ToString() method on it. The objects output by Select-Object -Property Length produce blank strings:

    $objects = $a | Select -Property Length
    $objects[0].ToString()
    

    Which is why you wind up with nothing visible in your original code.

You must be logged in to reply to this topic.