Where-Object 过滤器意外匹配整个输入集合,Get-Member 显示集合类型而不是元素类型

Chr*_*idt 5 powershell filtering enumeration

我的Get-AzureStorSimpleAccessControlRecord调用返回 2 个对象,其中包含
Name属性值servertest4servertest3

然而,

Get-AzureStorSimpleAccessControlRecord | where {$_.Name -like '*servertest4*'}
Run Code Online (Sandbox Code Playgroud)

意外地返回两个对象。

如果我通过 for-each 循环传递它,则 where 语句将捕获该属性。

Get-AzureStorSimpleAccessControlRecord | % {$_.Name} | where {$_ -like 'servertest4'}
servertest4
Run Code Online (Sandbox Code Playgroud)

意外地传递原始命令Get-Member不会显示该Name属性。这是问题所在吗?

如果是这样,为什么它把它作为一列,为什么当我将它传递给 for-each 循环时它会起作用?这是它返回的所有属性(我删除了方法):

Get-AzureStorSimpleAccessControlRecord | gm


   TypeName: System.Collections.Generic.List`1[[Microsoft.WindowsAzure.Management.StorSimple.Models.AccessControlRecord, Microsoft.WindowsAzure.Management.StorSimple, 
Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]

Name           MemberType            Definition                          
Item           ParameterizedProperty 

Microsoft.WindowsAzure.Management.StorSimple.Models.AccessControlRecord Item(int index) {get;set;}                                   
Capacity       Property              int Capacity {get;set;}                                                                                                              
Count          Property              int Count {get;}                                                                                                                     
IsFixedSize    Property              bool IsFixedSize {get;}                                                                                                              
IsReadOnly     Property              bool IsReadOnly {get;}                                                                                                               
IsSynchronized Property              bool IsSynchronized {get;}                                                                                                           
SyncRoot       Property              System.Object SyncRoot {get;}                                                                                                        
Run Code Online (Sandbox Code Playgroud)

我缺少什么?

mkl*_*nt0 7

似乎Get-AzureStorSimpleAccessControlRecord行为不当,并将其输出集合作为一个整体通过管道作为单个对象发送,而不是逐个元素发送

您应该可以通过将调用包含在以下内容中来解决这个问题(...)

(Get-AzureStorSimpleAccessControlRecord) |
  Where-Object { $_.Name -like '*servertest4*' }
Run Code Online (Sandbox Code Playgroud)

将调用包含在 中(...)分组运算符使 PowerShell枚举集合,即它通过管道将其元素一一发送,正如通常所期望的那样。


可选阅读:如果没有解决方法会发生什么?

下面的简化示例Get-AzureStorSimpleAccessControlRecord通过创建一个数组来模拟 的不良行为,[int[]]该数组通过数组构造运算符 的一元形式人为地包装,在另一个数组中。通过管道
发送这个包装的集合会导致它作为一个整体发送,而不是逐项发送。

$wrappedColl = , [int[]] (1, 2) # create artificially wrapped collection
Run Code Online (Sandbox Code Playgroud)

现在,像通常情况一样Get-Member报告包装的集合类型而不是单个项目的类型(管道解开外部[int[]]数组并按原样发送其唯一元素 - 内部数组):

PS> $wrappedColl | Get-Member

   TypeName: System.Int32[]  # !! Type of the wrapped array as a whole
   ...
Run Code Online (Sandbox Code Playgroud)

在应用过滤器时,作为整体传递的数组也会妨碍Where-Object,这就是引发问题的原因:

# Trying to extract element 2 outputs the whole array(!).
PS> $wrappedColl | Where-Object { $_ -eq 2 }
1
2
Run Code Online (Sandbox Code Playgroud)
  • 由于[int[]]数组是作为一个整体传递的,因此这就是脚本块$_内部绑定的内容Where-Object

  • 应用于-eq作为数组的 LHS执行数组过滤,而不是返回简单的[bool]值,以便 [int[]] (1, 2) -eq 2返回匹配项的数组[object[]] 2,在本例中为(请注意,结果数组始终是类型为 的常规 PS 数组[object[]])。

  • 然后,生成的(单项)数组在 cmdlet 上下文中被解释为布尔值Where-Object,并且任何非空数组$true在强制转换为布尔值时都会计算为 。

  • 因此,由于传递给的脚本块Where-Object计算为$true,因此输入对象将通过 传递,在本例中,如上所述,输入对象是整个 [int[]]数组。