'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?
Solution 1:[1]
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-WinUserLanguageListexhibits 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-Objectin 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 noLanguageTypeproperty, nothing matches, and you get no output.[2]
- Without the enclosing
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 the simplified PSv3+ comparison statement 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 this GitHub issue.
Solution 2:[2]
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.
Solution 3:[3]
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'})
Solution 4:[4]
FOund :) Check Get-member. It's return array.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | mklement0 |
| Solution 4 | Adam |
