質問: フォルダ内にある複数のテキストファイルから、何らかの文章が含まれるファイルパスを抽出するワンライナーを作成しました ``` Get-ChildItem -include *.xml -Recurse | sls 'Target String' | Select-Object -Unique Path ``` このワンライナーの結果が下記のように1つ以上検出された場合、検出されたファイルの中からどれか一つのファイルを選択して開く方法はありますでしょうか? > > D:\tmp\sample1.xml > > D:\tmp\sample2.xml > > D:\tmp\sample3.xml > > D:\tmp\sample4.xml > > ... > > > 開くファイルを選択する条件は限定しません インデックスで指定する、検出したパスのうち最初/最後を指定するなど、何でも構いません また、上記のワンライナーに変更を加えていただいてもかまいません ただし、検出されたファイルが1つの場合も複数の場合も同じワンライナーでファイルを開く方法が望ましいです
回答: ワンライナーが必須要件ならば下記のコードで実現できます。 ``` Get-ChildItem -include *.xml -Recurse | sls 'Target String' | Get-Item | Out-GridView -Title 'ファイルを選択してください' -PassThru | Invoke-Item ``` ワンライナー以外で選択肢を表示したい第三者に有益な回答と信じて、以下で`PromptForChoice`や`Out-GridView`を使う複数行のサンプルコードを提示します。 他にもfor文とWrite-Hostの組み合わせを使って自前で選択肢を表示する方法やSystem.Windows.Formsを使ってリストボックスを作成する方法などもあります。 ※エラー処理はしていません。 ※「開く」処理を拡張子に応じた関連付け実行と解釈して`Invoke-Item`しています。 1. PromptForChoice)を使う 基本的に横並びの選択リストです。 コンソール画面で作業を完結できます。 ``` $files = Get-ChildItem -include *.xml -Recurse | sls 'Target String' | Select-Object -Unique Path $options = @() foreach ($item in $files) { $i = $files.IndexOf($item) $name = ($files[0] | Get-Item).Name $options += New-Object System.Management.Automation.Host.ChoiceDescription("${name}(&${i})") } $selectedIndex = $host.ui.PromptForChoice('選択', 'ファイルを選択してください', $options, 0) $selectedPath = $files[$selectedIndex].Path Invoke-Item "$selectedPath" ``` 2. Out-GridViewを使う Windows PowerShellならば特に何もせず使えます。 PowerShell Coreでは未サポートですがリンク先のモジュールを入れれば使えます。 GUIを自動作成して選択リストを表示してくれますが、フルパスを表示できないなど階層化された複数フォルダからの選択は苦手なようです。 ``` $files = Get-ChildItem -include *.xml -Recurse | sls 'Target String' | Get-Item $selectedPath = $files | Out-GridView -Title 'ファイルを選択してください' -PassThru Invoke-Item $selectedPath ```