RandomB
RandomB

Reputation: 3749

Why do we need brackets in this example?

Why this

Get-WinUserLanguageList | Where-Object LanguageTag -eq en-US

returns empty list (seems it does not filter values) but this

(Get-WinUserLanguageList) | Where-Object LanguageTag -eq en-US

does work? Usually I don't need () but in this case they are mandatory, but why?

Upvotes: 2

Views: 222

Answers (4)

mklement0
mklement0

Reputation: 440679

Usually I don't need () but in this case they are mandatory, but why?

  • (...) forces enumeration of the elements of a collection output by the enclosed command in a pipeline.

  • This shouldn't be necessary, but is in your case, because Get-WinUserLanguageList exhibits nonstandard behavior: instead of outputting multiple result objects one by one to the pipeline, it emits an entire collection[1] as a single output object.

    • Without the enclosing (...), the command in the next pipeline segment - Where-Object in your case - therefore receives just one input - the entire collection - and operates on it rather than on the elements one by one.
      Since the collection object itself has no LanguageType property, nothing matches, and you get no output.[2]

As mentioned in the comments, you can pipe a command's output to Get-Member to see the (distinct) types of its output objects; for standard cmdlets, you'd see the types of the individual objects output, not a collection type.


[1] Specifically, the collection is a generic list of type [System.Collections.Generic.List[Microsoft.InternationalSettings.Commands.WinUserLanguage]].

[2] You're using simplified syntax in your command - Where-Object LanguageType -eq en-US - instead of the more verbose, but more flexible script-block syntax - Where-Object { $_.LanguageType -eq 'en-US' }. Had you used the latter, your command would have accidentally returned the entire collection and thereby effectively all languages. The reason is that only the script-block syntax applies member-access enumeration to the input collection, which means that even though $_ itself doesn't have a .LanguageTag property, the elements do, and their values are returned as an array. With an array as the LHS, -eq acts as a filter, and as long as en-US is among the values returned, the -eq operation will still be considered $true, causing the input object - the entire collection - to be passed through.
This surprising discrepancy in behavior between the two seemingly equivalent syntax form is discussed in GitHub issue #9576.

Upvotes: 4

codewario
codewario

Reputation: 21518

Get-WinUserLanguageList returns an array of System.Generic.Collection.List objects. That underlying list is what you need to filter on.

Placing the cmdlet in parentheses unrolls the underlying collection without having to iterate over every index in the returned array. mklement0's answer explains more about this behavior and why Get-WinUserLanguageList works differently than most other cmdlets that return collections.

Upvotes: 2

RoscoeT
RoscoeT

Reputation: 87

As mentioned above you're getting a list object and not the WinUserLanguage object you're expecting.

PS C:\Users\admin user> $test = Get-WinUserLanguageList

PS C:\Users\admin user> $test.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                                           
-------- -------- ----                                     --------                                                                                                                           
True     True     List`1                                   System.Object                                                                                                                      



PS C:\Users\admin user> $test[0].GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                                           
-------- -------- ----                                     --------                                                                                                                           
True     False    WinUserLanguage                          System.Object                                                                                                                      

You could also use this.

(Get-WinUserLanguageList).where({$_.LanguageTag -eq 'en-US'})

Upvotes: 1

Adam
Adam

Reputation: 62

FOund :) Check Get-member. It's return array.

Upvotes: -2

Related Questions