【PowerShell】自作コマンドレットの結果をパイプラインに渡すときに補完を効かせるようにする

# TL;DR

- 自作コマンド（関数もかな？）をパイプラインに渡したときに`Where-Object`などで結果を抽出するとき、プロパティの補完が効かなかった
- 関数の定義内に`OutputType[]`で適切な型を定義すると解決する
- `OutputType[]`には複数の型を定義できる


# つくった関数（これは補完が効かない）

```powershell
function Get-RecentItems {
	$recentFolderLists = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Recent)
	Get-ChildItem "$($recentFolderLists)\*.lnk" | Sort-Object -Property LastWriteTime -Descending
}
```

「最近使った項目」のフォルダから拡張子が`lnk`のものだけを引っ張って表示するという関数です。
実行するとこんな感じになります。

```powershell
PS C:\Users\Test> Get-RecentItems


    ディレクトリ: C:\Users\Test\AppData\Roaming\Microsoft\Windows\Recent


Mode                LastWriteTime         Length Name                                                                                                                               
----                -------------         ------ ----                                                                                                                               
-a----       2019/08/06     15:50            661 WindowsPowerShell.lnk                                                                                                              
-a----       2019/08/06     15:50           1003 Microsoft.PowerShellISE_profile.ps1.lnk
```


## やりたかったこと

- `Where-Object`を使って、特定の`lnk`ファイルだけを表示する

これをやりたかった理由は、`lnk`ファイルを指定すると、そのディレクトリへ移動するというコマンドを作成したので、それに利用するためです。

## やってみた

補完が効かない。

```powershell
Get-RecentItems | ? {$_. # 本当なら'Name'を補完を効かせて入力したかったができず
```

## `OutputType[]`を定義する必要があると知る

```powershell
function Get-RecentItems {
	[OutputType([String])] # これだよ！
	Param()
	$recentFolderLists = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Recent)
	Get-ChildItem "$($recentFolderLists)\*.lnk" | Sort-Object -Property LastWriteTime -Descending
}
```

さっきの関数の中身を書き換えました。
`OutputType[]`を使うには`Param()`が**必須**とのこと。

これを定義すれば、補完が効くようになりました。

## 補完は効くようになったが想定している結果になってない

```powershell
Get-RecentItems | ? {$_. # 出てくるのは'ToChar'とか'Equals', 'GetType'とか...。
```

想定していたプロパティ名`Name`は補完に出てきませんでした。

## `OutputType[]`で指定した型に誤りがあったと知る

そもそも、プロパティ名`Name`や`LastWriteTime`は何の型を指定したら出てくるものなのか？
これらのプロパティ名は`Get-ChildItem`でも見たなあと思って、調べてみました。

```powershell
PS> (Get-Command Get-ChildItem).OutputType

Name                    Type                    TypeDefinitionAst
----                    ----                    -----------------
System.IO.FileInfo      System.IO.FileInfo                       
System.IO.DirectoryInfo System.IO.DirectoryInfo
```

`System.IO.FileInfo`と`System.IO.DirectoryInfo`みたいです。

# 補完が効くようになった

```powershell
function Get-RecentItems {
	[OutputType([System.IO.FileInfo], [System.IO.DirectoryInfo])] # ここを書き直したよ！
	Param()
	$recentFolderLists = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Recent)
	Get-ChildItem "$($recentFolderLists)\*.lnk" | Sort-Object -Property LastWriteTime -Descending
}
```

`OutputType[]`は複数指定ができるとのことで、さっき調べて出てきたものをそのまま突っ込むことにしました。

これでめでたく補完が効くようになりました。

こんな感じです。

```powershell
PS C:\Users\Test> Get-RecentItems | ? {$_.Name -match 'powershell'}


    ディレクトリ: C:\Users\Test\AppData\Roaming\Microsoft\Windows\Recent


Mode                LastWriteTime         Length Name                                                                                                                               
----                -------------         ------ ----                                                                                                                               
-a----       2019/08/06     15:50            661 WindowsPowerShell.lnk                                                                                                              
-a----       2019/08/06     15:50           1003 Microsoft.PowerShellISE_profile.ps1.lnk
```


嬉しい。（おわり）

# バージョン情報

```powershell
PS C:\Users\Test> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      18362  145  
```

# 参考

- [Register-ArgumentCompleter で 入力補完機能を自作しよう！ - pierre3のブログ](https://pierre3.hatenablog.com/entry/2015/12/08/222338)
- [PowerShell で 関数実行結果の型をパイプラインの先に伝搬する - tech.guitarrapc.cóm](https://tech.guitarrapc.com/entry/2015/01/20/034358)