読者です 読者をやめる 読者になる 読者になる

銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

PowerShell を C# から実行する

C# PowerShell

PowerShell Advent Calendar 2013 : ATND 10日目のエントリです。

以前発表した資料の中にもあるのですが、弊社で運用を自動化するためにPowerShellでスクリプトを書いているのですが、簡単に操作できるようにGUIツールをWPFで作って、その中からPowerShellスクリプトを実行しています。本当はこのツールでの操作を含めて自動化できるといいのでしょうが、そこは自動化コストとの兼ね合いを考えて今の形になっています。というわけで、C# から PowerShell を実行する基本的なところを紹介したいと思います。

C# から PowerShell を実行しようと考えたとき真っ先に思いついたのは Process.Start でした。

var psInfo = new ProcessStartInfo
{
    FileName = "powershell.exe",
    CreateNoWindow = true,
    UseShellExecute = false,
    Arguments = "Get-ChildItem",
    RedirectStandardOutput = true
};
var p = Process.Start(psInfo);
Console.WriteLine(p.StandardOutput.ReadToEndAsync().Result);
Console.ReadKey();

この例だと期待した通りの結果が得られるのですが、本番で利用しているスクリプトについては実行できないという問題が発生しました。原因までは突き止めなかったのですが、おそらく呼び出すScriptの内部で新たにRunSpaceを作っているのが問題なのでは...?というところまであたりをつけていました。

で、さらに調べていくと、 System.Management.Automation.dll というライブラリを見つけました。これを使うと、.NET Framework から Powershellを実行でき、その結果をPSObectというオブジェクトで取得することができるのです。PowerShellの売りの一つに、実行結果が単なる文字列ではなくてオブジェクト、というのがありますから、その売りをC# でも利用することができるのです。

上の例を System.Management.Automation.dll を使って書き直してみましょう。

まず、System.Management.Automation.dll を追加します。Windows8などPowerShell 3.0が使えて、VisualStudioをインストールしていれば、 C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll にあるはずです。

コードとしては、System.Management.Automation.Runspaces.RunSpace -> System.Management.Automation.PowerShell を作成して、Invoke メソッドを呼ぶことで実行し、実行結果をPSObjectのコレクションとして取得できます。実行結果はPSObjectの Propertiesにプロパティ名を指定して、Valueを取ることで取得できます。

さて、このRunSpaceはPowerShellリモーティングを使ってリモートコンピューターでPowerShellを実行してその結果を取得することもできます。こんな感じ。

System.Management.Automation.Runspaces.WSManConnectionInfo というので接続先情報を設定します。↑の例はAzure上の仮想マシンの場合の例です。ポートはAzure側の設定でPowerShellリモーティングを有効するときに指定したポートになります。ユーザーとパスワードも仮想マシン作成時に指定したユーザーとパスワード、証明書(CA)の検証を無効化しています。この設定をRunSpace作成時の引数に与えてやるだけで、あとはローカル実行時と同じ要領で結果を取得することができます。

という感じに簡単な例でしたが、PowerShellをC#から実行する方法を紹介しました。 さて、第1回 PowerShell勉強会 : ATND が弊社にて開かれます。すでに定員オーバーなのですが、私はこのブログでやった PowerShellをC#から実行する方法をもう少しいろんなパターンを使って紹介したいと思っています。(登録された方は)ぜひお越しください。