PowerShellでTodo管理 その1
なんとなくTodoアプリを作りたくなったので、PoweShellで作ってみる。
最初はスクリプトで作ろうかと思ったけど、無理がありそうだったのでカスタムProviderでやることにした。
PowerShellの特徴として、種類の違うデータに対して同一のコマンドで操作を行えるというのがある。FileSystemに対してもRegistryに対してもNew-Itemコマンドレットでアイテムの追加ができるというあれ。
この話自体は知っていたけど、実際どんなメカニズムなのか知らないので、それの勉強も兼ねてという意味あいもある。
作りたい物のイメージとしては、
PS Todo:\> dir
出力
完了 タイトル 詳細 ---- ---- ---- false テスト テストです true テスト2 テストでした
実用性は低いけどPowerShellの可能性を垣間見る事はできるかもしれん。
準備
開発環境にはVisual Studio 2005 Professional Edtionを使用する。
PowerShellで独自のCmdletやProviderを作るにはPowerShellをインストールするとGACに登録されるSystem.Management.Automation.dll が必要になる。
GACにしかインストールされていないので、まずはこれを「C:\WINDOWS\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35」フォルダから適当な場所にコピーしてくる。
プロジェクトの作成
「クラスライブラリ」プロジェクトで新規プロジェクトを作成して、先程コピーしたSystem.Management.Automation.dllを参照設定に追加しておく。プロジェクト名は「PSTodo」にしておく。
で、カスタムのProviderを作るわけだが全然情報が無いので、オブジェクトブラウザとにらめっこすること数分。
まず、Provider関係のクラスはSystem.Management.Automation.Provider というそのまんまの名前空間の下にある。
FileSystemProviderとかRegistryProviderというクラスがMicrosoft.PowerShell.Commands という名前空間にあったので、クラス階層を探ってみた。
Providerクラス階層
- CmdletProvider
- DriveCmdletProvider
- ItemCmdletProvider
- ContainerCmdletProvider
- NavigationCmdletProvider
- FileSystemProvider
- RegistryProvider
- SessionStateProviderBase
- AliasProvider
- EnvironmentProvider
- FunctionProvider
- VariableProvider
- NavigationCmdletProvider
- ContainerCmdletProvider
- ItemCmdletProvider
- DriveCmdletProvider
NavigationCmdletProvider を基本クラスとして使っているのがわかる。そこから派生してSessionStateProviderBase という抽象クラスがあるが、ここから派生しているクラスを見ると、この抽象クラスがセッション毎に情報を持つProviderを実装する時に継承するものだということがわかる。
今回作るのはセッション毎に情報を持つわけではないので、NavigationCmdletProviderクラスから派生させることにする。
PSTodoProvider.cs
using System; using System.Management.Automation.Provider; using System.Diagnostics; namespace PSTodo { /// <summary> /// Todo機能を提供するプロバイダクラス /// </summary> [CmdletProvider("Todo", ProviderCapabilities.ShouldProcess)] public class TodoProvider : NavigationCmdletProvider { public TodoProvider() { } protected override bool IsValidPath(string path) { return true; } } }
実装する必要のある抽象メンバは「IsValidPath」メソッドだけなので、とりあえずこれを実装する。これはおそらく引数で渡されたパスが有効なパスかどうかを判断するためのメソッドだと思うので、とりあえずtrueを返しておく。
あと、Providerとして登録するにはCmdletProviderAttribute 属性でクラスをマークする必要があるので、Provider名を「Todo」としてマークしておく。二つ目の引数はよくわからないので、とりあえずProviderCapabilities.ShouldProcess を指定しておく(他のProviderもたいがいこれだったので)。
ここまでで一度PowerShellにこのProviderを登録してみる。
PowerShellに独自のCmdletやProviderを登録するにはPSSnapIn クラスから派生したインストーラクラスを作る必要がある。
この辺のことは以下のサイトを参考にした
TodoSnapIn.cs
using System; using System.Management.Automation; using System.ComponentModel; using System.Diagnostics; namespace PSTodo.Configuration { /// <summary> /// SnapInをインストールするクラス /// </summary> [RunInstaller(true)] public class TodoSnapIn : PSSnapIn { public TodoSnapIn() { } public override string Description { get { return "PowerShellにTodo機能を追加します。"; } } public override string Name { get { return "PSTodo"; } } public override string Vendor { get { return "coma2n"; } } } }
Description、Name、Vendorというプロパティを実装すればOK。
あとはこのプロジェクトをビルドしてできたdllを「installutil.exe」を使ってPowerShellに登録する。
PS > installutil PSTodo.dll
PowerShellを起動して、以下のコマンドを実行する。
PS > Add-PSSnapIn PSTodo PS > New-PSDrive Todo Todo "c:\PSTodo"
New-PSDrive コマンドレットでTodoというドライブ名でTodoプロバイダを「c:\PSTodo」というフォルダをルートにして、新しくドライブをマウントする。
Todoドライブが作れたので、さっそくcdをしてみると、
Set-Location : プロバイダがこの操作をサポートしていないため、プロバイダの実行が中止されました。 発生場所 行:1 文字:3 + cd <<<< todo: