web-dev-qa-db-ja.com

PowerShell-関数の「書き込み出力」と「戻り値」

私はPowerShellを何年も使用していて、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」)の違いは何ですか?つまり、両方ともハッシュテーブルですが、そのうちの1つだけが「pscustomobject」です。そして、変数にあるすべてのハッシュテーブルがpscustomobjectでもあるかどうかを明らかにチェックする以外に、コードとの違いを判断できる一般的な方法はありますか?

この動作がPowerShellの特定のバージョンに固有である場合、$ PSVersionTableは次のようになります。

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

12
mclayton

returnと_[pscustomobject]_は、ある意味でここでは赤いニシンです。

結局のところ:

  • 暗黙的/式の出力とコマンドレットで生成された出力。 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でもあるかどうかを明らかにチェックする以外に、コードとの違いを判断できる一般的な方法はありますか?

ハッシュテーブルはnotPSカスタムオブジェクトであることに注意してください-_[psobject]_-ラップされたオブジェクトの場合にのみそのように表示されます-_[pscustomobject]_は_[psobject]_と同じです。

_[pscustomobject] @{ ... }_または_New-Object PSCustomObject_/_New-Object PSObject_で作成された、または_Select-Object_や_Import-Csv_などのコマンドレットによって生成された真のPSカスタムオブジェクトを検出するには、次を使用します。

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

関連する_-as_演算子を真のPSカスタムオブジェクトで使用すると、Windows PowerShell v5.1/PowerShell Corev6.1.0以降で機能しなくなることに注意してください。以下を参照してください。

余分な_[psobject]_ラッパーが無害である状況の例として、ラップされたオブジェクトでもそのタイプを直接テストできます。

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

つまり、ラッパーにもかかわらず、_-is_はwrappedタイプを認識します。したがって、いくぶん逆説的に、両方_-is [psobject]_と_-is [hashtable]_は、この場合、これらのタイプが_$True_を返します。無関係。


これらの不一致の正当な理由はありませんそしてそれらは漏れのある抽象化(実装)として私を襲います:内部構造が誤ってカーテンの後ろから覗いています。

次のGitHubの問題では、これらの動作について説明しています。

13
mklement0