PowerShellスクリプトの有効活用

PowerShellでWebサイトにアクセスして情報を取ってきて、その情報をオブジェクト(PSObject)として出力するようなスクリプトを作った。

このスクリプトはあくまでもテスト用に作っただけで、Webサイトへのアクセス方法と情報の取得方法がわかって完全に動作した段階でC#ASP.NETで作り直すつもりでいた。

PowerShellスクリプトでは利用できる範囲が限定されるので、ASP.NETで作り直してWebからアクセスできるようにすればより広範に使えるからだ。もちろんその時はレスポンスをXMLJSONで出力する。

で、PowerShellからC#に書き直そうと思ったんだけど、このスクリプトがテスト用に作ったわりになかなかよくできていた。これは書き直して捨てるのはもったいないなと思って、なんとかこのまま有効活用する手はないかと考え始めた。

・・・・・・・・・!?
ASP.NET上でPowerShellスクリプトを実行して、その出力をレスポンスとして出力すればいいんじゃね?」


そうと決まれば話は簡単。まずはスクリプトXMLを出力する機能を付ける。

doSomething.ps1

param([Switch]$xml)

# なんかサイトにアクセスして、ごちゃごちゃやってオブジェクトをゲット!!
$objs = doSomething

if($xml) {
@"
<?xml version="1.0" encoding="utf-8"?>
<root>
"@
$objs | % {
$id = $_.Id; $name = $_.Name
@"
    <item>
        <id>$id</id>
        <name>$name</name>
    </item>
"@}
@"
</root>
"@
}
else {
    # 今まで通りオブジェクトを出力
    $objs
}

XMLの出力機能はオプションにして「-xml」が指定された時だけにする。

後はこのスクリプトASP.NETのWebページから実行する。

DoSomething.aspx.cs

protected void Page_Load(object sender, EventArgs e) {
    // この場所にさっきのスクリプトを置いているとして
    var scriptPath = Server.MapPath("~/App_Data/script");

    var ri = new RunspaceInvoke();
    // スクリプトを実行できるようにパスを通しておく
    ri.Invoke(string.Format("$Env:Path = '{0};' + $Env:Path", scriptPath));

    var result = ri.Invoke("./doSomething -xml");

    Response.ContentType = "text/xml";
    Response.ContentEncoding = Encoding.UTF8;
    Response.Write(string.Join(Environment.NewLine, result.Select(o => o.ToString()).ToArray()));
    Response.End();
}

「System.Management.Automation.dll」を参照設定しておくことを忘れずに。

これで「/DoSomething.aspx」にブラウザでアクセスすれば、内部でPowerShellスクリプトが実行されてその結果をHttpレスポンスとして取得できる。

こうすればPowerShellスクリプトを有効活用できる。他にも「.ps1」拡張子に対応するHttpHandlerを作って、そこで同様のことをやるというのも一つの手。

こんな風にスクリプトとして単独で使える上にシステムの1コンポーネントとしても機能するPowerShellの使い方っていうのも結構いいんじゃないだろうか?テストも変更もしやすいし、パフォーマンスもちゃんと測ったわけじゃないけどいい感じ。