C#からOffice365でメールエイリアスを作成

Office365で動的にメールエイリアスを作る必要があったので簡単にメモ。
APIを使って変更したかったけどPowerShellからの操作しか見当たらないのでそれで対応。


## Office365のアカウント
メールエイリアスを取り扱うには管理者権限が必要。

## PowerShellのバージョン
テスト用のWindows7環境だとPowerShellのバージョンが2.0になっていてそのままでは動かず。
4.0にバージョンアップしてみたところ問題なかった。

[PowerShell/PowerShellのバージョンを確認する方法・$PSVersionTable - Windowsと暮らす](http://win.just4fun.biz/PowerShell/PowerShell%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%83%BB$PSVersionTable.html)
[Download Windows Management Framework 4.0 from Official Microsoft Download Center](https://www.microsoft.com/ja-jp/download/details.aspx?id=40855)


## ツールのインストール
必要なソフトウェアとして紹介されている2種をダウンロードしてインストール。

[Connect to Office 365 PowerShell](https://technet.microsoft.com/JA-JP/library/dn975125.aspx)

* IT プロフェッショナル 用 Microsoft Online Services サインイン アシスタント RTW
* Windows PowerShell の Microsoft Azure Active Directory モジュール の 64 ビット バージョン


## スクリプト実行の許可
デフォルトではインストールしたコマンドをPowerShellで実行できないらしい。
以下のコマンドで実行可能にする。ScopeはCurrentUser|Processなどがあるらしいので適切なものを選択。

```PowerShell
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
```


## PowerShellでのコマンド
発行する必要があるPowerShellでのコマンドは以下の通り。

```PowerShell
#モジュールのインストール
Import-Module MSOnline

# アカウントの認証
$UserCredential = Get-Credential
Connect-MsolService -Credential $UserCredential

# office365との接続
$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $UserCredential -Authentication "Basic" -AllowRedirection

# セッション情報の保管
Import-PSSession $exchangeSession

# 作成
Invoke-Command -ScriptBlock { Set-Mailbox アカウント名 -EmailAddresses @{Add="エイリアス名"} } -Session $exchangeSession

# 削除
Invoke-Command -ScriptBlock { Set-Mailbox アカウント名 -EmailAddresses @{Remove="エイリアス名"} } -Session $exchangeSession

# 設定済みのエイリアス取得
(Invoke-Command -ScriptBlock { Get-Mailbox アカウント名 } -Session $exchangeSession).EmailAddress

```


## MSOnlineモジュールのコピー
C#から上記コマンドを投げても Connect-MsolService が見つからないというエラーが発生する。

[Claus Konrad Blog: PowerShell and C#: Can’t load MSOnline module](http://blog.clauskonrad.net/2013/06/powershell-and-c-cant-load-msonline.html)

*C:\Windows\System32\WindowsPowerShell\v1.0\Modules* に入っているMSOnlineを
*C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules* にコピーする必要があるらしい。

この後、PowerShellで以下のコマンドを実行。

```PowerShell
Import-Module MSOnline
```

この辺りはもう少しちゃんと調査したい。


## 参照の追加
プロジェクトに *System.Management.Automation* への参照を追加。


## 実行
あとはさっきのコマンドをPowerShellに投げれば良い。


```c#
/// <summary>
/// エイリアスを追加する
/// </summary>
/// <param name="alias"></param>
private void CreateAliasCommand(string aliasName)
{
    StringBuilder ss = new StringBuilder();
    ss.AppendLine("$password = ConvertTo-SecureString \"" + AccountPassword + "\" -AsPlainText –Force");
    ss.AppendLine("$credential = New-Object  System.Management.Automation.PsCredential(\"" + AccountName + "\", $password)");
    ss.AppendLine("$UserCredential = Get-Credential -cred $credential");
    ss.AppendLine("Connect-MsolService -Credential $UserCredential");
    ss.AppendLine("$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri \"https://outlook.office365.com/powershell-liveid/\" -Credential $UserCredential -Authentication \"Basic\" -AllowRedirection");
    ss.AppendLine("Invoke-Command -ScriptBlock { Set-Mailbox " + AccountName + " -EmailAddresses @{Add=\"" + aliasName + "\"} } -Session $exchangeSession");
    ss.AppendLine("(Invoke-Command -ScriptBlock { Get-Mailbox " + AccountName + " } -Session $exchangeSession).EmailAddresses");

    var results = ExecuteCommand(ss.ToString());
    var emails = ExtractEmails(results);

    //作成に失敗した場合は例外
    if (!emails.Contains(aliasName))
    {
        throw new Exception("メールエイリアスの作成に失敗");
    }
}


/// <summary>
/// PowerShellコマンドの実行
/// </summary>
/// <param name="commands"></param>
/// <returns>出力結果</returns>
private List<string> ExecuteCommand(string commands)
{
    var result = new List<string>();
    InitialSessionState iss = InitialSessionState.CreateDefault();
    iss.ImportPSModule(new string[] { "MSOnline" });

    using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
    {
        Collection<PSObject> results = null;
        try
        {
            runspace.Open();
            using (Pipeline pipeline = runspace.CreatePipeline())
            {
                pipeline.Commands.AddScript(commands);

                results = pipeline.Invoke();

                var regex = new Regex("^SMTP:(.+)$", RegexOptions.IgnoreCase);
                foreach (var item in results)
                {
                    result.Add(item.ToString());
                }
            }
        }
        finally
        {
            runspace.Close();
        }
    }
    return result;
}
```


## IISでの実行
~~IIS8.0 + ASP.NET5で実行すると **New-PSSession** でnullが返ってきた。試しに実行ユーザを管理者に変更してみると実行できることを確認した。
この環境での実行ユーザや権限等はまだ把握できていないので追加調査が必要。~~

~~

当初は実行ユーザにRemote Management Usersグループに所属させれば良いと勘違いしていたが違った。
デフォルトで実行されるAPPOOLのユーザに権限付与したかったが、どうにもうまくいかないので実行ユーザをLocalServiceに変更することで対応した。