ページ

2014-06-03

PSCmdletでもasync/awaitを使いたい

PowerShellコマンドレットをC#で作ること自体は簡単で、単にSystem.Management.Automationアセンブリを参照してCmdletかPSCmdletクラスを継承したクラスを含むクラスライブラリを作るだけなのだけど(このへんを参照→How to Write a Simple Cmdlet) うっかりasync/awaitしたあとにWriteObjectでオブジェクトを出力しようとしたりすると、以下のように怒られてしまう。

Get-SampleCmdlet : WriteObject メソッドと WriteError メソッドは、BeginProcessingメソッド、ProcessRecord メソッド、および EndProcessing メソッドの上書きの外側から呼び出すことはできず、同じスレッド内からだけ呼び出すことができます。コマンドレットで呼び出しが正しく作成されていることを確認するか、または Microsoft カスタマー サポート サービスにお問い合わせください。

Microsoft カスタマー サポート サービスにお問い合わせしたらこんなことも教えてくれるの?と思うところだけど、まぁこういう状況ではSynchronizationContextを提供してあげればよくね?ということでオレオレSynchronizationContextを準備して提供するようにしたのがこのAwaitablePSCmdletクラス

使い方は簡単で、PSCmdletクラスの代わりにこのAwaitablePSCmdletクラスを継承して、BeginProcessing/ProcessRecord/EndProcessingの代わりにAsyncをつけたBeginProcessingAsync/ProcessRecordAsync/EndProcessingAsyncを実装すればいいだけ。
例えばこんな感じ。


本当はStopProcessingにCancellationTokenまわりとか実装しないといけないのだろうけど、たぶんあとは微調整できるレベルだと思うので、必要に応じて。

0 件のコメント:

コメントを投稿