Windows Server標準のメール通知の機能不足は「Send-MailMessage」コマンドレットで解決!その知識、ホントに正しい? Windowsにまつわる都市伝説(137)

Windows Server標準の管理ツールの中には、メール通知機能を備えたものがあります。しかし、SMTPサーバの指定がTCPポート25への匿名認証にしか対応していない場合、高いセキュリティが要求される現代のメール環境では使いのものにならないでしょう。

» 2019年06月11日 05時00分 公開
[山市良テクニカルライター]
「Windowsにまつわる都市伝説」のインデックス

Windowsにまつわる都市伝説

メール通知機能が前提とする“牧歌的な”メール環境

 Windows Server標準の管理ツールの中には、簡単なメール通知機能を備えているものがあります。例えば、「ファイルサーバーリソースマネージャー」はその一つであり、「クォータ制限」や「ファイルスクリーン制限」に対する管理者やユーザーへのメール通知、記憶域レポートのメール通知が可能です。

 しかし、ファイルサーバーリソースマネージャーのメール通知機能の設定オプションは、SMTPサーバと送信元アドレスの指定しかなく、TCPポート25と匿名認証を前提としています。電子メールに高いセキュリティが要求される現代では、そのような匿名接続を受け付けるようなSMTPサーバは、自前で社内に構築しない限りあり得ません。「System Center Operations Manager」のような統合管理ツールもまた、当然のようにメール通知機能を備えていますが、現代のセキュアなSMTPサーバに対応できるほどのオプションは備えていません(画面1)。

画面1 画面1 Windows ServerのファイルサーバーリソースマネージャーやOperations Managerの「電子メールチャネル」では、現代のメールサーバに対応するのが難しい

現代のメール環境にも対応できる「Send-MailMessage」コマンドレット

 Windows Serverのメール通知は、Windows PowerShell(2.0以降)およびマルチプラットフォーム対応の「PowerShell 6」で利用可能な「Send-MailMessage」コマンドレットで代替できることを知っていると便利です。SMTPポート、SMTP認証、SSL(TLS/StartTLS)の指定が可能なため、現代のセキュアなメール環境に柔軟に対応できるからです。

 例えば、社内にメールサーバがなくても、「Outlook.com」の個人のメールアカウントや「Office 365」の組織メールアカウントの資格情報でコマンドラインから任意の宛先に対してメールを送信できます。これらのサービスを利用する場合、SMTPサーバの指定は共通であり、以下のドキュメントで説明されているように、SMTPサーバ「smtp.office365.com」、SMTPポート「587」、TLS/StartTLS「有効」として、メールボックスの資格情報を指定することで、メール送信が可能になります。

 Windows 8/Windows Server 2012のときに廃止されましたが、かつては「タスクスケジューラ」の「電子メールの送信」操作を使用することで、トリガー発生時にメール通知を行うことができました。ただし、「電子メールの送信」操作がサポートされていたときも、指定できるのはSMTPサーバだけで、TCPポート25、匿名認証が前提でした。

 タスクスケジューラにおける「電子メールの送信」と「メッセージの表示」操作の廃止については、本連載第9回で取り上げ、Send-MailMessageコマンドレットを含む代替案を幾つか提示しました。今回は、この過去の記事のフォローアップでもあります。

 実は、第9回で紹介したSend-MailMessageコマンドレットのコマンドラインでは、日本語が文字化けするというエンコード指定の漏れがありました。

 Send-MailMessageコマンドレットに「-Encoding」オプションのエンコード指定がない場合、日本語環境における既定のエンコードは「日本語(シフトJIS)」(([System.Text.Encoding]::default).EncodingName)が使用され、日本語の文字化けが発生します。

 例えば、Windows PowerShellを開いて、第9回で示したオプション指定と同様の次のようなコマンドラインを実行すると、Outlook.comまたはOffice 365のSMTPサーバを使用してメールを送信できますが、日本語のタイトルや本文、送信元アドレスの日本語表示名は文字化けしてしまいます。

$mailuser = 'メールアカウントのID'
$mailpass = convertto-securestring 'メールアカウントのパスワード' -asplaintext -force
$mailcred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $mailuser, $mailpass
$mailfrom = '送信元メールアドレス'
$mailto = '宛先メールアドレス'
$mailsubject = '件名'
$mailbody = 'メール本文'
Send-MailMessage -from $mailfrom -to $mailto -subject $mailsubject -body $mailbody -smtpServer 'smtp.office365.com' -Port 587 -Credential $mailcred -UseSSL

 日本語の文字化けを回避するには、最後のSend-MailMessageコマンドレットに「-Encoding ([System.Text.Encoding]::UTF8)」を追加してください(画面2)。なお、「-Encoding」オプションは、日本語メールで古くから使用されているエンコード方式であるJIS(ISO-2022-JP)には対応していません。

Send-MailMessage -from $mailfrom -to $mailto -subject $mailsubject -body $mailbody -Encoding ([System.Text.Encoding]::UTF8) -smtpServer 'smtp.office365.com' -Port 587 -Credential $mailcred -UseSSL
画面2 画面2 Send-MailMessageコマンドレットの文字化け問題は、「-Encoding」オプションに「UTF8」を指定することで回避できる(注:スクリプト例の$mailfromは使用せず、$mailuserを送信元として流用している)

 このサンプルを、コマンドプロンプトから実行可能なコマンドライン1行で記述するなら、以下のようになります。すごく複雑に見えますが、PowerShellのコマンドラインの行をセミコロン(;)で1行につなぎ、「powershell.exe -Command "& {スクリプトブロック}"」のスクリプトブロックのところに入れただけです。

powershell.exe -Command "& {$mailuser = 'メールアカウントのID'; $mailpass = convertto-securestring 'メールアカウントのパスワード' -asplaintext -force; $mailcred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $mailuser, $mailpass; $mailfrom = '送信元メールアドレス'; $mailto = '宛先メールアドレス'; $mailsubject = '件名'; $mailbody = 'メール本文'; Send-MailMessage -from $mailfrom -to $mailto -subject $mailsubject -body $mailbody -Encoding ([System.Text.Encoding]::UTF8) -smtpServer 'smtp.office365.com' -Port 587 -Credential $mailcred -UseSSL}"

 Outlook.comやOffice 365など、外部のメールを使用する場合、アカウントで2段階認証や多要素認証がセットアップされていると、コマンドラインからのメール送信は認証に失敗します。これを回避するには、アプリパスワードを作成し、メールアカウントのパスワードにアプリパスワードを指定します(画面3)。

画面3 画面3 2段階認証や多要素認証がセットアップされている場合は、送信時のSMTP認証に失敗するので、アプリパスワードを作成してこれを認証に使用する

コマンド実行機能でメール通知機能を代替

 タスクスケジューラで廃止された「電子メールの送信」操作は、本連載第9回で説明したように、「プログラムの開始」操作のプログラム/スクリプトに「powershell.exe」を指定し、引数に「-Command "& {スクリプトブロック}"」を指定することで代替できます(画面4)。

画面4 画面4 「プログラムの開始」操作に「powershell.exe」を指定し、引数に「-Command "& {スクリプトブロック}"」を指定する

  SMTPサーバの設定が柔軟に行えない管理ツールの場合は、コマンドの自動実行機能を備えていれば、それを利用できます。最初の例として挙げたファイルサーバーリソースマネージャーの場合は、クォータやファイルスクリーンのプロパティの「コマンド」タブで構成します。

 ただし、実行するコマンドは「powershell.exe」ではなく、「C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe」のように“フルパスで指定”する必要があります(画面5画面6)。Operations Managerの場合は「コマンド通知チャネル」を作成して、フルパスを指定することで同様に構成できます。

画面5 画面5 ファイルサーバーリソースマネージャーの場合は、クォータやファイルスクリーンのプロパティの「コマンド」タブで「powershell.exe」をフルパスで指定し、引数に「-Command "& {スクリプトブロック}"」を指定する
画面6 画面6 画面6 イベントの発生をトリガーとしたメール通知と、ファイルサーバーリソースマネージャーからのメール通知

 プログラムや引数の文字数に制限がある場合は、「powershell.exe -Command "& {スクリプトブロック}"」の1行を記述したバッチファイル(.cmd)を作成し、安全な場所(SYSTEMやAdministratorsのみがアクセスできるディレクトリ)に保存して、パッチファイルをプログラムに直接指定するか、プログラム「C:\Windows\System32\cmd.exe」、引数「-C "パッチファイルのパス"」を指定すればよいでしょう。

標準のメール通知機能と外部メールサーバを連携させる方法

 コマンドの自動実行機能を利用した方法は、宛先や本文が固定で、特定の宛先にメール通知するには十分でしょう。動的な構成が可能な場合もありますが、複雑になってしまいます。標準のメール通知機能が利用できれば、簡単に実装できることが多くあります。

 例えば、ファイルサーバーリソースマネージャーで対象ユーザーに対するメール通知や、記憶域レポートの通知(これはコマンド実行ではできません)、通知メッセージの動的なカスタマイズなどは、標準のメール通知機能の方が圧倒的に簡単です。

 SMTPサーバの指定オプションが不足しているメール通知機能であっても、Windows Serverの「SMTPサーバー」を社内のメール転送専用にTCPポート25、匿名認証やWindows統合認証でセットアップして外部メールサーバに中継させるという方法があります。

 具体的な方法は、筆者の個人ブログにまとめてあります。以下の記事では「中継の制限」を使用して、ローカル(127.0.0.1)からの接続のみを受け付けるようにしていますが、社内のサブネットアドレスに変更することで別のホストからの中継にも対応できます。

 ただし、このようなメール転送サーバは、社内のクライアントがマルウェアに感染すると踏み台にされる可能性があるため、認証方法や中継の範囲を可能な限り狭めておくことが重要です。

最新情報(2019年6月13日追記)

 クロスプラットフォームの「PowerShell Core 6.2」から、Send-MailMessageコマンドレットは非推奨になりました。PowerShell Coreの将来のリリースでは削除される可能性があります。現在のWindowsに搭載されているWindows PowerShellに関しては、Send-MailMessageコマンドレットの廃止の予定は発表されていません。


筆者紹介

山市 良(やまいち りょう)

岩手県花巻市在住。Microsoft MVP:Cloud and Datacenter Management(2018/7/1)。SIer、IT出版社、中堅企業のシステム管理者を経て、フリーのテクニカルライターに。Microsoft製品、テクノロジーを中心に、IT雑誌、Webサイトへの記事の寄稿、ドキュメント作成、事例取材などを手掛ける。個人ブログは『山市良のえぬなんとかわーるど』。近著は『ITプロフェッショナル向けWindowsトラブル解決 コマンド&テクニック集』(日経BP社)。


Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。