返回多个对象的 cmdlet,它是什么集合类型(如果有)?[电源外壳] [英] A cmdlet which returns multiple objects, what collection type is it, if any? [PowerShell]

查看:19
本文介绍了返回多个对象的 cmdlet,它是什么集合类型(如果有)?[电源外壳]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Get-ADuser cmdlet 示例:

An example of the Get-ADuser cmdlet:

$Users = Get-ADuser -Filter *

在大多数情况下它会返回多个 ADuser 对象,但它是什么集合"类型?文档只说它会返回一个或多个 Microsoft.ActiveDirectory.Management.ADUser 的用户对象.

It will in most cases return multiple ADuser objects, but what "collection" type is it? The documentation only says it will returns one or more user objects of Microsoft.ActiveDirectory.Management.ADUser.

尝试使用例如($Users -is [System.Collections.ArrayList]) 但我无法确定集合"类型?

Tried to use e.g. ($Users -is [System.Collections.ArrayList]) but I cannot nail the "collection" type?

推荐答案

Cmdlet自身通常在其输出中使用no集合类型.[1]:
它们单个对象发送到管道,这可以根据情况表示:零、一个或多个.

Cmdlets themselves typically use no collection type in their output.[1]:
They emit individual objects to the pipeline, which can situationally mean: zero, one, or multiple ones.

这正是 Get-ADUser 所做的:输出对象的具体数量取决于给定的参数;这就是为什么 Get-AdUser帮助主题仅提及标量类型ADUser 作为输出类型并声明它返回一个或多个"其中.

This is precisely what Get-ADUser does: the specific number of output objects depends on the arguments that were given; that is why the Get-AdUser help topic only mentions scalar type ADUser as the output type and states that it "returns one or more" of them.

通常,PowerShell 管道是一个对象流,其特定长度(对象计数)不需要提前知道,在随后的管道段中带有命令处理上一个段的输出对象一个一个,因为它们被接收(请参阅about_Pipelines).

Generally, the PowerShell pipeline is meant to be a stream of objects whose particular length (object count) need not be known in advance, with commands in subsequent pipeline segments processing the previous segment's output objects one by one, as they're being received (see about_Pipelines).

然而,PowerShell 引擎自动收集多个输出到[object[]]数组[2] 如果需要,特别是如果您通过变量赋值捕获输出或通过(...)分组运算符(或$(...)子表达式运算符[3]),作为表达式:

However, it is the PowerShell engine that automatically collects multiple outputs for you in an [object[]] array[2] if needed, notably if you capture output via a variable assignment or use a command call via (...), the grouping operator (or $(...), the subexpression operator[3]), as an expression:

# 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[]


但是,如果给定的命令——可能是情况——只输出一个单个对象,那么你将只得到那个对象本身em> - 它没有被包裹在一个数组中:


However, if a given command - possibly situationally - only outputs a single object, you'll then get just that object itself - it is not wrapped in an array:

# 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

棘手的是,给定的命令可以根据情况产生一个或多个输出,具体取决于输入和运行时条件,因此引擎可能返回单个对象em> 一个数组.

What can get tricky is that a given command can situationally produce either one or multiple outputs, depending on inputs and runtime conditions, so the engine may return either a single object or an array.

# !! 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 DirectoryInfo instances.
    # If there is only *one* subdir.: a DirectoryInfo instance itself.
    # (See below for the case when there is *no* output.)

@()array-subexpression operator,旨在消除这种歧义,如果需要:通过将命令包装在 @(...) 中,PowerShell 确保其输出总是收集为 [object[]] - 即使命令碰巧只产生一个输出对象,甚至:

@(), the array-subexpression operator, is designed to eliminate this ambiguity, if needed: By wrapping a command in @(...), PowerShell ensures that its output is always collected as [object[]] - even if the command happens to produce just one output object or even none:

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

对于变量赋值,一种可能更有效的替代方法是使用 [array] 类型约束 来确保输出成为一个数组:

With variable assignments, a potentially more efficient alternative is to use an [array] type constraint to ensure that the output becomes an 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 已经是一个数组,则按原样分配,而 @(...) 实际上枚举 ... 的输出,然后 重新组合 元素为 new ([object[]]) 数组.

  • This is potentially more efficient in that if the RHS already happens to be an array, it is assigned as-is, whereas @(...) actually enumerates the output from ... and then reassembles the elements into a new ([object[]]) array.

  • [array] 通过简单地传递来保留输入数组的特定类型(例如,[array] $var = [int[]] (1..3)[int[]] 数组按原样存储在 $var 中).
  • [array] preserves the specific type of an input array by simply passing it through (e.g., [array] $var = [int[]] (1..3) stores the [int[]] array as-is in $var).

放置[array]$var = ...左侧 - 这就是它对变量的类型约束 - 意味着变量被锁在中,以后给$var赋值不同的值会继续把RHS的值转成[array]([object[]]),如果需要(除非您指定 $null 或nothing"(见下文)).

Placing the [array] "cast" to the left of $var = ... - which is what it makes it a type constraint on the variable - means that the type of the variable is locked in, and assigning different values to $var later will continue to convert the RHS value to [array] ([object[]]), if needed (unless you assign $null or "nothing" (see below)).

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

Taking a step back: Ensuring that collected output is an array is often not necessary, due to PowerShell's unified handling of scalars and collections in v3+:

  • PowerShell 公开 内部成员 甚至在允许您将它们视为集合的标量(非集合)对象上.

  • PowerShell exposes intrinsic members even on scalar (non-collection) objects that allow you treat them like collections.

  • 例如(42).Count1 ((42).Length 也可以);它被视为具有 1 个元素的整数 collection,这也适用于 索引:(42)[0]42,即虚拟集合的第一个也是唯一的元素.
  • 警告:Type-native 成员优先,这是字符串的一个陷阱:'foo'.Length3,字符串的长度 - 但 'foo'.Count 有效(是 1);然而,'foo'[0] 总是 'f',因为 [string] 类型的本机索引器返回数组中的单个字符(解决方法:@('foo')[0])
  • E.g. (42).Count is 1 ((42).Length works too); it is treated like an integer collection with 1 element, and this also applies to indexing: (42)[0] is 42, i.e. the virtual collection's first and only element.
  • Caveat: Type-native members take precedence, which is a pitfall with strings: 'foo'.Length is 3, the string's length - but 'foo'.Count works (is 1); however, 'foo'[0] is invariably 'f', because the [string] type's native indexer returns the individual characters in the array (workaround: @('foo')[0])

有关详细信息,请参阅此答案.

See this answer for details.

如果命令产生输出,您将得到无"(严格来说:[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]可以将整个集合作为一个整体输出到管道(在带有 Write-Output -NoEnumerate $ 的 PowerShell 代码中)collection,或者更简洁地说,, $collection),但这只是管道中的另一个对象,恰好是一个集合本身.将集合作为一个整体输出是一种异常,但是,这会改变您通过管道查看输出的命令的方式,这可能是意料之外的;一个突出的例子是 ConvertFrom-Json 在 v7.0 之前的意外行为.


[1] It is possible to output entire collections as a whole to the pipeline (in PowerShell code with Write-Output -NoEnumerate $collection or, more succinctly, , $collection), but that is then just another object in the pipeline that happens to be a collection itself. Outputting collections as a whole is an anomaly, however, that changes how commands you pipe to see the output, which can be unexpected; a prominent example is ConvertFrom-Jsons unexpected behavior prior to v7.0.

[2] 一个 System.Array 实例,其元素类型为 System.Object,允许您在单个数组中混合不同类型的对象.

[3] 使用 (...) 通常就足够了;$(...) 仅用于字符串插值(可扩展字符串)以及将整个语句或多个命令嵌入到更大的表达式中;请注意,$(...)(...) 本身不同,它会解开单元素数组;比较 (, 1).GetType().Name$(, 1).GetType().Name;请参阅此答案.

[3] Use of (...) is usually sufficient; $(...) is only needed for string interpolation (expandable strings) and for embedding whole statements or multiple commands in a larger expression; note that $(...), unlike (...) by itself, unwraps single-element arrays; compare (, 1).GetType().Name to $(, 1).GetType().Name; see this answer.

[4] 在某些情况下,什么都没有"行为与 $null 不同,特别是在管道和 switch 语句中,详见 GitHub 上的此评论;链接的问题是一个功能请求,要求什么都不做";通过支持 -is [AutomationNull] 更容易与 $null 区分开来一个测试.

[4] There are scenarios in which "nothing" behaves differently from $null, notably in the pipeline and in switch statements, as detailed in this comment on GitHub; the linked issue is a feature request to make "nothing" more easily distinguishable from $null, by supporting -is [AutomationNull] as a test.

这篇关于返回多个对象的 cmdlet,它是什么集合类型(如果有)?[电源外壳]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆