PowerShellのOutputType属性を調べたので覚書

自分は他人が書いたPowerShellのコードをあまり読む機会がなく思わぬところで基礎的な部分が抜けていたりします

で、ごく最近になってからOutputType属性を知ったので、それを調べた時の覚書です


まず、about_Functions_OutputTypeAttribute | Microsoft Docsを読んでみます

The OutputType attribute lists the .NET types of objects that the functions returns. You can use its optional ParameterSetName parameter to list different output types for each parameter set.

The OutputType attribute is supported on simple and advanced functions. It is independent of the CmdletBinding attribute.

The OutputType attribute provides the value of the OutputType property of the System.Management.Automation.FunctionInfo object that the Get-Command cmdlet returns.

The OutputType attribute value is only a documentation note. It is not derived from the function code or compared to the actual function output. As such, the value might be inaccurate.

凄い雑に意訳するとこんな感じででしょうか

  • OutputType属性は関数が返却する.NETオブジェクトの型を一覧 (lists) で、ParameterSetNameパラメーターを使うことができるよ
  • OutputType属性はシンプルな関数と高度な関数 (advanced functions) で使えてCmdletBinding属性とは独立しているよ
  • OutputType属性はGet-Commandコマンドレットの返すSystem.Management.Automation.FunctionInfoOutputTypeプロパティの値になるよ
  • OutputType属性はドキュメンテーションノートだけで、実際の関数の出力は違うかもだ

本文中にもサンプルコードがいくつか示されていますので、それを参考に自分でもコードを書いてみて確認してみます (あくまで引数と戻り値のセットを確認するサンプルコードなので中身はアレですが気にしないでください。あとSwitch内でReturnしていてもBreakを書くのは個人的なコーディング規約です)

Function Get-UserInfo{
    [CmdletBinding(DefaultParameterSetName='Id')]
    [OutputType([String], ParameterSetName='Id')]
    [OutputType([Int], ParameterSetName='Name')]
    param(
        [Parameter(ParameterSetName='Id',Position=0)]
        [Int] $Id,
        [Parameter(ParameterSetName='Name', Position=0)]
        [String] $Name
    )
    Switch ($PsCmdlet.ParameterSetName)
    {
        'Id'{Return 'UserName'; Break}
        'Name'{Return 123456; Break}
    }
}

PS> Get-UserInfo 'UserName'
123456
PS> Get-UserInfo 123456
UserName
PS> Get-Command -Name Get-UserInfo | %{$_.OutputType};
Name          Type          TypeDefinitionAst
----          ----          -----------------
System.String System.String
System.Int32  System.Int32

とりあえず上記のサンプルコードを実行してもりあえずエラーにならず、FunctionInfoのOutputTypeに値が設定されることは分かりました

PS> &([ScriptBlock]{[OutputType([Int])]param()'A';});
A

The OutputType attribute value is only a documentation note. It is not derived from the function code or compared to the actual function output. As such, the value might be inaccurate.とある通り、[OutputType([Int])]としているScriptBlockがString型の 'A' を返却しても、エラーも警告も出ません

OutputType属性で指定した型と異なる出力があったらそこでエラー起こして欲しいところなのですが、それはそれとして、ドキュメント通りのようです


個人的にはOutputType属性は書かないよりは書いておいた方が良いかな、でも、今まで書いてきたコードをわざわざ修正して回るほどでもないな、という認識になりました