我已经使用PowerShell多年了,我以为我对它的一些``古怪''行为有所了解,但是我遇到了一个我不能做的事...

我一直使用“返回”从函数返回值,但是最近我想我可以看一下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

干杯,

中号

最佳答案

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

归结为:

  • 隐式表达式输出与cmdlet产生的输出;使用return(无cmdlet调用)属于前一类,而使用Write-Output属于后者。
  • 仅在cmdlet产生的输出中包裹了输出对象-大多是不可见的-[psobject]实例。

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



    请注意,哈希表不是PS自定义对象,因为[psobject][pscustomobject]相同,所以它仅对-[psobject]包裹的对象才显示。

    要检测由[pscustomobject] @{ ... }New-Object PSCustomObject / New-Object PSObject创建或由cmdlet(例如Select-ObjectImport-Csv)生成的真实PS自定义对象,请使用:
    $obj -is [System.Management.Automation.PSCustomObject] # NOT just [pscustomobject]!
    

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

    例如,多余的[psobject]包装器是良性的,您仍然可以直接测试包装对象的类型:
    (Write-Output @{ "aaa" = "bbb" }) -is [hashtable]  # $True
    

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

    这些差异没有充分的理由,它们让我感到困惑的是抽象的(实现):内部结构意外地从幕后偷看。

    以下GitHub问题讨论了这些行为:
  • Objects are situationally invisibly [psobject] -wrapped, sometimes causing unexpected behavior.
  • Why is [pscustomobject] the same as [psobject] , even though a distinct [System.Management.Automation.PSCustomObject] type exists?
  • Should all [psobject] cmdlet parameters be changed to [object] ?
  • The -as operator does not recognize System.Management.Automation.PSCustomObject instances as such
  • 关于powershell - PowerShell-函数中的 “Write-Output”与 “return”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51177881/

    10-11 05:48