PowerShellから全社員に予定を投入したい

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

Facebookでリスクエストを貰ったので、PowerShellから全社員のメールボックスに創立記念日の予定を入れるPowerShellを作ってみたいと思います。

Exchangeでは、各種管理用のPowerShellコマンドレットが用意されておりますが、各ユーザーのメールボックスのアイテムを直接操作するコマンドは基本的には有りません。

ただし、EWS(Exchange Web Services)というAPIが用意されておりますので、そちらを利用する事によりメールボックスにアプローチできます。また、その際にアプリケーション偽装(ApplicationImpersonation)権限を利用する事により、「そのユーザーに成り代わって」そのアイテムを利用できます。

今回は、目的が明確ですので一番近いサンプルスクリプトとして以下のstack overflowに回答例として提示されているスクリプトを元に、作成用のコマンドを作ってみます。

How to import meetings into office365 (EWS and Powershell?)

変更している所は赤字で記載します。

function Create-Appointment
{
    [CmdletBinding()]
    param(
        [Parameter(Position=0, Mandatory=$true)] [string]$MailboxName,
        [Parameter(Position=1, Mandatory=$true)] [string]$Subject,
        [Parameter(Position=2, Mandatory=$true)] [DateTime]$Start,
        [Parameter(Position=3, Mandatory=$true)] [DateTime]$End,
        [Parameter(Position=4, Mandatory=$true)] [AllowEmptyString()] [string]$Location,
        [Parameter(Position=5, Mandatory=$true)] [AllowEmptyString()] [string]$Body,
        [Parameter(Position=6, Mandatory=$true)] [Boolean]$IsAllDayEvent,
        [Parameter(Position=7, Mandatory=$true)] [PSCredential]$Credentials
    )
    Begin
    {
        $EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue -Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).'Install Directory') + "Microsoft.Exchange.WebServices.dll")
        if (Test-Path $EWSDLL)
        {
            Import-Module $EWSDLL
        }
        else
        {
            "$(get-date -format yyyyMMddHHmmss):"
            "This script requires the EWS Managed API 1.2 or later."
            "Please download and install the current version of the EWS Managed API from"
            "http://go.microsoft.com/fwlink/?LinkId=255472"
            ""
            "Exiting Script."
            exit
        }

        $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
        $creds = New-Object System.Net.NetworkCredential($Credentials.UserName.ToString(),$Credentials.GetNetworkCredential().password.ToString())
        $service.Credentials = $creds
        $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
        $Compiler=$Provider.CreateCompiler()
        $Params=New-Object System.CodeDom.Compiler.CompilerParameters
        $Params.GenerateExecutable=$False
        $Params.GenerateInMemory=$True
        $Params.IncludeDebugInformation=$False
        $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
        $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
        $TAAssembly=$TAResults.CompiledAssembly
        $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
        [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
        $service.AutodiscoverUrl($MailboxName,{$true})
        #"Using CAS Server : " + $Service.url
        $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxName)
        $folderid= new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar,$MailboxName)
        $Calendar = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)
        $Appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
        $Appointment.Start = $Start
        $Appointment.End = $End
        $Appointment.Subject = $Subject
        $Appointment.Location = $Location
        $Appointment.Body = $Body
        $Appointment.IsAllDayEvent = $IsAllDayEvent
        $Appointment.Save($Calendar.Id,[Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone)
    }
}
こちらを実行するためには、まず実行するアカウント(ここでは、仮にews_userとします)にApplicationImpersonation権限を付与します。ExchangeにPower Shellで接続し、以下のコマンドレットを実行します。
New-ManagementRoleAssignment –Name:EWSCalendarApplication -Role:ApplicationImpersonation –User:ews_user

続いて、PowerShellを実行するコンピュータにEWS Managed APIをインストールします。

PowerShellを開き、上記コードを実行し、Create-AppointmentのFunctionを登録します。

最後に、以下のコマンドを実行します。最初の行では実行アカウントのID/PASSを入力します。

$LiveCred = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $LiveCred -Authentication Basic -AllowRedirection
Import-PSSession $Session -AllowClobber

$results = Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited | select WindowsEmailAddress

foreach ($result in $results){
    Create-Appointment -MailboxName $result.WindowsEmailAddress -Subject "創立記念日" -Start "2017/07/01" -End "2017/07/01" -Body $null -Location $null -IsAllDayEvent $true -Credential $LiveCred
}

これで、来年の7/1に終日イベントとして[創立記念日]が全ユーザーMBXに作成されます。

 

他にも、これを応用すれば会議室の利用状況を集計したり、役員の今日の予定の印刷用の元データを抜いたりできます。

また、このコマンドを行うには対象となるメールボックスが先に作成されている必要があります。メールボックスはNew-Mailboxコマンドなどで作成した時点では実体は作成されていません。ユーザー自身のログイン以外にも、以下の様な動作を行う事により作成されますので、エラーが出て登録出来ないメールボックスには試してみると良いでしょう。

  1. メールの受信(例えば、メールの開通通知などの名目でテストメールを送る)
  2. 受信トレイルールの作成(管理者がNew-InboxRuleコマンドレットで作成できます。ダミーのルールを作成し、すぐに消せば影響は無いと思います)

Office 365で儲けられるエンジニアとは

この投稿は Office 365 Advent Calendar 2016 に参加しています。

先日開催された第17回Office 365勉強会セッション中においても少しお話をさせて頂いたのですが、Microsoftのパートナーの立場から言うと、既にOffice 365は機能やサービス内容の説明だけでは新規ユーザーがゲットできなくなってきました。(逆に言うと、それだけ導入が進んだ)

普段このblogでは技術的なことばかりを書かせて頂いておりますが、今回は少し趣向を変えて、どうやっていけば、これからもOffice 365でご飯を食べられるエンジニアでいられるのかを書いてみたいと思います。

一言でいうと、

Office 365を通じてお客様のワークスタイルを変え、生産性を向上させ続けられるエンジニア

かなと自分では思っています。ちょっと漠然としていますが、広い意味での「導入支援」ですね。ただ、単に技術的な要件に留まらず、これまでの経緯や周辺領域の動きと合わせて今後Microsoftがどういう方向にこの機能(サービス)を持って行こうとしているのか、どう使ったら生産性が上がると思って設計しているかなどを含め、自分の言葉で語れる人物。

例えば、思いつくままに書いてみますが、お客様への導入の中で出てくる以下の様なことが常に鮮度の高い情報を持って答えられる人かなと思っています。

  • SharePoint/Groups/Exchange/Teams/Yammer/Skype for Businessなど、いっぱい有るけどどうやって使い分ければ良いの?
  • サービスを導入したらインターネット接続環境はどういった物を用意すれば良いの?(帯域、セッション数、冗長性など)
  • サービスに接続するクライアントは何を使えば良いの?シーンによって使い分けるとしたらどういう使い分け?
  • アクセス制御はするべき?するならどこまですれば良い?
  • うちの現在定めているセキュリティポリシーとの整合性はどう取っていけば良い?
  • 監査はどういったことを何処までやれば良いの?事前に利用する社員と合意しておくべき項目はある?
  • BYODを認める場合、その条件や取り交わすべき誓約書など、社内規程の整備はどう進めれば良い?
  • 365日24時間仕事ができるようになってしまうが、業務時間外のメール等の確認に対して労使でどう合意すれば良い?
  • 他の同業他社はどこまでOffice365を使いこなしてどう業務に活かしているの?
  • セキュリティにはどこまでお金をかけてどのレベルまで取り組めば良いの?
  • 社内で自立的に対応していけるようにする運用体制はどう作っていったら良い?

書いていてなんですが、自分も全然できていないので、もう少しアンテナ高くして頑張って精進していきたいです。

第17回Office 365勉強会に登壇します

今週の土曜日に品川の日本Microsoftで開催される第17回Office 365勉強会に登壇させて頂きます。

今回は、既に導入がかなり進んでいるということもあって、なかなか改めて話題に上がることも少ないExchange Onlineにスポットを当ててみようということで、Exchange Online特集になっております。

私のセッションでは、
「意外と知らない最近のExchange Online」
ということで、ここ数年で追加された、もしくは追加予定のExchange Onlineの新機能や仕様変更についてお話ししたいと思います。

お時間のある方は是非ご参加頂けると幸いです。

Microsoft MVPを再受賞しました

おかげさまで、MicrosoftのMVPアワードをOffice Servers and Servicesの分野で受賞しました。
2012年にOffice 365で初受賞して以来、5年連続での受賞となります。

これも偏にblogやコミュニティ運営などでご協力を頂いている皆さまの応援のおかげと感謝しております。

これからもよろしくお願い致します。

MVP_Logo_Horizontal_Secondary_Blue286_RGB_300ppi

Exchange 2013/2016の更新失敗時の対応

Exchange Server 2013 / 2016の累積更新プログラム(CU)を初めとする更新プログラムの適用においては、インストール開始時にExchange関連のサービスが停止されるのみならず、自動起動の状態が「無効」として設定されます。
20160719_01

これにより、インストール中に故障が発生してOS再起動した場合などにおいても、更新が中途半端になされた状態でExchange Serverが立ち上がって全体の動作に悪影響を及ぼすなどの事が無いように設計されております。

反面、これも万能ではなく、意図せずサービスが無効化された状態のままインストーラーが終了(しかも再開ができない)してしまうケースが比較的に多く存在します。再現性は無いのですが、以下私が遭遇したケースです。

  • インストーラーが異常終了してしまった
  • 途中でハードウェア障害でOSが再起動した
  • 厳密な名前の検証を無効化せずに中間更新プログラム(IU)を適用した
  • SCCM経由で他の更新プログラムと一緒にExchangeの更新プログラムをインストールした

正常に動作しているサーバーのサービスの状態と見比べながら戻すのが一番単純な方法ですが、特に時間に追われているメンテナンス作業などの場合は途方に暮れることになってしまいます。

こうしたケースにおいて覚えておいた方が良いコマンドがあるので紹介します。

① PowerShellを管理者モードで開く
② インストールディレクトリのBin(C:\Program Files\Microsoft\Exchange Server\V15\Bin)に移動
③ .\ServiceControl.ps1 AfterPatch

更新プログラム適用の処理において、実際にはどういった処理がされているかは C:\ExchangeSetupLogs\ExchangeSetup.log にも詳細が記録されておりますので、そちらを参考にしても良いかと思います。

Exchange2013のマルウェア対策をProxy経由で更新

インターネットへの直接接続が無い環境でのExchange 2013組み込みのマルウェア対策のパターンファイル更新についてメモ。

Exchange Server 2010の頃のFPE(Forefront Protection for Exchange)はGUIで設定できる項目があったのですが、Exchange Server 2013では標準に組み込まれて、Exchange管理シェル(EMS)からも設定することができません。

winhttpで設定することもできるのですが、意外とBypass-listを書くのが面倒だったりするので、FPEの頃のようにパターンファイル更新のみ特定のProxyサーバ経由で実行するように設定できます。

  1. http://forefrontdl.microsoft.com/server/scanengineupdate に対して、認証なしで接続できるようにProxyサーバを設定
  2. PowerShellを管理者として開いて以下のコマンドを実行する
Add-PSSnapin Microsoft.Forefront.Filtering.Management.PowerShell
Set-ProxySettings -Enabled $true -Server [ProxyサーバのIP] -Port [Proxyサーバのポート]

しばらく待てば更新が開始されます。即時で実行したい場合は、以下のコマンドで。

cd 'c:\Program Files\Microsoft\Exchange Server\v15\scripts\'
.\Update-MalwareFilteringServer.ps1 -Identity [対象のExchangeサーバのFQDN]

ExpressRoute for Office365の期待とギャップ

先日、Microsoftより以下のようなメッセージが示されました。

Azure ExpressRoute is not required or recommended for Office 365 except where mandated to use direct networking for regulatory purposes or where a network assessment for Skype for Business connectivity requires it

また、先日のde:codeのイベントのExpressRoute for Office 365関連の講演においても、しきりに「ExpressRouteはセキュリティ向上のためのソリューションではありません」というメッセージを出しており、少し自分的に違和感を覚えておりました。

今回はExpressRoute for Office 365と聴いてイメージする物と、実際のサービス導入後の構成のギャップについて少し整理したいと思います。

まず、標準のOffice 365の構成が下図の左側だとします。ExpressRouteでOffice 365に直接接続出来るようになると聴くと、何となく以下の問題が解決されるように思えます。(右側のイメージ)

  1. インターネット上に機密情報を置くことへの不安
  2. インターネットアクセスが急増することによる回線、NW機器やProxyサーバーなどのパフォーマンスの不安
  3. インターネットアクセスのログのモニタリングやOffice365側のURL/IPアドレスの増減に対応する運用負荷に関する不安

20160601_01

確かにExpressRoute for Office 365を入れると、いくつかの問題点は解消されるのですが、実際にはいくつかの点でギャップが発生します。

簡単に纏めると以下の図上の3点になると思います。

20160601_02まず、ExpressRoute for Office 365を利用しても、主にCDNから配信されてくるデータはインターネット経由でしか取得できないため、①ExpressRouteの他にもインターネット接続を必要とする という点がございます。これにより、インターネット接続経由でOffice 365の一部の通信は継続するため、その運用管理負荷は無くなりません。

また、ExpressRoute経由で接続するのはテナントではなくIPアドレス単位になる為、②他社テナントにもExpressRouteを経由して接続できてしまいます。構成によっては、自社の管理下にあるFirewallやProxyなどをバイパスして外部のクラウドに接続できてしまうことになります。

更に、ExpressRouteを契約しても接続元IPの制限ができるようになる訳では無いので、③ExpressRouteを経由しないインターネットからもこれまで通り利用できてしまいます。

 

勿論、②はSharePoint OnlineであればテナントごとにURL空間が異なるので、そこを意識して.pacファイルで制御するなどすれば、ある程度は制御できると思いますし、③はAD FSを入れれてクラウドIDの利用を制限すれば社外からの認証を抑制することもできます。

ただ、こう言ったFit & Gapを整理していくと、Azureとは違ってOffice 365にExpressRoute接続すべき(したい)シーンというのは、かなり限定されるのではと個人的に感じます。

【登壇情報】6/25 Cloud Samurai 2016

6/25(土)に日本Microsoft品川本社で行われるInteract x Cloud Samurai 2016 Summerに登壇させて頂く事になりました。

タイトルは【オンプレミス x Exchange Server 2016 という選択肢】ということで、Exchange Onlineではなくサーバ製品であるExchange Server 2016について話をさせて頂きたいと思います。

Microsoft_Exchange_2016[1]

Exchange Serverってそれなりにまだ出ているみたいだけど、普段なかなか勉強会で話を聴く機会がないよね…って話がありまして、誰も喋らないのであればじゃあ私が、ということで枠を頂きました。

内容としてはまだこれから考えていくのですが、なるべく具体的に、実際に役に立つ内容となるようにしたいと思ってます。今考えてる(というか、自分が聴きたい内容なのですが)トピックは、以下の感じです。全部喋れるかわかりませんが…。こういった事が聴きたいとかのリクエストもあれば是非御連絡下さい。

  • Exchange Onlineとはどういった違いがあるの?
  • 実際作るとどういったH/W構成になるの?
  • 構築や運用で気をつけるべき所とかあるの?
  • 価格はどれくらい?
  • 2010とか2013とどう違うの?

お時間が許すようであればご参加頂ければ幸いです。

 

6/1に第15回Office365勉強会を開催します

既に満席になってしまっておりますが、6/1(水)の夜に株式会社ラック様の会議室をお借りしてOffice 365勉強会を開催します。

第15回 Office 365 勉強会 ~日本企業にとって必要なOffice 365のセキュリティ~

今回は動画配信は無しで、日本有数のセキュリティベンダであるラック様がパブリッククラウドであるOffice 365を利用するに至った経緯や苦労した点など、プレスリリースでは語れなかった深い部分まで聴かせて頂ければと思っております。

開催が迫ってまいりましたが、まだキャンセル待ちの方も多くいらっしゃいますので、参加ができなくなった方は忘れずキャンセルを入れて頂ければ幸いです。

以下の記事の対談をされていらっしゃるお二人に登壇をお願いしておりますので、事前に見られておくとスムーズに話が入ってくるかと思います。

【参考Web記事】
パブリック クラウドは危険? セキュリティのプロ、ラックの CTO に聞いてみた
【2分バージョン】セキュリティのプロはなぜパブリッククラウド Office 365 を選んだのか

ARRからのアクセスでSchannel 36871

Forefront TMGがサポート切れとなり、Microsoftが提供しているIISモジュールであるARR(Application Request Routing)を利用してExchange ServerのOWAやActiveSyncなどをインターネットに公開されている方も多いかと思います。

ある特定の環境下でARRを利用していると、ある時からARR上にSchannel 36871(内部エラー:10013)が記録され続け、そのままアクセスできない状態が続くことがあります。
20160501_02

10013のエラーコード自体は、サーバ側から返された利用可能な暗号化スイートの一覧にクライアント側で対応した物が無いという物なのですが、Schannelの設定はARRのクライアント側もExchangeのCASのサーバ側も同じに設定していますし、そもそも通常時は利用できているのでそういったことは無いのではと推測しました。

色々と検証したところ、以下のような事が分かって来ました。

  • 発生する環境は、SSL3.0を無効化した環境
  • 発生するタイミングは接続先のCASが起動してきたタイミング
  • ヘルスチェックを有効化している環境もしくは、アクセスが多いタイミングで発生する可能性が高い
  • 一度発生すると出続ける

以上のことから、Exchange Server側でIISが立ち上がりきる前にARRからアクセスし、TCPセッションの確立自体は成功したものの、その後のSSL通信の確立に失敗した為に発生。かつARRは都度セッションを張るのでは無く、一度張ったセッションを再利用し続ける仕様の為に発生している可能性が高いと思われます。

こちらを解消するためには、ARR側のOSを再起動しても勿論直りますが、一番簡単なのはARRのアプリケーションプールをリサイクルすることにより、完全に立ち上がったCASに対してセッションを張り直して貰うことです。

あとは、これを自動的に事象発生時に実行して貰うように、以下の様なスクリプトを作成してタスクスケジューラでイベントログをトリガーにして起動すれば自動的に復旧してくれます。
20160501_03

Import-Module WebAdministration
$SysDate = Get-Date -Format "yyyy/MM/dd HH:mm:ss"
$HostName = hostname

"$SysDate $HostName ARR Recovery Script Start" | Out-File C:\scripts\recovery_arr\recovery_arr.log -encoding default -append
$site = "Default Web Site"
$pool = (Get-Item "IIS:\Sites\$site"| Select-Object applicationPool).applicationPool
Restart-WebAppPool $pool
sleep 300

$SysDate=Get-Date -Format "yyyy/MM/dd HH:mm:ss"
"$SysDate $HostName ARR Recovery Script End" | Out-File C:\scripts\recovery_arr\recovery_arr.log -encoding default -append

このイベントログは発生すると大量に出続けるので、同時起動を無しに設定し、スクリプト中で5分間のwaitを入れていますが、この値は環境により調整して下さい。WebアプリケーションプールはDefault Web Siteのみの想定です。別の発生要因により直らなかった場合はアラートを出すなどの処理を加えても良いかもしれません。