この記事は、ニフティグループ Advent Calendar 2023 10日目の記事です。
「CLIを使っていて、複数の選択肢から1つ選びたい。なおかつ値を入力するのではなく、カーソルを移動して選択したい。」と思ったことはありませんか?少なくとも私にはありました。
bashにはdialog
コマンドが実装されており、予め設定した選択肢から1つを選択するような操作画面を出すことができます。
しかし、powershellにはそういった機能はありません。正確にはあるにはあるのですが、.NET Frameworkの機能を使って別ウィンドウを新たに生成するといったものになっています。できれば別ウィンドウは開かず、dialog
のようにCLI上ですべて完結したいですよね。
そこで今回は、powershellを用いてdialog
を実装してみようと思います。
つくってみた
array を渡すと選択肢が表示されて、選択した要素のindexが返ってくるようなpowershellコマンドを作ります。
環境
1 2 3 4 5 6 7 8 9 10 11 12 13 |
PS C:\Users> $PSVersionTable Name Value ---- ----- PSVersion 7.4.0 PSEdition Core GitCommitId 7.4.0 OS Microsoft Windows 10.0.19045 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0 |
powershellのモジュールについて
powershellモジュールのディレクトリ構成は以下の様になります。
1 2 3 |
MyPsModule/ └ MyPsModule.psm1 |
作成したモジュールは、.psm1
で保存します。
保存するディレクトリ名とモジュールファイル名は同じにしてください。powershellはモジュール置き場に置かれたディレクトリ名と同じpsm1モジュールを検索して読み込みます。
どこに置けばよいかは、$env:PSModulePath
で確認することができます。
1 2 3 |
PS C:\\Users\\xxxxx> $env:PSModulePath C:\\Users\\xxxxx\\Documents\\PowerShell\\Modules;C:\\Program Files\\PowerShell\\Modules;c:\\program files\\powershell\\7\\Modules;C:\\Program Files\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules |
ここで表示されているいずれかのディレクトリにファイルをモジュールディレクトリを格納してpowershellを再起動すると、自動でモジュールが取り込まれます。
実装
MyPsModule.psm1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
function Show-Dialog { param ( [string[]] $array ) # 何列目を選択中か $row = 0 # メニューカーソルの位置を取得 $firstLine = $Host.UI.RawUI.CursorPosition while ($true) { $counter = 0 # # 情報を1つずつ出力 foreach ($item in $array) { if ($counter -eq $row) { Write-Host "> " -NoNewline Write-Host $($item) -BackgroundColor White -ForegroundColor Black } elseif ($counter -eq ($array.Length - 1)) { Write-Host " " -NoNewline Write-Host $($item) -ForegroundColor White -NoNewline } else { Write-Host " " -NoNewline Write-Host $($item) -ForegroundColor White } $counter++ } $key = [Console]::ReadKey($true) # enterが押されたらrowを格納して終了 if ($key.Key -eq 'Enter') { return $row } # 入力ボタンに応じてrowの値を変更 elseif (($key.Key -eq 'UpArrow') -and ($row -gt 0)) { --$row } elseif (($key.Key -eq "DownArrow") -and ($row -lt ($array.Length - 1))) { ++$row } $cursorPos = $Host.UI.RawUI.CursorPosition $cursorPos = $firstLine $Host.UI.RawUI.CursorPosition = $cursorPos } } Set-Alias -Name dialog -Value Show-Dialog Export-ModuleMember -Function Show-Dialog -Alias dialog |
動作確認
選択肢が表示され、カーソルが動くことを確認しました
まとめ
今回はpowershellでdialog機能を作成してみました。まだまだ荒削りなので、エラー処理ができていなかったり、カーソルが1度でも改行された状態でコマンドを使うとバグが出たりします。
今後はそのあたりもつめつつ、より実用性のあるパッケージにしていきたいです。