如果cmdlet返回array的数组,例如:
function test() {
$results = New-Object System.Collections.ArrayList
$array = @()
for ($idx = 0; $idx -lt 3; $idx++) {
$obj = New-Object PSObject -Property @{
"key1" = "value1";
}
$array += @($obj)
}
[Void] $results.add($array)
return ,$results.TOArray()
}
然后,分配返回值后,输出将不同。
如果直接运行test
,则会显示:
test
Length : 3
LongLength : 3
Rank : 1
SyncRoot : {@{key1=value1}, @{key1=value1}, @{key1=value1}}
IsReadOnly : False
IsFixedSize : True
IsSynchronized : False
Count : 3
同时分配给变量:
$result = test
$result
key1
----
value1
value1
value1
如果cmdlet返回一个一级数组,则test
和$(test)
的输出是相同的。
function test() {
$array = New-Object System.Collections.ArrayList
for ($idx = 0; $idx -lt 3; $idx++) {
$obj = New-Object PSObject -Property @{
"key1" = "value1";
}
$array += @($obj)
}
return ,$array
}
test
的输出:
key1
----
value1
value1
value1
答案 0 :(得分:1)
PetSerAl在简短的评论中提供了关键的指针:
输出呈现的差异归结为以下事实:
test
是命令 (对函数,cmdlet或外部程序的调用)$result
(以前捕获test
的输出)是表达式 (其中仅涉及变量引用,PowerShell的运算符和。 NET方法调用在管道外部-尽管它可能包含 nested 命令)。通过从, $results.ToArray()
函数(函数是命令的一种形式)输出test
,您可以使用数组构造运算符,
来包装{{1 }}(产生数组的数组)在一个辅助的,暂时的单元素数组中,这是确保集合作为单个对象而不是枚举其元素。
即辅助。包装器数组是:
在流向管道的输出中始终会丢失
,但它确保通过管道中的下一条命令将包裹的数组视为单个对象。 p>
在函数中,$results.ToArray()
在概念上更清晰,但更冗长的等效项是, $results.ToArray()
;也就是说,PowerShell通常隐式的输出是显式的,并请求禁止显示枚举输出集合的默认行为。
鉴于管道中没有其他命令,Write-Output -NoEnumerate $results.ToArray()
输出将隐式打印到屏幕。
对于当前情况,将数组数组作为单个对象打印会导致您看到的属性列表输出格式。
相反,由于表达式是隐式枚举的 ,因此 tests
。也就是说,从$result
捕获的数组的数组-没有辅助。包装数组! -一次发送一个元素到输出格式系统,然后这些元素将更有意义地呈现。
要提供一个更简单的示例:
假设函数test
使用test
输出包含3元素数组的容器数组,该数组最终包装在aux中。单元素数组(顺便说一句:PowerShell中的return , , (1..3)
只是退出函数或脚本块的语法糖,它与输出)。
执行return
函数等效于直接执行以下 expression :
test
即外部辅助。由于隐式枚举,数组再次被丢弃,, , (1..3)
被呈现为单个对象,从而导致属性列表格式:
, (1..3)
相比之下,执行Length : 3
LongLength : 3
Rank : 1
SyncRoot : {1, 2, 3}
IsReadOnly : False
IsFixedSize : True
IsSynchronized : False
Count : 3
(在运行$result
之后)等效于:
$result = test
即外部辅助。数组在, (1..3)
期间丢失,容器数组现在也被隐式枚举,并且$result = test
作为单个对象呈现得更有意义(您无法从视觉上区别于将其直接发送给(1..3)
管道,即逐个元素):
1..3
当命令或表达式既未捕获到变量中,也未发送到管线中的另一命令,也未重定向(使用1
2
3
或>
)时,它将隐式打印到屏幕(主机)上,使用PowerShell的默认输出格式系统。
您可以想到一个命令,例如:
>>
等同于 [1] :
test
test | Out-Host
根据第一个输入对象自动选择一个Out-Host
cmdlet进行渲染,该cmdlet适于手头的输入:
如果该对象具有4个或更少的属性,则选择Format-*
;否则为Format-Table
。
但是,如果第一个输入对象是 collection (实现Format-List
),则格式cmdlet的选择基于集合的 first元素 (与整个集合类型相反),然后使用该cmdlet分别设置集合的元素格式。
如果您的IEnumerable
变量得到输出,则输入数组的第一个元素是一个$result
实例(由[pscustomobject]
创建),具有1个属性,New-Object PSObject
;因此,选择key1
,并以表格格式显示组成数组的[pscustomobject]`实例。
相比之下,在您进行Format-Table
调用的情况下,输入数组的第一个元素是另一个数组,其本身进一步被 枚举。 test
揭示了一个数组具有8个属性(Get-Member -InputObject (1,2) -Type Property
,Count
,IsFixedSize
,IsReadOnly
,IsSynchronized
,Length
,{ {1}},LongLength
),这就是选择Rank
的原因,它会将每个属性作为名称/值对单独列出。
当然,您可以选择显式使用格式化cmdlet,PetSerAl指出格式化cmdlet支持SyncRoot
参数,该参数使您可以控制输入对象的格式。集合的格式:您可以要求对集合进行枚举,即打印其元素(Format-List
,这是默认设置),仅显示集合自身的属性,而无需打印其属性元素(-Expand
或两者(-Expand EnumOnly
)。
但是请注意,您无法通过-Expand CoreOnly
请求额外的枚举级别,因此您的-Expand Both
输出无法直接格式化为显示嵌套数组的各个元素。
但是,通过管道传递到-Expand
来实现这一点很简单,test
执行了单独呈现元素所需的附加枚举级别:
Write-Output
[1]更准确地说,正如PetSerAl所指出的,它是:test | Write-Output
,使用户可以覆盖. { test } 2>&1 | Out-Default
cmdlet进行自定义格式。