頑張って整形してるコンソールアプリの出力、GridViewで表示したい
内容はタイトルまんまです。
Windows Subsystem for Linuxをいろいろいじくり倒していた際に
wsl.exe --list --verbose
でディストリビューションの稼働状況を見ていたのですが、ふと「これGridViewで見れればなぁ」と思ったのでやってみたところ意外と手こずったので記事にしました。
検証環境
バージョン | |
---|---|
Operating System | Windows 11 |
Windows Subsystem for Linux | 1.0.3.0 |
PowerShell | 7.3.1 |
wsl.exe --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
MSRDC バージョン: 1.2.3575
Direct3D バージョン: 1.606.4
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windowsバージョン: 10.0.22621.1194
Name Value
---- -----
PSVersion 7.3.1
PSEdition Core
GitCommitId 7.3.1
OS Microsoft Windows 10.0.22621
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
1. Null文字を除去しよう
一番最初につまづいたのはPowerShellコンソール上で見ている文字列と実際に出力された文字列が違ったことです。
何で気づいたかってCSVにしたくて頑張って置換処理を書いていたんですが、思った通りに動かなかったのでよくよく見返したからなんですけれどもね。
結論から言うと各文字の間にNull文字が入ってました。
解説すると、例えばNull文字を''
として
''P''o''w''e''r''s''h''e''l''l<CR><LF>
という文字列がコンソールに渡されたとしても、表示上は
PowerShell
と見えます。
テキストエディタに渡したりして見てみるとやっと
<NULL>P<NULL>o<NULL>w<NULL>e<NULL>r<NULL>s<NULL>h<NULL>e<NULL>l<NULL>l<CR><LF>
とNull文字があることに気づきます。
ですので、コンソールアプリの出力からNull文字(文字コードだとchar(00))を除去してやります。
本記事では、例としてwls.exeで導入済みのディストリビューションを一覧表示する場合を取り扱います。
具体的な処理自体は単なる置換処理で
(wsl.exe --loist --verbose) -replace([char](0x00),'')
と出力そのものに対して-replace()を使用してNull文字を「何もない」文字と置換します。
ところでこの出力はそもそも-replace()
かけられるの?という疑問も出てきます。
それについては
# まずはオブジェクト全体の型を確認
# ->この時点では「配列」ということまでしかわからない
(wsl.exe --list --verbose).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
# 配列ならば必ず先頭があるだろうという前提で[0]番目の型を確認した結果
# -> String型であることが確認できる
(wsl.exe --list --verbose)[0].GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
というように複数行で出力されるものであればSystem.Array
型の中にSystem.String
型が入っている
つまり[System.String][]array
をコンソールは受け取ることになります。
したがって、Stringクラスに対してreplaceメソッドを適用するという一般的な処理でNull文字の除去が可能となります。
2. 空行(改行しかない行)を除去しよう
うまい具合にOut-GridView
コマンドで表形式の表示にするためには
- 空行(特に列数が一致しない空行)が除去されていること
- そこそこ正しいCSVになっていること(最低限、各行の列数が一致していること)
が必要です。
ここでは1.について考えます。
先ほど「コンソールアプリの出力がString型の配列だ」(これ前提条件)というのがわかっのたで、各行に対して「もし空だったらその行は無きものにしてね」という処理を書けばよいわけです。
ここでは先人の知恵をお借りして[1] [2] [3] [4]さくっと書いていきます。
(wsl.exe --list --verbose) -replace([char](0x00),'') |
Where-Object {${_}.trim() -ne ""}
パイプライン処理でNull除去したオブジェクトをそのまま渡して""
(空白行)ではないものを返しています。
ここで、単純にやるのであればWhere-Object {${_} -ne "}
とするところですが、上の2.を満たすため空白のみの行もtrimコマンドで空行に変更してから処理を実施しています。
3. 出力中の「空白の連続」を「カンマ区切り」に編集しよう
(※ただし改行はそのままにすること)
ここまででパイプライン出力にはヘッダー行とデータ項目のみが存在するデータになりました。
今度は各行に対して空白(または空白の連続)を","
区切りにする処理をかけていきます(CSV: Comma-Separated Values 形式にしたい)。これはさほど難しくありません。繰り返し処理と正規表現で「空白の1個以上の連続」をすべて","
に置き換えます。
(wsl.exe --list --verbose) -replace([char](0x00),'') |
Where-Object {$_.trim() -ne "" } |
ForEach-Object -Process { $_ -replace "\s+", "," } |
正規表現[5]に関してはとほほの正規表現入門[6]を見ておけばまず間違えないかと思います。
極めるならO'Reilyのフクロウ本[7]を参照するとよいかもしれません。
4. CSV形式に加工した配列をオブジェクトに変換しよう
ここまでくれば、あとはCSVに加工したString型配列をオブジェクトに変換してGridViewにパイプライン処理で渡すだけです。
ここではCSV文字列からなる配列をGridViewが扱うことのできるオブジェクトに変換する方法を確認します。
といってもやることはConvertFrom-Csv
コマンドにCSV形式の文字列を渡して次のパイプライン処理へ出力を渡せばおしまいです。
具体的なコードは次のようになります。
(wsl.exe --list --verbose) -replace([char](0x00),'') |
Where-Object {$_.trim() -ne "" } |
ForEach-Object -Process { $_ -replace "\s+", "," } |
ConvertFrom-Csv | # <-ここでCSVの("a","b","c",...)というのがPS-Objectに変換される
Out-Host # <-この Out-Host がパイプラインで受け取る入力(ConvertFrom-Csvの出力)がオブジェクトになっている
ここでConvertFrom-CSV
に渡す文字列が「完全なCSV」であれば何も起こらないのですが、例えば表1のような(今回のお題であるwsl.exeの出力)の場合はコンソールに警告が出てきます。今回取り扱うデータには※のセルのデータがありません。
※ | NAME | STATE | VRSION |
---|---|---|---|
* | Ubuntu | Stopped | 2 |
Ubuntu-22.04 | Stopped | 2 |
CSVにするとこうなります。
※,NAME,STATE,VRSION<CR><LF>*,Ubuntu,Stopped,2<CR><LF>Ubuntu-22.04,Stopped,2
実行するとエラー表示が出ます。
(画像を取るのがめんどいので、以下、コンソール出力についてはコピー&ペーストで結果を貼り付けます。)
(wsl.exe --list --verbose) -replace([char](0x00),'') |
> Where-Object {$_.trim() -ne "" } |
> ForEach-Object -Process { $_ -replace "\s+", "," } |
> ConvertFrom-Csv | Out-Host -replace "\s+", "," } |
# 以下が出力。
# WARNINGで「ヘッダーが定義されてないよ!!代わりに"H"付きで勝手につけたからね!!」と怒られてる。
WARNING:
One or more headers were not specified.
Default names starting with "H" have been used in place of any missing headers.
H1 NAME STATE VERSION
-- ---- ----- -------
* Ubuntu Stopped 2
Ubuntu-22.04 Stopped 2
それほど使うわけでなければWARNINGのメッセージがでても良いのですが、できることなら気にせず行きたいところです。
そこで、エラーを握りつぶしてコンソールをきれいにするためにConvertFrom-CSV -WarningAction SilentlyContinue
とオプションをつけて実行します。
(wsl.exe --list --verbose) -replace([char](0x00),'') |
> Where-Object {$_.trim() -ne "" } |
> ForEach-Object -Process { $_ -replace "\s+", "," } |
> ConvertFrom-Csv -WarningAction SilentlyContinue | Out-Host
H1 NAME STATE VERSION
-- ---- ----- -------
* Ubuntu Stopped 2
Ubuntu-22.04 Stopped 2
このように実行結果の前に表示されていた警告を非表示にできます。
特に、ログ収集などで「特定の場合にスクリプトがエラーを吐くのはわかっているんだけれどもそれは出力させたくない」という場合などに応用できます。
PowerShellのエラー表示[8]とWariningActionに設定できる値[9]については参考文献8、参考文献9をそれぞれ参照してください。
5. 結果をGridViewで表示しよう
1.~4. まででデータの取得・クリーニング・CSVへの整形・オブジェクトへ変換とパイプライン処理をつないできました。
ここまでくればGridViewへ出力できます。やり方はいたって単純で、パイプライン処理の結果をOut-GridView
へパイプ渡ししてやります。
(wsl.exe --list --verbose) -replace([char](0x00),'') |
Where-Object {$_.trim() -ne "" } |
ForEach-Object -Process { $_ -replace "\s+", "," } |
ConvertFrom-Csv -WarningAction SilentlyContinue |
Out-GridView -Title "List of WSL Status"
以上、扱いづらいデータであってもCSV形式を経由して、いい感じにGUIのテーブル形式で表示できるようになりました。
番外. Microsoft.PowerShell_Profile.ps1に関数として登録する
1.~5.までパイプライン処理を用いてGUIで状況を見られるようにしました。
でもこんなの一々打ち込んでられないので、私はPowerShellのプロファイル(Linuxの.[hoge]shrc
に相当するファイル $PROFILEにパスが格納されている)に関数を作って一発でだせるようにしています。
以下、抜粋です。
Filter Get-WslStatus
{
<#
.SYNOPSIS
WSLの稼働状況を取得してグリッドビューに表示します。
.DESCRIPTION
wsl.exe --list --verboseした結果をCSV形式で構造化した上で
グリッドビューにパイプラインで渡して表示します。
#>
(wsl.exe --list --verbose) -replace([char](0x00),'') |
Where-Object {$_.trim() -ne "" } |
ForEach-Object -Process { $_ -replace "\s+", "," } |
ConvertFrom-Csv -WarningAction SilentlyContinue |
Out-GridView -Title "List of WSL Status"
}
頭にコメントでヘルプメッセージを書いておくと、後で「これなんだっけ?」となった際や、ほかに人に渡した際に「ヘルプ参照してください」で済むので便利です。
何かの参考になれば幸いです。
参考文献
6. とほほの正規表現入門
7. Jeffrey E.F. Friedl 著, 長尾 高弘 訳,"詳説 正規表現 第3版", O'Reily Japan, 2008
8. [Microsoft Learn] Write-Warning
9. [Microsoft Learn] about_CommonParameters - 長い説明