为什么在这个例子中我们需要括号?

Why do we need brackets in this example?

为什么会这样

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

returns 空列表(似乎不过滤值)但是这个

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

有用吗?通常我不需要 () 但在这种情况下它们是强制性的,但为什么?

已找到 :) 检查 Get-member。 这是 return 数组。

Get-WinUserLanguageList return 是 System.Generic.Collection.List 个对象的数组。该基础列表是您需要过滤的内容。

将 cmdlet 放在括号中可以展开基础集合,而不必遍历 returned 数组中的每个索引。 的回答解释了有关此行为的更多信息,以及为什么 Get-WinUserLanguageList 与 return 集合的大多数其他 cmdlet 的工作方式不同。

如上所述,您得到的是一个列表对象,而不是您期望的 WinUserLanguage 对象。

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                                                                                                                      

你也可以用这个。

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

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

  • (...) 强制枚举 管道中包含的命令输出的集合元素。

  • 这应该不是必需的,但在你的情况下是这样,因为 Get-WinUserLanguageList 表现出 非标准行为:不是将多个结果对象一个一个输出到管道,它发出一个整个集合[1]作为单一输出对象.

    • 没有封闭的 (...),下一个管道段中的命令 - 在您的情况下为 Where-Object - 因此仅接收 一个 输入 - 整个集合- 并且在 it 上操作,而不是一个一个地操作元素。
      由于集合对象本身没有 LanguageType 属性,没有任何匹配项,因此您没有输出。[2]

如评论中所述,您可以将命令的输出通过管道传输到 Get-Member 以查看其输出对象的(不同)类型;对于标准 cmdlet,您会看到 单个对象 输出的类型,而不是集合类型。


[1] 具体来说,集合是 [System.Collections.Generic.List[Microsoft.InternationalSettings.Commands.WinUserLanguage]].

类型的泛型列表

[2] 您在命令中使用了简化的 PSv3+ 比较语句 语法 - Where-Object LanguageType -eq en-US - 而不是更冗长的语法,但是更灵活的 script-block 语法 - Where-Object { $_.LanguageType -eq 'en-US' }。如果您使用后者,您的命令会意外返回 整个集合 ,从而有效地返回 所有 语言。原因是只有 script-block 语法将 member-access enumeration 应用于输入集合,这意味着即使 $_ 本身没有 .LanguageTag 属性, elements 做,它们的值作为 array 返回。使用数组作为 LHS,-eq 充当过滤器,只要 en-US 在 返回值中 -eq 操作将仍被视为 $true,导致输入对象 - 整个集合 - 被传递。
this GitHub issue.

中讨论了这两种看似等效的语法形式之间令人惊讶的行为差异