PowerShellを使ってWSUSの状態を特定のメール宛てに送信する方法

こんにちは、みなさん!今回の記事では、PowerShellスクリプトを使用してWSUSサーバーに登録されたコンピューターの更新状況をモニタリングし、HTMLメールでレポートする方法について解説します。

WSUSサーバーを管理している場合、コンピューターの更新状況を効果的に把握し、問題が発生していないかどうかを確認することは重要です。しかし、大量のコンピューターを一度に管理するのは容易ではありません。そこで、このPowerShellスクリプトが役立ちます。

この記事は、PowerShellに興味があり、WSUSサーバーの更新管理に関わっているシステム管理者やITプロフェッショナルを対象としています。基本的なPowerShellの知識があると理解がより深まりますが、初心者にも分かりやすく解説します。

このスクリプトを使用することで、手動で複数のコンピューターの更新状況を確認する手間を省き、迅速かつ効果的に問題を特定できます。また、HTMLメールにより情報を視覚的に整理し、迅速な対応が可能です。

まず、WSUSサーバーの更新状況を確認するためのPowerShellスクリプトの各部分を詳しく解説します。次に、HTMLメールの構築方法やスクリプトの各ステップに関する注意事項など、詳細な情報を提供します。

PowerShellスクリプト

以下スクリプトの変数$UpdateServer、$Port、$smtp、$to1、$to2、$to3、$fromをご自身の環境にあわせてご利用ください。解説は下記に記載しております。

Param (
[string]$UpdateServer = 'serever-name', # WSUSサーバ名
[int]$Port = 8530, # WSUSにアクセスするためのTCPポート
[bool]$Secure = $False
)
$smtp = "relay.xxxxxx.jp" # SMTPサーバ
$to1 = "test1@example.com" # 受信者のSMTPアドレス1
$to2 = "test2@example.com" # 受信者のSMTPアドレス2
$to3 = "test3@example.com" # 受信者のSMTPアドレス3
$from = $UpdateServer + "<send@example.com>" # WSUSサーバを識別する送信者のアドレス

$MsgBody = "<HTML>"
$MsgBody = $MsgBody + "<HEAD>"
$MsgBody = $MsgBody + "<title>" + $UpdateServer + " コンピュータの更新状況</title>"
$MsgBody = $MsgBody + "</HEAD>"
$MsgBody = $MsgBody + "<BODY style=""font-family:'Courier New', Courier, monospace"">"

$MsgBody= $MsgBody + "<h1>" + $UpdateServer + " コンピュータの更新状況</h1>"
$intLineCounter = 0 # コンピュータのカウンター

Remove-Item -force PcStatusReport.txt # 前回の実行結果を追跡するための小さなログファイル。読み取りリストを開始する前に削除する必要がある。

If (-Not (Import-Module UpdateServices -PassThru)) {
Add-Type -Path "$Env:ProgramFiles\Update Services\Api\Microsoft.UpdateServices.Administration.dll" -PassThru
}

$Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($UpdateServer,$Secure,$Port) # WSUSサーバに接続

$CTScope = New-Object Microsoft.UpdateServices.Administration.ComputerTargetScope # WSUSサーバーに登録されたすべてのコンピュータ

# HTMLテーブルのヘッダー書き込み
$MsgBody = $MsgBody + "<table border=""1"" cellspacing=""2"" cellpadding=""2"" style=""font-family:'Courier New', Courier, monospace"">"
$MsgBody = $MsgBody + "<tr>"
$MsgBody = $MsgBody + "<th>No.</th>"
$MsgBody = $MsgBody + "<th>ステータス</th>"
$MsgBody = $MsgBody + "<th>ホスト名</th>"
$MsgBody = $MsgBody + "<th>IPアドレス</th>"
$MsgBody = $MsgBody + "<th>最終ステータス更新日</th>"
$MsgBody = $MsgBody + "<th>総更新数</th>"
$MsgBody = $MsgBody + "<th bgcolor=""LightSalmon"">再起動待ち</th>"
$MsgBody = $MsgBody + "<th bgcolor=""Cyan"">インストール準備完了</th>"
$MsgBody = $MsgBody + "<th bgcolor=""Yellow"">ダウンロード保留</th>"
$MsgBody = $MsgBody + "<th bgcolor=""IndianRed"">失敗</th>"
$MsgBody = $MsgBody + "<th bgcolor=""Silver"">不明な状態</th>"
$MsgBody = $MsgBody + "</tr>"

# コンピュータのリストを名前順にソートし、それぞれの詳細を取得
$wsus.GetComputerTargets($CTScope) | Sort -Property FullDomainName | ForEach {

$objSummary = $_.GetUpdateInstallationSummary()
$Down = $objSummary.DownloadedCount # すでにダウンロードされた更新の数
$Fail = $objSummary.FailedCount # 失敗した更新の数
$Pend = $objSummary.InstalledPendingRebootCount # 再起動待ちで完了する更新の数
$NotI = $objSummary.NotInstalledCount # インストールされていない更新の数
$Unkn = $objSummary.UnknownCount # 最初の検索で検出待ちの更新の数です。
$Total = $Down + $Fail + $Pend + $NotI + $Unkn # コンピュータの総更新数

$intLineCounter = $intLineCounter + 1 # テーブル行カウンターを増やす
$IntStr = [Convert]::ToString($intLineCounter) # HTMLコードに入れるために文字列に変換

if ($Total -eq 0) {$Estado="OK"; $bgcolor="LightGreen"} # すべての更新が正常にインストールされました。
elseif ($Pend -ne 0) {$Estado="再起動が必要"; $bgcolor="LightSalmon"} # 再起動が必要な更新があります。
elseif ($Down -ne 0) {$Estado="インストール準備完了"; $bgcolor="Cyan"} # ダウンロード済みの更新があります。
elseif ($NotI -ne 0) {$Estado="保留中"; $bgcolor="Yellow"} # まだインストールされていない更新があります。
elseif ($Fail -ne 0) {$Estado="ERROR"; $bgcolor="IndianRed"} # 失敗した更新があります。
elseif ($Unkn -ne 0) {$Estado="まだ報告されていません"; $bgcolor="Silver"} # まだ報告されていない更新があります。
else {$Estado=""; $bgcolor="White"} # それ以外の場合

Write-Verbose ($IntStr + " : " + $_.FullDomainName) -Verbose # 画面上でタスクの進捗状況を表示します。

$LastContact = $_.LastReportedStatusTime # コンピュータがWSUSに報告した最終時刻
$days = [Math]::Ceiling((New-TimeSpan -Start $LastContact).TotalDays) # 最終報告からの日数

if ($days -gt 14) {$Color="Red"} # コンピュータが長期間接続されていない場合は赤く表示
elseif ($days -gt 7) {$Color="Orange"} # コンピュータに問題がある可能性がある場合はオレンジで表示
elseif ($days -gt 2) {$Color="Yellow"} # コンピュータがオフになっている可能性がある場合は黄色で表示
else {$Color="White"} # コンピュータは正常

# 日数を読みやすい形式に再フォーマットします。
if ($days -eq 0) {$Dias="今日"}
elseif ($days -eq 1) {$Dias="昨日"}
else {$Dias = "$days" + "日前"}

if ($LastContact -eq [DateTime]::MinValue) {$Dias="未報告"; $Color="Silver"}

# すべての情報を含むテーブル行を書き込み
$MsgBody = $MsgBody + " <tr>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle""> " + $IntStr +" </td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"" bgcolor=""" + $bgcolor + """> " + $Estado + " </td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle""> " + $_.FullDomainName.replace(".tkgnet.local","")+ " </td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle""> " + $_.IPAddress + " </td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"" bgcolor=""" + $Color + """> " + $Dias +"</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $Total + "</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $Pend + "</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $Down + "</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $NotI + "</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $Fail + "</td>"
$MsgBody = $MsgBody + "<td align=""center"" valign=""middle"">" + $Unkn + "</td>"
$MsgBody = $MsgBody + "</tr>"

$_.FullDomainName >> PcStatusReport.txt # ログファイルに新しい行を追加
}

$MsgBody = $MsgBody + "</table><br>" # HTMLテーブルを終了します。

if ($intLineCounter -eq 0) {
Write-Verbose ("WSUSデータベースを読み取るためには、管理者としてスクリプトを実行する必要があります。") -Verbose # 管理者特権で実行されていない場合は警告を表示します。
$MsgBody = $MsgBody + " WSUSデータベースを読み取るためには、管理者としてスクリプトを実行する必要があります。 <hr>"
} else {
$MsgBody = $MsgBody + "<hr>"
}

# レポートの読者に対する注釈
$MsgBody = $MsgBody + "<p><h2>注記:</h2>更新は、検索、ダウンロード、インストールの3段階のプロセスで順次適用されます。<br> 各コンピュータはこれらの3つの段階を経て更新される必要があります。<ul>"
$MsgBody = $MsgBody + "<li>最初の検索が実行される前は、コンピュータが更新が必要かどうかは不明です。そのため、この場合、すべての更新が<strong>不明な状態</strong>で表示されます。</li>"
$MsgBody = $MsgBody + "<li>検索が完了すると、更新は<strong>ダウンロード保留</strong>として表示されます。これは、そのコンピュータが特定の更新を必要としていることを示します。</li>"
$MsgBody = $MsgBody + "<li>コンピュータがダウンロード保留の更新をダウンロードした場合、これらは<strong>インストール準備完了</strong>として数えられます。</li>"
$MsgBody = $MsgBody + "<li>インストールの最後の段階で次の結果を得ることができます:</li><ul>"
$MsgBody = $MsgBody + "<li><strong>OK</strong>:すべての必要な更新が正常にインストールされました。</li>"
$MsgBody = $MsgBody + "<li><strong>ERROR</strong>:1つ以上の必要な更新が正常にインストールされませんでした。</li>"
$MsgBody = $MsgBody + "<li><strong>再起動が必要</strong>:インストールの最初の部分が終了しましたが、2つ目の部分を完了するためにコンピュータを再起動する必要があります。</li>"
$MsgBody = $MsgBody + "</ul></ul></p>"
$MsgBody = $MsgBody + "コンピュータがサーバーに接続されていない場合、14日以上は<font style=""background-color:red"">赤</font>で強調表示されます。<br>"
$MsgBody = $MsgBody + "コンピュータがサーバーに接続されていない場合、7日から14日は<font style=""background-color:orange"">オレンジ</font>で強調表示されます。<br>"
$MsgBody = $MsgBody + "コンピュータがサーバーに接続されていない場合、2日から6日は<font style=""background-color:yellow"">黄色</font>で強調表示されます。<br>"
$MsgBody = $MsgBody + "<hr>"

$MsgBody = $MsgBody + "<center><strong>" + [System.DateTime]::Now + "</strong></center>" # メッセージの末尾にタイムスタンプを追加

$IntStr = [Convert]::ToString($intLineCounter) # 行カウンターを文字列に変換
$subject = $IntStr + " 台のコンピュータが " + $UpdateServer + " サーバーに登録されています" # メッセージの件名

# Body と HTML のタグを閉じる
$MsgBody = $MsgBody + "</BODY>"
$MsgBody = $MsgBody + "</HTML>"

# メール送信
send-MailMessage -SmtpServer $smtp -To $to1, $to2, $to3 -From $from -Subject $subject -Body $MsgBody -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)

解説

パラメータの定義

Param (
[string]$UpdateServer = 'serever-name', # WSUSサーバ名
[int]$Port = 8530, # WSUSにアクセスするためのTCPポート
[bool]$Secure = $False
)

Paramを使用し、引数を定義します。
$UpdateServerではWSUSサーバのホスト名を定義します。[string]で変数を文字列型にしています。
$PortではWSUSにアクセスするためのTCPポートを定義します。[int]で変数を整数型にしています。
$SecureではHTTP形式でWSUSにアクセスする場合は$False、HTTPS形式は$Trueと定義します。[bool]で変数をブール型にしています。

SMTP設定

$smtp = "relay.xxxxxx.jp" # SMTPサーバ
$to1 = "test1@example.com" # 受信者のSMTPアドレス1
$to2 = "test2@example.com" # 受信者のSMTPアドレス2
$to3 = "test3@example.com" # 受信者のSMTPアドレス3
$from = $UpdateServer + "<send@example.com>" # WSUSサーバを識別する送信者のアドレス

$smtpでは受信先のSMTPサーバを指定します。
$to1/$to2/$to3では受信者のメールアドレスを指定します。
$fromではWSUSサーバを識別する送信者のアドレスを指定します。

HTMLメール本文の構築

$MsgBody = "<HTML>"
# ... 中略 ...
$MsgBody = $MsgBody + "</HTML>"

メールの本文はHTML形式で構築されています。コンピューターごとの更新状況を表形式で示すためにHTMLテーブルが使用されています。

更新ステータスのロジック

# コンピュータの更新ステータスに応じて異なる背景色を指定
if ($Total -eq 0) {$Estado="OK"; $bgcolor="LightGreen"} # すべての更新が正常にインストールされました。
elseif ($Pend -ne 0) {$Estado="再起動が必要"; $bgcolor="LightSalmon"} # 再起動が必要な更新があります。
elseif ($Down -ne 0) {$Estado="インストール準備完了"; $bgcolor="Cyan"} # ダウンロード済みの更新があります。

コンピューターごとの更新ステータスに基づいて、HTMLテーブルセルの背景色が異なります。例えば、再起動が必要な場合はLightSalmonの背景色が指定され、インストール準備が完了した場合はCyanの背景色が指定されます。

レポート生成とログ

$_.FullDomainName >> PcStatusReport.txt # ログファイルに新しい行を追加

WSUSから情報を取得し、それに基づいてHTMLレポートを生成します。また、各コンピューターの更新ステータスをPcStatusReport.txtというログファイルに追記しています。

メール送信

send-MailMessage -SmtpServer $smtp -To $to1, $to2, $to3 -From $from -Subject $subject -Body $MsgBody -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)

生成されたレポートが指定された受信者に電子メールで送信されます。

注意事項

Write-Verbose ("WSUSデータベースを読み取るためには、管理者としてスクリプトを実行する必要があります。") -Verbose

スクリプトの実行には管理者特権が必要であり、その旨の注意事項が表示されます。

この記事がお役に立ちましたか?ご質問やフィードバックがあれば、お気軽にコメントしてください!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です