Windows PowerShell(ISE)を使用して2台以上のPCで更新プログラムの適用状況を手動で揃える

#はじめに
エーティーエルシステムズ 森村です。

今回は、Windows PowerShell(ISE)を使用して複数台のマシンで更新プログラムのインストール可否を同じ状態に揃える手順を紹介します！

経緯として、私の担当する案件の中で「複数台の仮想マシンの更新プログラムの適用状況を同じ状態にする」と言う作業がありました。
その際に、ググってもいまいちヒットしなかったため自前でコードを書きましたので、どうせなら記事にしようと思い投稿に至りました。

**※免責事項(必ず、ご一読ください)**
本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
また、誤情報が入り込んだり、情報が古くなったりすることもありますので、必ずしも正確性を保証するものではありませんのでご了承ください。

#1. 基準となるPCからインストールされている更新プログラム一覧を取得する
任意のPC(以降、基準PCとする)からインストールされている更新プログラム一覧をCSV形式で取得します。

```
#インストールされている更新プログラムを一覧化
function Get-InstalledKB
{
    $session = New-Object -ComObject Microsoft.Update.Session
    $searcher = $session.CreateUpdateSearcher()
    $results = $searcher.QueryHistory(0, $searcher.GetTotalHistoryCount())
    $results|
        where Title -ne $null|
        select @(
            @{L="HotFixId";E={$_.Title -replace '^.*(KB\d+).*$','$1'}},
            "Date",
            "Title",
            "Description"
        )
}

#インストールされている更新プログラムをCSVファイルにする
Get-InstalledKB | Export-Csv -Encoding Default -Path InstalledKB.csv -NoTypeInformation
```
<br>
実行結果です。このCSVファイルを基に、基準PC以外のPC(以降、対象PCとする)に更新プログラムをインストールします。
※データはダミーのものに差し替えてあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/e16cf541-6a6c-dadb-fcbc-3adc7f93a52a.png)

#2. 対象PCからインストールされていない更新プログラム一覧を取得する
対象PCから、対象PCにインストールされていない更新プログラム一覧をCSV形式で取得します。

```
#インストールされていない更新プログラムを一覧化
function Get-NotInstalledKB
{
     $results =  (New-Object -c Microsoft.Update.Session).CreateUpdateSearcher().Search("IsInstalled=0").Updates
     $results|
            where Title -ne $null|
            select @(
                @{L="HotFixId";E={$_.Title -replace '^.*(KB\d+).*$','$1'}},
                "LastDeploymentChangeTime",
                "Title",
                "Description"
            )
}

#インストールされていない更新プログラムをCSVファイルにする
Get-NotInstalledKB | Export-Csv -Encoding Default -Path NotInstalledKB.csv -NoTypeInformation
```
<br>
実行結果はこんな感じ。ここまでで作成した2つのCSVファイルを比較してHotFixIdが一致した更新プログラムを対象PCにインストールすることになります。
※データはダミーのものに差し替えてあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/09e4ba24-d8f3-37a5-6a18-a045f0fbebc0.png)

#3. 作成したCSVファイルを比較してインストールすべき更新プログラム一覧を取得する
1,2で作成したCSVファイルを比較して、基準PCにインストールされていて対象PCにインストールされていない更新プログラム一覧をCSV形式で取得します。

```
#インストールすべき更新プログラムを一覧化
$properties = "HotFixId"
$NotInstalledKB = Import-Csv NotInstalledKB.csv | sort -Unique -Property $properties
$InstalledKB = Import-Csv InstalledKB.csv | sort -Unique -Property $properties
$resultKB = Compare-Object $NotInstalledKB $InstalledKB -Property $properties -IncludeEqual | where SideIndicator -eq "=="

#インストールされていない更新プログラムをCSVファイルにする
$resultKB | Export-Csv -Encoding Default -Path Result.csv -NoTypeInformation
```
<br>
実行結果はこのようになります。ここで出力された更新プログラムをインストールします。
※データはダミーのものに差し替えてあります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1753781/6d2f2bc0-2f6c-902c-4208-0776ad03e6d2.png)

#4. インストールすべき更新プログラムをインストールする
3で作成したCSVファイルを参照して、対象PCに更新プログラムをインストールします。
これで基準PCと同様の更新プログラムインストール状況になります。

```
$ErrorActionPreference = "Stop"

#更新プログラムを検索
$updateSession = New-Object -com Microsoft.Update.Session
$searcher = $updateSession.CreateUpdateSearcher()
$searchResult = $searcher.search("IsInstalled=0")
$updatesCandidateToInstall = New-Object -com Microsoft.Update.UpdateColl
$searchResult.Updates | % { [void]$updatesCandidateToInstall.add($_) }

#更新プログラムをダウンロード
$updatesToDownload = New-Object -com Microsoft.Update.UpdateColl
$searchResult.Updates | ? { $_.IsDownloaded -eq 0 } | % { [void]$updatesToDownload.add($_) }
$downloader = $updateSession.CreateUpdateDownloader()
$downloader.Updates = $updatesToDownload
if($updatesToDownload.Count -ne 0) {
    $downloader.Download()
}

#インストールすべき更新プログラムを抽出
$resultKB = Import-Csv Result.csv | sort -Unique -Property HotFixId
$updateToInstall = New-Object -com Microsoft.Update.UpdateColl
foreach($x in $updatesCandidateToInstall){
    if(($resultKB | Where-Object {$x.Title -like "*"+$_.HotFixId+"*"} | Measure-Object).Count -ne 0) {
        $updateToInstall.add($x)
    }
}

#更新プログラムをインストール
$installer = $updateSession.CreateUpdateInstaller()
$installer.Updates = $updatesToInstall
$installationResult = $installer.Install()
```

これで対象PCに更新プログラムをインストールは完了です。

#最後に
　最後まで読んでいただき、ありがとうございました！
　余談ですが、弊社は**facebook**もしております！
[![f_logo_RGB-Blue_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/81cb9432-5fc7-7dfd-0155-15a602114fa2.png)](https://www.facebook.com/atlsystems)