我已经使用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
答案 0 :(得分:13)
return
和[pscustomobject]
在某种程度上是红色鲱鱼。
其含义是:
隐式/表达式输出与cmdlet生成的输出;使用return
属于前一种类别,使用Write-Output
属于后者。
对象被包裹在主要是不可见的[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 PSObject
和Select-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问题讨论了这些行为: