Reputation: 3749
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
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.
(...)
, 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.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
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
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