1/12/2011

C#のアプリケーションからPowerShell用Azure Service Management Tools CommandLets を使う

前回はAzure SDK 1.3 に PowerShellのAzure Service Management Tools CommandLets をインストールする方法を紹介しましたが、今回はインストールされたCommandLets を使用してC#のアプリケーションからAzureを操作してみます。

と、その前にPowerShellのAzure Service Management Tools CommandLetsのインストーラにはもう一つ罠があり、64bit環境で通常のインストールのままでは、今回紹介する方法は動作しません。64bit環境でも動作させる場合はAzure Service Management Tools CommandLetsのインストーラを少しいじる必要がありますので、その方法は次回紹介します。ですので、今回は32bit環境のWindowsで使用する方法の紹介となります。

PowerShellのAzure Service Management Tools CommandLets 単体の利用方法は、下記のサイトを確認していただければよいと思います。このサイトに紹介されている方法を使ってC#のアプリケーションから操作しますので、これらのサンプルコードは重要です。

http://www.microsoft.com/japan/powerpro/TF/column/st2_01_1.mspx
http://code.msdn.microsoft.com/azurecmdlets/Wiki/View.aspx?title=Sample%20Scripts&referringTitle=Home

では、さっそく方法を紹介します。

1.Visual Studioでプロジェクトを作成
.NET Frameworkを使用するプロジェクトを選択します。コンソールアプリケーションでもWPFでも構いません。

2. System.Management.Automation.dllを参照設定
ソリューションエクスプローラの参照から、System.Management.Automation.dllを参照します。インストールしてある場所は下記の場所です。(64bitな方は、次回紹介します。)

C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll

3.PowerShellを利用するコードを書く
参照したAutomationクラスを使用してPowerShellこのコマンドを実行します。ここで紹介するようにPowerShellクラスを作ると便利です。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using System.Threading;

namespace AzureCommandlets
{
    public class PowershellEventArgs : EventArgs
    {
        public Collection<psobject> CommandResults;
    }

    public delegate void PowershellEventHandler(object sender, PowershellEventArgs e);

    public class Powershell
    {
        public event PowershellEventHandler RunCommandCompleted;

        public void RunAsync(string command)
        {
            List<string> commands = new List<string>();
            commands.Add(command);
            ThreadPool.QueueUserWorkItem((unused) => RunComands(commands));
        }

        public void RunAsync(List<string> commands)
        {
            ThreadPool.QueueUserWorkItem((unused) => RunComands(commands));
        }

        public void RunComands(List<string> commands)
        {
            PowershellEventArgs e = new PowershellEventArgs();

            // Prepares azure management tool commandlets.
            RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
            PSSnapInException snapInException = null;
            PSSnapInInfo info = rsConfig.AddPSSnapIn("AzureManagementToolsSnapIn", out snapInException);
            Runspace myRunSpace = RunspaceFactory.CreateRunspace(rsConfig);
            myRunSpace.Open();

            // Runs commands.
            Pipeline pipeLine;
            pipeLine = myRunSpace.CreatePipeline();
            foreach (string command in commands)
            {
                pipeLine.Commands.Add(new Command(command, true));
            }
            e.CommandResults = pipeLine.Invoke();

            RunCommandCompleted(this, e);
            myRunSpace.Close();
        }
    }
}

インストールされた証明書を表示する場合は下記のように書きます。

static void Main(string[] args)
{
   Powershell ps = new Powershell();
   ps.RunCommandCompleted += new PowershellEventHandler(ps_RunCommandCompleted);
   ps.RunAsync("Get-Item cert:\\CurrentUser\\My\\*");
   Console.ReadLine();
}

static void ps_RunCommandCompleted(object sender, PowershellEventArgs e)
{
   var keys = from c in e.CommandResults
               where (from p in c.Properties
                      where "HasPrivateKey".Equals(p.Name) && true.Equals(p.Value)
                      select p).Any()
               select c;
    foreach (var key in keys)
    {
        Console.WriteLine(string.Format("Subject:{0} Thumbprint:{1}",
               key.Properties["Subject"].Value.ToString(),
               key.Properties["Thumbprint"].Value.ToString()));
    }
}

Hosted Serviceの情報を表示する場合は下記のように書きます。もし、パイプラインを使う場合は一行で書いてください。

static void Main(string[] args)
{
    Powershell ps = new Powershell();
    ps.RunCommandCompleted += new PowershellEventHandler(ps_RunCommandCompleted);
    List<string> commands = new List<string>();
    commands.Add(@"$cert=Get-Item cert:\CurrentUser\My\XXXXXXXXXXXXXXXXXXXXXXXX");
    commands.Add("$sub=\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"");
    commands.Add("$servicename=\"xxxxxxxxx\"");
    commands.Add("Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub");
    ps.RunAsync(commands);
    Console.ReadLine();
}

static void ps_RunCommandCompleted(object sender, PowershellEventArgs e)
{
    foreach (var cmdlet in e.CommandResults)
    {
        foreach (var propInfo in cmdlet.Properties)
        {
            string value = string.Empty;
            try
            {
                if (propInfo != null && propInfo.Value != null)
                {
                    value = propInfo.Value.ToString();
                }
            }
            catch
            {
            }
            Console.WriteLine(propInfo.Name + ":" + value);
        }
    }
}

PowerShellのAzure Service Management Tools CommandLets を使わない方法として、C#のみでアプリケーションを完成させる場合、WebのAPIを直接触るか、Azure Service Management Tools CommandLetsやMMCに含まれている、Microsoft.Samples.WindowsAzure.ServiceManagementのプロジェクトを自分のアプリケーションから利用する方法がありますが、圧倒的にサンプルコード数が多いPowerShellのCommandLetsを使用した方が効率良いのではないでしょうか。