PowerShell - 函数中的"写输出"与"返回"

mcl*_*ton 10 syntax powershell pscustomobject psobject

我已经使用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])
Run Code Online (Sandbox Code Playgroud)

输出:

System.Collections.Hashtable
System.Collections.Hashtable
True
True
True
False
Run Code Online (Sandbox Code Playgroud)

$ x和$ y(或'write-output'和'return')之间有什么区别,这意味着它们都是哈希表,但只有其中一个'-is'是一个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
Run Code Online (Sandbox Code Playgroud)

干杯,

中号

mkl*_*nt0 14

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
Run Code Online (Sandbox Code Playgroud)

请注意 - 令人惊讶的[pscustomobject]是- [psobject]它们都是相同的:它们都引用了type [System.Management.Automation.PSObject],这是PowerShell在幕后使用的通常不可见的帮助器类型.
(为了增加混乱,存在一个独立[System.Management.Automation.PSCustomObject]类型).

在大多数情况下,这个额外的[psobject]包装器是良性的 - 它主要表现为包装对象直接 - 但有些情况会导致微妙的不同行为(见下文).


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

请注意,哈希表不是 PS自定义对象 - 它只会出现 - 任何 - [psobject]包装对象的方式, 因为[pscustomobject]它是相同的[psobject].

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

$obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!
Run Code Online (Sandbox Code Playgroud)

请注意,-as从Windows PowerShell v5.1/PowerShell Core v6.1.0开始,使用具有真实PS自定义对象的相关运算符将被破坏 - 请参阅下文.

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

(Write-Output @{ "aaa" = "bbb" }) -is [hashtable]  # $True
Run Code Online (Sandbox Code Playgroud)

也就是说,尽管包装器-is仍然可以识别包装类型.因此,有些矛盾, -is [psobject]-is [hashtable]返回$True在这种情况下,即使这些类型是不相关的.


这些差异没有充分的理由,它们会让我感到漏洞抽象(实施):内部构造意外地从幕后偷看.

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

  • @sschoof 是的,`return` 是一个流程控制语句,无条件退出封闭的函数或脚本块或脚本 - 请参阅 [about_Return](https://learn.microsoft.com/en-us/powershell/module/microsoft. powershell.core/about/about_Return)。`return <some-command-or-expression>` 只是 `<some-command-or-expression> 的语法糖;返回`。 (2认同)