代码之家  ›  专栏  ›  技术社区  ›  MrCalvin

返回多个对象的cmdlet,它是什么集合类型(如果有的话)?[PowerShell]

  •  0
  • MrCalvin  · 技术社区  · 4 年前

    举个例子 Get-ADuser cmdlet:

    $Users = Get-ADuser -Filter *
    

    在大多数情况下,它会返回多个ADuser对象,但它是什么“集合”类型? 文档只说它将返回一个或多个微软的用户对象。活动目录。管理。AD用户。

    尝试使用例如。 ($Users -is [System.Collections.ArrayList]) 但我无法确定“收藏”类型?

    0 回复  |  直到 4 年前
        1
  •  9
  •   mklement0    2 年前

    Cmdlets 他们自己 通常使用 输出中的集合类型 . 1. :
    他们 发出 单个对象 管道 ,这可以 情境性 平均值:0、1或多个1。

    这正是 Get-ADUser 做: 输出对象的具体数量取决于给定的参数 ;这就是为什么 Get-AdUser help topic 仅提及标量类型 ADUser 作为输出类型,并声明它“返回一个或多个”它们。

    一般而言, PowerShell管道被设计为 流动 物体 ,其计数不需要提前知道 命令通常输出对象 逐一地 ,一旦可用 ,以及 接收 命令通常也会处理它们 逐一地 ,一旦收到 (参见 about_Pipelines ).


    PowerShell引擎本身 自动收集 为您提供多种输出 [object[]] 阵列 2. 如果需要 ,特别是如果您通过 变量赋值 或通过以下方式使用命令调用 (...) ,the grouping operator (或 $(...) ,the subexpression operator 3. ,或 @(...) ,the 阵列 子表达式运算符,下面将详细讨论),作为 表达 :

    # Get-ChildItem C:\Windows has *multiple* outputs, so PowerShell
    # collects them in an [object[]] array.
    PS> $var = Get-ChildItem C:\Windows; $var.GetType().Name
    Object[]
    
    # Ditto with (...) (and also with $(...) and always with @(...))
    PS> (Get-ChildItem C:\Windows).GetType().Name
    Object[]
    

    但是,如果给定的命令-可能 情境性 -仅输出a 单一的 对象,然后你会得到那个对象 它本身 -确实如此 包裹在数组中(除非您使用 @(...) -见下文):

    # Get-Item C:\ (always) returns just 1 object.
    PS> $var = Get-Item C:\; $var.GetType().Name
    DirectoryInfo # *not* a single-element array, 
                  # just the System.IO.DirectoryInfo instance itself
    

    可能会变得棘手的是,给定的命令可以 情境性 根据输入和运行时条件,产生一个或多个输出,因此引擎可以返回单个对象 阵列。

    # !! What $var receives depends on the count of subdirs. in $HOME\Projects:
    PS> $var = Get-ChildItem -Directory $HOME\Documents; $var.GetType().Name
    ??? # If there are *2 or more* subdirs: an Object[] array of DirectoryInfos.
        # If there is only *one* subdir.: a DirectoryInfo instance itself.
        # (See below for the case when there is *no* output.)
    

    @(...) ,the array-subexpression operator ,旨在消除这种歧义 ,如果需要: 通过将命令包装在 @(...) PowerShell确保其 输出为 总是 收集为 [对象[]] -即使命令恰好生成 输出对象甚至 没有人 :

    PS> $var = @(Get-ChildItem -Directory $HOME\Projects); $var.GetType().Name
    Object[] # Thanks to @(), the output is now *always* an [object[]] array.
    

    对于可变分配, 一个潜在的更有效的替代方案是使用 [array] 类型约束 以确保输出成为数组:

    # Alternative to @(...)
    # Note: You may also create a strongly typed array, with on-demand type conversions:
    #       [string[]] $var = ...
    PS> [array] $var = Get-ChildItem -Directory $HOME\Documents; $var.GetType().Name
    Object[]
    

    注:

    • 这可能更有效,因为如果RHS恰好是一个数组,则按原样分配,而 @(...) 事实上 列举 输出来自 ... 然后 重新组装 元素变成a ( [对象[]] )阵列 .

      • [阵列] 蜜饯 输入数组的特定类型 通过它 (例如。, [array] $var = [int[]] (1..3) 存储 [int[]] 按原样排列 $var ).
    • 放置 [阵列] “铸”到 左边 属于 $var = ... -这就是它成为 类型约束 on变量-表示变量的类型为 已锁定 ,并为其分配不同的值 $var 稍后将继续将RHS值转换为 [阵列] ( [对象[]] ),如果需要(除非您指定 $null 或“无”(见下文)。


    退一步: 确保收集的输出是一个数组通常 没有必要 ,由于 PowerShell的 标量和集合的统一处理 在v3+版本中:

    • PowerShell暴露 intrinsic members 即使是标量(非集合)对象,也允许您将其视为集合。

      • 例如。 (42).Count 1 ( (42).Length 也工作);它被视为一个整数 收集 1个元素,这也适用于 索引 : (42)[0] 42 即虚拟收藏的第一个也是唯一的元素。
      • 注意事项 : 类型原生 成员优先,这是一个陷阱 : 'foo'.Length 3 ,字符串的长度-但是 'foo'.Count 作品(is 1. )然而, 'foo'[0] 总是如此 'f' ,因为 [string] 类型的本机索引器返回数组中的单个字符(解决方法: @('foo')[0] )
    • 请参阅 this answer 了解详情。


    如果命令产生 输出,您将得到“无” (严格来说: [System.Management.Automation.Internal.AutomationNull]::Value 单例),其中 在大多数情况下,行为如下 $null 4. :

    # Get-Item nomatchingfiles* produces *no* output.
    PS> $null -eq (Get-Item nomatchingfiles*)
    True
    
    # Conveniently, PowerShell lets you call .Count on this value, which the
    # behaves like an empty collection and indicates 0.
    PS> (Get-Item nomatchingfiles*).Count
    0
    

    [1] 它 可以输出整个集合 作为一个整体 到管道(在PowerShell代码中使用 Write-Output -NoEnumerate $collection 或者更简洁地说, , $collection ),但这只是管道中的另一个对象,恰好是一个集合本身。将集合作为一个整体输出是 异常 但是,这会改变您管道命令的方式 查看输出,这可能是意外的;一个突出的例子是 ConvertFrom-Json s unexpected behavior prior to v7.0 .

    [2] a System.Array 元素类型为的实例 System.Object ,允许您 混合不同类型的对象 在单个阵列中。

    [3] 使用 (...) 通常就足够了; $(...) 仅用于字符串插值(可扩展字符串)和嵌入整个语句或 倍数 更大的表达式中的命令;请注意 $(...) ,不像 (...) 其本身可以展开单个元素数组;比较 (, 1).GetType().Name $(, 1).GetType().Name ;参见 this answer .

    [4] 在某些情况下,“无”的行为与 $null ,特别是在管道和 switch 声明,详见 this comment on GitHub ;相关问题是一个功能请求,使“无”更容易与 $null ,通过支持 -is [AutomationNull] 作为 测试。

        2
  •  1
  •   js2010    4 年前

    通常它只是一个对象数组:

    $Users.gettype()
    $Users.count
    $Users -is [object[]]
    

    $error是一个数组列表:

    $error -is [collections.arraylist]