关于语法:PowerShell-函数中的”写输出”与”返回”

PowerShell - “Write-Output” vs “return” in functions

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

的尾巴

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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])

输出:

1
2
3
4
5
6
System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False

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

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

1
2
3
4
5
6
7
8
9
10
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


在某种程度上,

return[pscustomobject]在这里是红色鲱鱼。

归结为:

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

  • 仅package在cmdlet生成的输出中的,包裹在输出对象中-大多数是不可见的-[psobject]实例。

1
2
3
4
5
# 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]package器是良性的-它的行为几乎直接像被package的对象一样-但是在某些情况下,它会引起细微的不同行为(请参见下文)。

And is there a generalised way I can determine the difference from code, other than obviously checking whether every hashtable I have in a variable is also a pscustomobject

请注意,哈希表不是PS自定义对象-由于[pscustomobject][psobject]相同,因此它仅对-[psobject]包裹的对象那样显示。

要检测真实的PS自定义对象-使用[pscustomobject] @{ ... }New-Object PSCustomObject / New-Object PSObject创建或由cmdlet(例如Select-ObjectImport-Csv)生成-使用:

1
$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!

请注意,从Windows PowerShell v5.1 / PowerShell Core v6.1.0开始,将相关的-as运算符与真正的PS自定义对象一起使用已损坏-参见下文。

作为额外的[psobject]package器是良性的情况的示例,您仍然可以直接测试package对象的类型:

1
(Write-Output @{"aaa" ="bbb" }) -is [hashtable]  # $True

即,尽管有package器,但-is仍可识别package的类型。
因此,有些矛盾的是,即使这些类型无关,在这种情况下,-is [psobject]-is [hashtable]都返回$True

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

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

  • 对象有时会被[psobject]隐形包裹,有时会导致意外行为。

  • 即使存在独特的[System.Management.Automation.PSCustomObject]类型,为什么[pscustomobject][psobject]相同?

  • 是否应将所有[psobject] cmdlet参数都更改为[object]

  • -as运算符不能这样识别System.Management.Automation.PSCustomObject实例。