• 【PowerShell】証明書を使用して暗号化したパスワードを復号する

    ※ この投稿は PowerShell Advent Calendar 2011 に参加しています。

    前回以下の投稿をしました。

    【PowerShell】証明書を使用してパスワードを暗号化する

    前回の投稿では、自己署名証明書を作成し、その証明書を使ってパスワードを暗号化しました。

    今回は、前回暗号化したパスワードを証明書を使用して復号してみます。

    前回は、makecert コマンドで作成した証明書の公開キーによってパスワードを暗号化しました。

    今回は復号化する必要があるので、相手側には秘密キーを保持しておいてもらう必要があります。

    ※なんか順番が逆ですが、今回はひとまず気にせず...

    秘密キーを含んだ証明書をエクスポートする方法はおなじみですね。画面遷移を以下に示します。

    imageimageimageimageimageimage

    せっかくなので、PowerShell を使用して秘密キー付証明書(.pfx)をエクスポートする方法も紹介しておきましょう。赤字の部分にはパスワードを入力してください。

    $thumbprint = "13B97E99532151A1FC2617636CB04FE07C43C6C2"
    $Cert = get-item cert:\CurrentUser\MY\$thumbprint
    $bytes = $Cert.Export("Pfx","P@ssw0rd")
    [System.IO.File]::WriteAllBytes("c:\tmp\EncPassword.pfx", $bytes)

    上記では Thumbprint を使用して証明書を取得していますが、以下のように証明書のファイル名を指定することも可能です。

    $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("c:\tmp\EncPassword.cer")
    $bytes = $Cert.Export("Pfx","P@ssw0rd")
    [System.IO.File]::WriteAllBytes("c:\tmp\EncPassword.pfx", $bytes)

    作成された証明書(.pfx)は、相手方(復号する側)の PC にインストールされていなければなりません。

    証明書で暗号化した文字列を復号するには、以下のようなスクリプトを使用します。

    ## 暗号化や復号化に必要な System.Security アセンブリを読み込む
    Add-type –AssemblyName System.Security

    ##暗号化したパスワードのBase64文字列
    $Password = "MIIBlQYJKoZIhvcNAQcDoIIBhjCCAYICAQAxggFGMIIBQgIBADAqMBYxFD.....(略)

    ##証明書の拇印(Thumbprint)
    $thumbprint = "13B97E99532151A1FC2617636CB04FE07C43C6C2"

    ##ユーザーストアのMyから証明書を取得
    $Cert = get-item cert:\CurrentUser\MY\$thumbprint

    ##Base64でエンコードされたパスワードをデコードし、証明書を使って復号化(Decrypt)
    $env = new-object Security.Cryptography.Pkcs.EnvelopedCms
    $env.Decode([Convert]::FromBase64String( $Password ))
    $env.Decrypt( $Cert )

    ##バイト型からストリング型に変換
    [Text.Encoding]::UTF8.GetString($env.ContentInfo.Content)

    どうでしょう?うまくデコードできましたか?

    お互いに公開キーと秘密キーを持ち合うことで、公開キーで暗号化された文字列を秘密キーで復号することができます。昔から使われている手法ではありますが、あらためてPowerShellを使用してもできることも知っておくと何かと便利です。

  • 【WP for ITPro】Windows Phone から直接 Active Directory 認証を行うには ~その4(完結編)

    ※この投稿は Windows Phone Advent Calender 2011 に参加しています
    ※こちらもお勧め
    Windows Phone Advent Calendar "ひとり" 2011 : ATND

    Windows Phone + Active Directory の 4 回目です。過去の投稿は以下より。

    2011年11月28日 Tech Fielders セミナー 「Windows Phone に認証機能を実装する」で使用した資料、ソースコードは以下からどうぞ。当日の収録動画もあります。
    2011/11/28 セミナー資料 Windows Phone アプリケーションに認証機能を実装する

    前回までの作業で準備が整いました(かなり時間が空いてしまいましたが)。ここからは、実際に Active Directory Federation Service からセキュリティトークンを受け取ってみましょう。

    極力シンプルなコードにするために、各パラメタはハードコーディングしますのでご容赦ください。

    はじめに新しい Windows Phone のプロジェクトを作成します。選択するテンプレートは「Windows Phone アプリケーション」でよいでしょう。

    image

    プロジェクトが開いたら、前回作成したライブラリ(IdentityModel.WP7.dll)を「参照設定」に追加します。

    image

    MainPage.xaml ファイルをダブルクリックして開いてください。ここに、ボタンを2つ追加しておきます。1つは SSL 証明書をインストールするためのボタン、もう1つはログオンしてセキュリティトークンを受け取るためのボタンです。今回は極力シンプルにするためにユーザー名やパスワードなどは、すべてハードコーディングしてしまいます。なのでテキストボックスは使いません。

    image

    はじめに、AD FS の SSL 証明書をインストールするための仕組みを実装します。

    「証明書をインストールする」ボタンをダブルクリックしてください。ボタン名が button1 の場合には以下の黄色いマーカーで塗った部分が表示されるはずです。ここに、以下の太字部分を追加してください。using 句で Microsoft.Phone.Tasks を追記するのも忘れないようにしましょう。

    MainPage.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Tasks;

    namespace PhoneApp1
    {
        public partial class MainPage : PhoneApplicationPage
        {
            // コンストラクター
            public MainPage()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, RoutedEventArgs e)
            {
                string CertP7BPath = "
    http://tfdc01.tf.com/adfs.p7b";
                WebBrowserTask webBrowserTask = new WebBrowserTask();
                webBrowserTask.Uri = new Uri(CertP7BPath, UriKind.Absolute);
                webBrowserTask.Show();

            }
        }
    }

    CertP7BPath には、ADFS のサーバー証明書を公開している URL を指定してください。ここでは Webブラウザタスクを呼び出しているため、インストール可能な形式は .p7b です。Windows Phone と証明書の関係については、以下の投稿をご覧ください。

    【WP for ITPro】Windows Phone とルート証明書の関係、自己署名証明書のインストール方法

    ここまでできたら、ためしに実行してみます。F5 キーを押して実行してください。「証明書をインストールする」をタップすると、以下の画面が表示されますか?表示されていない場合には、証明書のパスが異なるか、証明書が p7b 形式ではありません。

    imageimageimage

    ちなみに、ここで使用している WebBrowserTask は、WEBサイトからドキュメントをダウンロードして開くときなんかにも使える便利な手法ですので、覚えておきましょう。

    OK ならばセキュリティトークンを取得するコードを書きましょう。

    まずは、参照設定で System.ServiceModel を追加してください。これは、コードの中で EndpointAddress クラスを使用するためです。

    imageimage

    MainPage.xaml を開いて、「セキュリティトークンを取得」ボタンをダブルクリックしてください。以下のように button2_Click イベントハンドラが追加されます。ここに、セキュリティトークンを取得するためのコードを書きこんでいきます。

    はじめに、using 句で、冒頭で参照設定したライブラリの名前空間(SL.IdentityModel.Claims、SL.IdentityModel.Protocols.WSTrust)と、System.ServiceModel を追記しておきます。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Tasks;
    using SL.IdentityModel.Claims;
    using SL.IdentityModel.Protocols.WSTrust;
    using System.ServiceModel;

    namespace PhoneApp1
    {
        public partial class MainPage : PhoneApplicationPage
        {
            // コンストラクター
            public MainPage()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, RoutedEventArgs e)
            {
                string CertP7BPath = "
    http://tfdc01.tf.com/adfs.p7b";
                WebBrowserTask webBrowserTask = new WebBrowserTask();
                webBrowserTask.Uri = new Uri(CertP7BPath, UriKind.Absolute);
                webBrowserTask.Show();
            }

            private void button2_Click(object sender, RoutedEventArgs e)
            {
                ここにコードを追記する
            }
        }
    }

    button2_Click イベントハンドラに以下のようなコードを追記し、さらに client_IssueCompleted も追記します。セキュリティトークンの取得は非同期で行われるため、_client.IssueAsync  の呼び出しから応答が戻るのを、client_IssueCompleted で待ち合わせているわけですね。

    WSTrustClient _client; がイベントハンドラの外に飛び出していますが、これは他の関数でも使用するためです。場所的にお行儀が悪いですが、ここではよしとしてください。

    WSTrustClient _client;

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        string EndPoint_WSTrust = "
    https://tfadfs.tf.com/adfs/services/trust/13/usernamemixed";
        string EndPoint_RP = "https://www.junichia.com/";
        st
    ring UserName = "tf\\administrator";
        string Password = "P@ssw0rd";

        _client = new WSTrustClient(
            new WSTrustBindingUsernameMixed(),
            new EndpointAddress(EndPoint_WSTrust),
            new UsernameCredentials(UserName, Password));

        var rst = new RequestSecurityToken(WSTrust13Constants.KeyTypes.Bearer)
        {
            AppliesTo = new EndpointAddress(EndPoint_RP)
        };

        _client.IssueCompleted += client_IssueCompleted;
        _client.IssueAsync(rst);

    }

    void client_IssueCompleted(object sender, IssueCompletedEventArgs e)
    {
        _client.IssueCompleted -= client_IssueCompleted;

        if (e.Error == null)
        {
            MessageBox.Show(e.Result.RequestedSecurityToken.RawToken.ToString());
        }
        else
        {
            MessageBox.Show(e.Error.Message);
        }
    }

    コードはたったこれだけです。これだけでADFSからセキュリティトークンを受け取ることができます。

    なお、以下の4つの変数には、それぞれユーザー環境での値を入力してください。

    • string EndPoint_WSTrust = "https://<ADFSサーバー名>/adfs/services/trust/13/usernamemixed";
    • string EndPoint_RP = "<ADFSの管理コンソールに追加した証明書利用者信頼>";
    • string UserName = "<ドメイン名>\\<ユーザー名>";
    • string Password = "<パスワード>";

    UserName に指定する<ドメイン名>と<ユーザー名>の間には2つのエンサイン(\\)が入るので注意しましょう。エンサイン1つだけでは特殊文字として認識されてしまいます。

    実際に実行してみましょう。

    実行結果はメッセージボックスに表示されるようにしています。

    はじめに証明書のインストールを行わないと、Issure (ADFSサーバーのこと)が見つからない旨のエラーが表示されてしまうので注意してください。

    以下のような画面が表示されましたか?

    image

    少しスクロールすると、ADFSで設定したクレームの内容が含まれていることがわかります。

    image

    サンプルプロジェクトおよび AD FS の設定方法等については、2011/11/28 セミナー資料 Windows Phone アプリケーションに認証機能を実装する に掲載してありますので、参考にしてください。

    以上完結です。

  • 【WP/Azure for ITPro】Windows Phone から Windows Azure AppFabric ACS を使用する

    ※この投稿は Windows Azure Advent Calender に参加しています

    Windows Phone で Windows Azure AppFabric Access Control Service からセキュリティトークンを受け取るにはためには、面倒なコードを書く必要があります。でも安心してください。うってつけのライブラリがあります。

    必要なソフトウェアは以下の2つです。

    Windows Phone SDK は Windows Phone アプリの開発環境なので、ここでの説明はよいでしょう。

    ■Windows Phone 用 ACS コントロールの準備

    重要なのは、Windows Azure Platform Training Kit(WAPTK) です。WAPTK を解凍すると、C:\WAPTK 配下に自習用のラボファイルが作成されます。この中に、Windows Phone 用のライブラリが用意されてます。

    以下のフォルダが、Windows Phone 用の ACS用ライブラリです。

    C:\WAPTK\Labs\ACS2andWP7\Source\Assets\SL.Phone.Federation

    Visutal Studio 2010 Express for Windows Phone(Windows Phone SDK をインストールすると一緒にインストールされます)で、上記フォルダの直下にある SL.Phone.Federation.csproj を開いてください。

    開いたらソリューションエクスプローラーでプロジェクト名を右クリックし、「Windows Phone 7.1 にアップグレード」を選択します。これにより、Windows Phone 7.1 OS に合ったプロジェクトに変換されます。

    imageimage

    ソースは何もいじらずに、ビルドしちゃいましょう。

    ビルドした結果が、C:\WAPTK\Labs\ACS2andWP7\Source\Assets\SL.Phone.Federation\Bin\Debug の下に、SL.Phone.Federation.dll というファイル名で作成されます。

    これは後で使います。

    ■ AppFabric ACS の準備

    Windows Azure の管理コンソールから、AppFabric ACS 管理コンソールを開きます。

    もし名前空間を作成していなければ、[新規作成] をクリックして作成してください。作成した名前空間は後から使用するので覚えておいてください。

    image

    名前空間が作成できたら、作成した名まえ空間を選択し「アクセス制御サービス」をクリックします。

    名前空間の環境設定画面が開くので、はじめに ID プロバイダーを選択します。今回は、Google と Windows Live を使用することにしましょう。

    image

    次に、「証明書利用者アプリケーション」をクリックしてください。

    [追加]ボタンをクリックし、必要な情報を埋め込みます。今回は以下のように指定しました。

    image名前:testapp

    領域(Realm):uri:techfielders

    戻り先URL:http://tf.com/

    トークン形式:SWT


     

    上記の画面で重要なのが、領域です。この値は後からアプリに埋め込むので間違えないでください。uri: 以降は適当な値を指定して大丈夫です。uriを指定する以外に、http://tf.com/ 等アプリのURLで指定することも可能です。もしアプリケーションを作成しているならば、それに合わせたURIを指定しますが、今回は作成していないので適当に指定しました。動作検証上は何の問題もありません。

    戻り先URLも適当な値で大丈夫です。この値はセキュリティトークンの発行先となりますが、これを指定しないとセキュリティトークンは発行されません。

    トークン形式は、今回はSWT(Simple Web Token)を選択しました。

    次に規則グループを作成します。

    管理画面の左側のメニューで「規則グループ」をクリックしてください。

    [追加]をクリックすると規則グループの名前を入力する画面が表示されるので、testrule などと適当に入力して[保存]をクリックします。

    以下の画面が表示されたら、[生成]をクリックします。

    image

    以下の画面で IDプロバイダーを選択して、「生成」ボタンをクリックすると、ルールが自動的に生成されます。

    image

    最後に、必ず「保存」してください。

    image

    もう一度「証明書利用者アプリケーション」を開き、下のほうにある「規則グループ」で先ほど作成したルールを選択し、保存します。

    image

    最後に、トークンを署名するためのキーを作成します。

    管理画面の左側のメニューから「証明書およびキー」をクリックしてください。

    以下の画面が開くので、対称キーを選択して、キーを生成します。このキーを使用してセキュリティトークンを暗号化します。

    image

    最後に保存してACSの設定は完了です。

    後で以下の2つの情報を使用します。

    • 作成した名前空間(ここでは testapp)
    • 領域(ここでは uri:techfielders)

    ■Windows Phone から ACS にアクセスするアプリの作成

    Visual Studio を起動し、[新しいプロジェクト」を選択し「Silverlight for Windows Phone」を選択してください。

    テンプレートの種類は「Windows Phone アプリケーション」でよいでしょう。

    プロジェクトの名前は何でもOKです。

    プロジェクトが開いたら、「参照の追加」で先ほど作成したライブラリを読み込みましょう。今回はこれ以外に追加するライブラリはありません。

    image

    コードを細かく解説する時間とスペースが無くて恐縮なのですが、以下にサンプルプロジェクトをアップロードしてありますので参考にしてください。ライブラリも含めてあるので、ひとまずこのプロジェクトだけでテストすることが可能です。

    サンプルプロジェクト(ライブラリ含)

    1点だけ、ACS の環境に合わせて変更しなければならないのが App.xaml です。

    App.xaml の Application.Resource に、ACS の名前空間(Namespace)と領域(Realm)を指定している部分があります。ここは先に作成した ACS の環境に合わせて修正してください。

    image

    以上を修正して実行すれば以下のように IDプロバイダーの選択画面が開きます。

    image

    グーグルを選択すれば、グーグルのモバイルログオン画面が開きます。

    image

    正しく認証されると、以下のようにSWTがメッセージボックスで開くようにしてあります。

    image

    OKをクリックすると、クレームタイプとクレームの値を表示します。

    image

    是非試してみてください。

  • 【IDM】テキストファイルを AD FS のカスタム属性ストアとして登録してみる その1

    やっとこの話題に触れることができます。なぜ触れなかったかというと、全くテストしていなかったから...すんません。

    TechNet に以下の記事が用意されています。この記事では、独自の属性ストア(テキストファイル)を作成して実装する手順が紹介されています。

    AD FS 2.0 Attribute Store Overview(英語)

    英語ということもあり読むのも面倒ですし、せっかくなのでここでご紹介します。

    AD FS の既定の属性ストアは以下の通りです。

    • Active Directory Domain Service
    • Active Directory Lightwaight Directory Service
    • SQL Server

    SQL Server を属性ストアとして使用する場合には、以下に示す手順に従って登録する必要があります。

    【IDM】AD FS 2.0 で属性ストアとしてSQL Server を使用する

    では、これ以外の属性ストア(例えばテキストファイルとか Facebook とか)を使用したい場合にはどうしたらよいかといえば、独自のクラスライブラリを作成して、AD FS にカスタム属性ストアとして登録する必要があります。

    image

    クラスライブラリの仕事は何かというと、AD FS からクエリーを受け取り、指定された属性ストアからデータを検索して AD FSに返してあげる...とうことです。理屈は単純ですね。

    image

    そうすると、実装すべきものは見えてきます。

    • AD FS のお作法にのっとって、クエリーや結果の受け渡し部分をコーディング
    • カスタム属性ストアにアクセスしてクエリーに合致したデータを検索する
    • クエリーや属性ストアに不備があればエラーとしてAD FSに返してあげる

    といった感じです。単純ですね。

    今回はテキストファイルをカスタム属性ストアとして使用しますが、作りさえすれば ORACLE だろうが OpenLDAPだろうが Facebook だろうがカスタム属性ストアとして使用することができます。SQL Azure だって問題ありません。なんなら 属性が存在しなければ 利用者に手入力させる...なんて仕組みも作れないわけではありません。

    ただ、いずれにしても Active Directory 認証が必須であることには変わりないので注意してください。AD 認証されたことを前提に、AD FS がクラスライブラリを呼び出します。なので、AD の代わりに Oracle Identity Managger を認証プロバイダーとして使用する...ということはできません。これは AD FS の仕様です。

    では、そのクラスライブラリはどうやって作るのでしょうか...IT Pro 向けに手順をきっちりご紹介します。

    1. カスタム属性ストアの識別名を決めておく

    はじめに、属性ストアの識別名を決めます。ここでは、TextFileAttibuteStore としましょう。

    2. カスタム属性ストアの仕様を決める

    どんな属性ストアかを定義しておかなければコーディングに入れません。

    今回は、以下のような CSV ファイルをカスタム属性ストアとして使用することにします。1行目はヘッダーです。ヘッダーが無いと検索が不便なので必ず付けましょう。

    EmpId,WindowsID,Age,Dept,Role
    1,Akiko,18,HR,Manager
    2,junichia,25,UX,Evangelist
    3,Shinobu,40,Marketing,Evangelist
    4,Akira,43,IT,Admin
    5,Kazunori,49,UX,Manager

    重要なのはカラムの位置です。クラスライブラリは極力ヘッダー名に依存しないようにコーディングしますが、位置が変わると面倒なので、ここでしっかり決めておきましょう。

    3. クエリーの仕様を決める

    AD FS が属性ストアを検索するには、専用のクエリ言語を使用してクレームルール(要求規則)を作成する必要があります。AD FS の管理コンソールを使用すると GUI を使ってクレームルールを作成することができますが、カスタム属性ストアを使用する場合には自分でクレームルールを作成する必要があります。

    自分で記述したクレームルールを「カスタムルール」と呼んでいます。

    カスタムルールについて説明を始めるときりがないので、過去の投稿および資料を参考にしてください。

    (参考) カスタムルールについて

    今回は、Windows のログオン ID で CSV ファイルを検索し、合致したら Age と Role を返すようにしましょう。これをカスタムルールで記述すると以下のようになります。

    c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
    => issue(store = "TextFileAttributeStore", types = ("http://schemas.tf.com/age", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"),
    query = "WindowsID={0};Age,Role", param = c.Value);

    カスタムルールに慣れていないと、なんのこっちゃわからないと思いますが、書いてあることは非常に単純です。

    1行ずつ見ていきましょう。ちょっと難しいので根気よく読んでください。

    c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]

    この行は、次の行にある「issue(発行する)」を実行するための条件文です。Type とはクレームタイプ(要求の種類)のことであり、http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname というクレームが入力方向に存在していれば...という意味になります。クレームタイプは Key-Value-Pair(KVP)の Key に当たるものだと思ってください。

    http://~~~~/windowsaccountname は Winodws にログオンしたときのユーザーIDが格納されているクレームタイプです。

    ここで「入力方向」の意味が分からない方がいらっしゃるかもしれません。入力方向とは「要求規則」に対する入力のことです。入力方向のクレームを、要求規則によって書き換えたり置換したり、破棄したり、出力方向のクレームが決定されるわけですね。

    image

    さて、もう1つ意味不明な記述がありますよね。先頭にちゃっかり書かれている「c」です。これは、指定されたクレームタイプをオブジェクトとして格納するための変数だと思ってください。つまり、http://~~/windowsaccountname が格納されています。これはあとで使用します。

    ここまでの説明がさっぱり???だという方は、我慢して次に進んでください。すこしずつ見えてくるはずです。ここを乗り越えることが AD FS プロフェッショナルへの第一歩です。

    => issue( ~~~~ )

    これはわかりますよね。この前の行の条件が満たされたら「 => 」以降を実行するという意味です。実行するのは issue 、つまり「発行する」ということですね。何を発行するのかは、()カッコ内に書かれています。

    store = "TextFileAttributeStore"

    発行するクレームが格納されているクレームストアの識別名を指定しています。もしクレームストアが Active Directory ならば「Active Directory」と指定します。1. で TextFileAttibuteStore と決めたことを思い出してください。

    types = ("http://schemas.tf.com/age", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role")

    ここで指定している Type もクレームタイプなのですが、今度は出力方向のクレームのタイプです。つまり、発行されるクレームタイプですね。ここでは、2つのクレームタイプを指定しています。agerole ですね。

    query = "WindowsID={0};Age,Role", param = c.Value

    これがテキストファイルを検索するためのクエリーです。非常に特徴的な記述法ですが、難しくはありません。

    WindowsID={0} は Where 句に相当します。つまり、テキストファイル「TextFileAttributeStore」内の WindowsID 列が「{0}」と合致したら...という意味です。{0} には param に指定された0番目の値が入ります。つまり、c.Value です。

    もうわかりましたね。c には http://~~/windowsaccountname がオブジェクトとして入っていると書きましたが、その Value 、つまり「値」を意味しています。

    もし、administrator というユーザーがログオンしたとすれば、c.Value は administrator になります。

    ここまでくれば、Age,Role は言わずもがなです。

    windowsaccountname が c.Value に合致した行の Age と Role を結果として返すという意味になります。もちろんその値はクレームタイプに格納します。

    Age 列 → http://schemas.tf.com/age
    Role  列 → http://schemas.microsoft.com/ws/2008/06/identity/claims/role

    もちろん、条件に合致しなかったり、CSVファイルに値が存在しない場合には、クレームタイプの中身は空のままで返されます。

    上のCSVファイルを見てください。もし windowsaccountname に junichia が格納されていたら、age=25、role=Evangelist が返されるということになります。

    ひとまずここまで。

    次回は実際にクラスライブラリを作ります。

  • 【PowerShell】Windows PowerShell を使用してメールに返信する

    ※この投稿は PowerShell Advent Calender に参加しています。

    前回、以下の投稿をしました。

    【Management】Windows PowerShell を使用して GMail や Office 365 からメールを送信する

    では、もう半歩だけ踏みこんで、PowerShell を使用してメールに返信するにはどうしたらよいか?

    なんで「返信」したいかというと、スレッド表示にしたいからです。多くのメーラーにはスレッド表示機能が実装されています。Outlook も例外ではありません。スレッド表示はとても便利です。ちなみに、Windows Phone に実装されている OUTLOOK Mobile もスレッド表示ができます。

    スレッド表示をするには、返信されてきたメールに所定のヘッダーが埋め込まれている必要があります。それが、In-Reply-To ヘッダーと References ヘッダーです。正直、RFC を読み込んでいないのでアレなのですが(すんません...orz)、OUTLOOKの場合、In-Reply-To に埋め込まれている Message-ID を使用してスレッドを構成しているようです。ただ、In-Reply-To が無い場合には、References を参照しているみたいですね。

    ここで、元のメールの Message-ID の値が xxxxxxxxxxx@mail.gmail.com だとしましょう。さらに、xxxxxxxxxxx@mail.gmail.com の親メールが yyyyyyyyyyy@mail.gmail.com だとしましょう。

    このメールに返信するには、以下のようなスクリプトを書きます。以下の例では、gmail を使用して、user9999@gmail.com というユーザーがメールを送信しています。

    ##SMTP認証するためのユーザーIDとパスワード
    $Cred_UserID = "user9999@gmail.com"
    $Cred_Password = "password"

    ##In-Reply-To にセットする Message-ID と References
    ##いずれも<>で囲む
    $InRelyTo = "<xxxxxxxxxxx@mail.gmail.com>"
    ## Referencesが複数必要な場合には半角空白で区切る
    $References = "<yyyyyyyyyyy@mail.gmail.com> <xxxxxxxxxxx@mail.gmail.com>"

    ##メールの送信先。複数指定することができる。
    $To = @("hogehoge0000@gmail.com","hogehoge9999@gmail.com")
    $Subject = "タイトル"
    $From = "user9999@gmail.com"
    $Body = "本文"
    $SmtpServer = "smtp.gmail.com"

    ##送信するメッセージを作成
    [System.Net.Mail.MailMessage]$newMessage = New-Object System.Net.Mail.MailMessage

    ##送信先や送信元等を newMessage にセットする
    foreach ($name in $To) {
          $newMessage.To.Add(($name))
    }
    $newMessage.From = $From
    $newMessage.Sender = $From
    $newMessage.Subject = $Subject
    $newMessage.Body = $Body
    $newMessage.Headers.Add("In-Reply-To", $InRelyTo)
    $newMessage.Headers.Add("References", $References)

    $client = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
    $client.EnableSsl = $True
    $client.Credentials = New-Object System.Net.NetworkCredential($Cred_UserID, $Cred_Password);

    ##送信
    $client.Send($newMessage)


    今回は In-Reply-To や References を使用しましたが、System.Net.Mail.MailMessage を使用すると、必要なヘッダーを自由に生成することができます。

    使い道は限られますが、例えばシステムが受信したメールに対して自動返信するような仕組みを生成する場合には、このように In-Reply-To ヘッダーを埋め込んで送信してあげると、受信者はスレッドで表示することができるのでメッセージの見逃しを防止できます。

    それにしても...詳しい方、正しい In-Reply-To と References の使い方を教えてください....。