写输出-InputObject(,'Test')-NoEnumerate

时间:2019-07-11 18:51:07

标签: windows powershell switch-statement enumerate

我认为这是一个仅适用于PowerShell Windows 5.1的错误:

通过命名的-NoEnumerate参数提供输入时,-InputObject开关不起作用:

以下函数返回False

Function Test {Write-Output -InputObject (,'Foo') -NoEnumerate} 
(Test) -is [Array]

此函数返回True

Function Test {Write-Output (,'Foo') -NoEnumerate} 
(Test) -is [Array]

PowerShell Windows

Name                           Value
----                           -----
PSVersion                      5.1.17134.858
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17134.858
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

不会出现在PowerShell Core 中。
(两个函数都返回True

Name                           Value
----                           -----
PSVersion                      6.2.0-preview.1
PSEdition                      Core
GitCommitId                    6.2.0-preview.1
OS                             Microsoft Windows 10.0.17134
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

尽管在Write-Output cmdlet的有关-NoEnumeration开关的说明中有一个注释:

  

注意

     

此开关仅适用于PowerShell Core 6.2和更高版本。   在旧版的PowerShell Core上,集合仍   即使使用此开关也可以枚举。 PowerShell中的行为   Core 6.2与Windows PowerShell一致。

(如果我没看错,我知道-NoEnumeration开关应该只适用于PowerShell Windows)

我已经在here的指导下Windows PowerShell [UserVoice]here报告了PowerShell GitHub Community问题,但感觉就像是一个黑洞……(我已经报告了问题之前,但几乎看不到任何回应。

问题:
这确实是一个错误还是我错过了什么?
如果是错误,Windows PowerShell [UserVoice]仍然是报告此类问题的正确地址吗?

1 个答案:

答案 0 :(得分:1)

确实是 Windows PowerShell 中的一个错误(直到v5.1,最后一个要发布的版本-由于该错误不是安全性至关重要的漏洞,因此< em>不太可能是固定的)。通过-NoEnumerate时仍会导致枚举,尽管只是一个级别。 [1]

此错误已(至少)从v6.2.3版 [2]

中被 PowerShell [Core] 修复

为了演示该问题(下面的所有命令现在都可以在PowerShell [Core]中按预期方式工作):

WinPS> (Write-Output -NoEnumerate -InputObject 1, 2 | Measure-Object).Count
2 # !! Should be *1*, because a *single array* (with 2 elements) was passed.

注意:在上面的命令中省略Measure-Object是很诱人的,但这会扭曲结果:使用(),在{em>命令周围使用grouping operator 在表达式的上下文中会导致该命令的输出被枚举

有一个解决方法 省略 -InputObject ,即将集合作为位置参数,令人惊讶的是,它导致参数按原样传递(而在参数绑定期间显式使用-InputObject 枚举参数):

# POSITIONAL argument binding, without -InputObject
WinPS> (Write-Output -NoEnumerate 1, 2 | Measure-Object).Count
1 # OK

请注意,尽管这是一种不常见的情况,但鉴于大多数命令都可以执行,因此该解决方法不适用于管道输入。 >不是整个输出集合到管道(它们将其元素一个一个地发送):

WinPS> ( , (1, 2) | Write-Output -NoEnumerate | Measure-Object ).Count
2 # !! Should be *1*: the unwrapped outer array contains a *single [array]* element

注意:外部包装器数组 , (...) ,使用,的一元形式,array constructor operator)是<如果要通过管道使用 expression 将集合作为整体发送 ,则必须始终使用em> 。

因此,这种单元素包装器数组技术Write-Output -NoEnumerate本身的一种简洁快捷的替代方法,因此,实际上是 , (1, 2) 本身就是基于管道的解决方法:它将数组操作数(1, 2作为一个整体写入(成功)输出流。


[1] 使用-NoEnumerate还会在 Windows PowerShell 中显示一个相关的错误:太多枚举发生明确使用-InputObject

错误地应用了一个递归级别:输入集合的元素被意外地枚举了 (同样,PowerShell [Core]现在可以正常工作):

WinPS> (Write-Output -InputObject 1, (2, 3) | Measure-Object).Count
3 # !! This should be *2*, because the single input array has only 2 elements.
  # !! That the 2nd element is itself an array should not matter.

同样,解决方法 省略 -InputObject

# POSITIONAL argument binding, without -InputObject
WinPS> (Write-Output 1, (2, 3) | Measure-Object).Count
2 # OK

[2]但是,从PowerShell [Core] 7.0.0-rc.2起,合并时仍然存在错误
-NoEnumerate,其标量参数受位置约束

PSCore> (Write-Output -NoEnumerate 42).GetType().Name
List`1 #`# !! scalar 42 was unexpectedly wrapped in a *list*

解决方法显式使用-InputObject

# OK thanks to -InputObject
PSCore> (Write-Output -NoEnumerate -InputObject 42).GetType().Name
Int32 # OK

正在this GitHub issue中跟踪该错误。