PowerShell-函数的“写输出”与“返回”

时间:2018-07-04 16:29:18

标签: powershell syntax psobject pscustomobject

我已经使用PowerShell多年了,我以为我对它的一些“古怪”行为有所了解,但是我遇到了一个我无法理解的问题。

我一直使用“ return”从函数返回值,但是最近我想我可以看一下Write-Output作为替代方法。但是,PowerShell是PowerShell,我发现了似乎毫无意义的东西(至少对我而言):

function Invoke-X{ write-output @{ "aaa" = "bbb" } };
function Invoke-Y{ return @{ "aaa" = "bbb" } };

$x = Invoke-X;
$y = Invoke-Y;

write-host $x.GetType().FullName
write-host $y.GetType().FullName

write-host ($x -is [hashtable])
write-host ($y -is [hashtable])

write-host ($x -is [pscustomobject])
write-host ($y -is [pscustomobject])

输出:

System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False

$ x和$ y(或“ write-output”和“ return”)之间有什么区别,这意味着它们都是散列表,但是其中只有一个-是pscustomobject?除了明显检查我在变量中具有的每个哈希表是否也是pscustomobject之外,还有一种通用的方法可以确定与代码的区别吗?

我的$ PSVersionTable如下所示,以防此行为特定于特定版本的PowerShell:

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

干杯

M

1 个答案:

答案 0 :(得分:13)

return[pscustomobject]在某种程度上是红色鲱鱼。

其含义是:

  • 隐式/表达式输出与cmdlet生成的输出;使用return属于前一种类别,使用Write-Output属于后者。

  • 仅在 cmdlet 输出中,
  • 对象被包裹在主要是不可见的[psobject]实例中。

# implicit / expression output: NO [psobject] wrapper:
@{ "aaa" = "bbb" } -is [psobject] # -> $False

# Cmdlet-produced output: [psobject]-wrapped
(Write-Output @{ "aaa" = "bbb" }) -is [psobject]  # -> $True

请注意-令人惊讶的是-[pscustomobject][psobject]相同:它们都引用类型[System.Management.Automation.PSObject],这是PowerShell的通常不可见的帮助程序类型在幕后使用。
(更令人困惑的是, 是单独的[System.Management.Automation.PSCustomObject]类型。)

在大多数情况下,这种额外的[psobject]包装器是良性的-它的行为与被包装的对象直接一样-但在某些情况下,它会导致行为有所不同(见下文)。


  

除了明显检查我在变量中具有的每个哈希表是否也是pscustomobject之外,还有一种通用的方法可以确定与代码的区别吗?

请注意,哈希表不是PS自定义对象-仅对-[psobject]包装的对象使用[pscustomobject]与{ {1}}。

要检测由[psobject][pscustomobject] @{ ... } / New-Object PSCustomObject创建或由New-Object PSObjectSelect-Object之类的cmdlet生成的真实PS自定义对象,请使用:

Import-Csv

请注意,从Windows PowerShell v5.1 / PowerShell Core v6.1.0开始,将相关的$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]! 运算符与真正的PS自定义对象一起使用已损坏-参见下文。

作为一个额外的-as包装器是良性情况的示例,您仍然可以直接测试一个包装对象的类型:

[psobject]

也就是说,尽管有包装器,(Write-Output @{ "aaa" = "bbb" }) -is [hashtable] # $True 仍然可以识别包裹的类型。 因此,尽管有些矛盾, -is-is [psobject]在这种情况下都返回-is [hashtable],即使这些类型无关。


这些差异没有充分的理由,它们以抽象的泄漏(实现)使我震惊:内部构造意外地从幕后窥视。

以下GitHub问题讨论了这些行为: