【WSUS運用自動化】置き換えられた更新プログラムを自動で拒否するスクリプトを試してみた

## 1. 試したこと
[WSUS メンテナンス ガイド](https://blogs.technet.microsoft.com/jpwsus/2018/03/08/maintenance-guide/) の [3.不要な更新プログラムは拒否済みに設定しよう！](https://blogs.technet.microsoft.com/jpwsus/2017/12/11/decline-is-yrfrnd/)を参考に、**「置き換えられた更新プログラムを拒否する」スクリプト**を試してみました。

公式には紹介されていない気づきがありましたので、作業ログとして残します。

## 2. 検証環境
- [Microsoft謹製「置き換えられた更新プログラムを拒否する」スクリプト (Decline-SupersededUpdates.ps1)](https://msdnshared.blob.core.windows.net/media/TNBlogsFS/prod.evol.blogs.technet.com/telligent.evolution.components.attachments/01/6906/00/00/03/64/80/93/Decline-SupersededUpdates.txt)
- Windows Server 2019 Standard version 1809
- Powershell version 5.1.17763.592
- WSUS version 10.0.17763.678

## 3. 検証手順
### 3.1 スクリプトの解析
スクリプトにおける引数の定義は以下の通りです。

>
```powershell
[CmdletBinding()]
Param(
	[Parameter(Mandatory=$True,Position=1)]
    [string] $UpdateServer,	
	[Parameter(Mandatory=$False)]
    [switch] $UseSSL,	
	[Parameter(Mandatory=$True, Position=2)]
    $Port,
    [switch] $SkipDecline,
    [switch] $DeclineLastLevelOnly
)
```

表にまとめると、こんな感じです。

| 引数名       |       型 |    必須    |    説明|
|:-----------------|------------------:|:------------------:|:------------------:|
| UpdateServer|      　　string|      〇|引数の値として、WSUSサーバのIPアドレスまたはFQDNを指定|
| Port|            　　-|       〇|引数の値として、WSUSが使用するポートを指定|
| UseSSL|            　　switch|       ×|WSUSがSSL通信を使用する場合に使用|
| SkipDecline|       　　switch|       ×|テスト実行または置き換えられた更新プログラムの数を確認する場合に使用|
| DeclineLastLevelOnly| switch|     　×　|最終レベルの置き換えられた更新プログラムのみ拒否する場合に使用 (**※1**)|

**※1：**
最終レベルの置き換えられた更新プログラムとは、最初に置き換えられた更新プログラムを指します。
例えば、更新プログラム1版が更新プログラム2版に置き換えられ、更新プログラム2版が更新プログラム3版に置き換えられている場合、最終レベルの置き換えられた更新プログラムは1版のものになります。
スクリプト内では、最終レベルの置き換えられた更新プログラムを「Superseded Updates (Last Level)」、最終レベルを除く置き換えられた更新プログラムを「Superseded Updates (Intermediate)」と表現しています。

次に、スクリプトにおけるアウトプットの定義は以下の通りです。

>
```powershell
$outPath = Split-Path $script:MyInvocation.MyCommand.Path
$outSupersededList = Join-Path $outPath "SupersededUpdates.csv"
$outSupersededListBackup = Join-Path $outPath "SupersededUpdatesBackup.csv"
"UpdateID, RevisionNumber, Title, KBArticle, SecurityBulletin, LastLevel" | Out-File $outSupersededList
```

実行すると、WSUS上の置き換えられた更新プログラムのリスト (SupersededUpdates.csv) をスクリプトと同じパスに作成します。
実際に「拒否」が実行された場合は、リストをコピーして、バックアップ (SupersededUpdatesBackup.csv)を作成します。


### 3.2 スクリプトのテスト実行

まずは、SkipDecline 引数を使用してテスト実行してみます。
標準出力に出される置き換えられた更新プログラムのサマリ情報もファイル (Decline-SupersededUpdates.log)に保存します。

```powershell
powershell -ExecutionPolicy Unrestricted -Command "C:\Tools\WSUS\Decline-SupersededUpdates.ps1 -UpdateServer localhost -Port 8530 -SkipDecline" >> C:\Tools\WSUS\Decline-SupersededUpdates.log
```

出力結果は以下の通りです。

- WSUS上の全ての更新プログラムが87個
- 拒否状態以外の更新プログラムが87個（全て未承認状態）
- 置き換えられた更新プログラムが69個
- 最終レベル以外の置き換えられた更新プログラムが58個
- 最終レベルの更新プログラムが11個

```powershell:Decline-SupersededUpdates.log
Connecting to WSUS server localhost on Port 8530... Connected.
Getting a list of all updates... Done
Parsing the list of updates... Done.
List of superseded updates: C:\Tools\WSUS\SupersededUpdates.csv

Summary:
========
All Updates = 87
Any except Declined = 87
All Superseded Updates = 69
    Superseded Updates (Intermediate) = 58
    Superseded Updates (Last Level) = 11

SkipDecline flag is set to True. Skipped declining updates

Done
```

```powershell:SupersededUpdates.csv(参考)
UpdateID, RevisionNumber, Title, KBArticle, SecurityBulletin, LastLevel
0fa3afd0-ef18-4967-8fb9-c1f03c537e7f, 200, 2019-04 Security Update for Adobe Flash Player for Windows 10 Version 1903 for x86-based Systems (KB4493478), 4493478, , False
4efec717-3b81-4c2f-a988-a345196b691b, 200, 2019-04 Security Update for Adobe Flash Player for Windows 10 Version 1903 for ARM64-based Systems (KB4493478), 4493478, , False

....(略)....

d1d399c6-3a78-436e-a3f2-7962fee86ad1, 200, 2019-05 Servicing Stack Update for Windows 10 Version 1903 for ARM64-based Systems (KB4498523), 4498523, , True
41a6b6d6-6976-49b5-a4c4-0121dc96189c, 200, 2019-05 Servicing Stack Update for Windows 10 Version 1903 for x86-based Systems (KB4498523), 4498523, , True
```

### 3.3 スクリプトの本番実行
いよいよ、SkipDecline 引数を外して本番実行してみます。
標準出力に出される置き換えられた更新プログラムのサマリ情報もファイル (Decline-SupersededUpdates.log)に保存ます。

```powershell
powershell -ExecutionPolicy Unrestricted -Command "C:\Tools\WSUS\Decline-SupersededUpdates.ps1 -UpdateServer localhost -Port 8530" >> C:\Tools\WSUS\Decline-SupersededUpdates.log
```

実行結果は以下の通りです。

**<実行前の「拒否済み」更新プログラム (0件/87件)>**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218139/88e41fdf-22d8-3589-b8eb-e1a870b1fa9f.png)
　　　　:arrow_down:　:arrow_down:　:arrow_down:　:arrow_down:　:arrow_down:　:arrow_down:　:arrow_down:

**<実行後の「拒否済み」更新プログラム (69件/87件)>**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218139/e092dbcb-7122-9410-e804-03df80a46c4f.png)


確かに、69個あることを確認していた置き換えられた更新プログラムが全て拒否されていることを確認しました。
Powershellによる実行内容を [WSUS メンテナンス ガイド](https://blogs.technet.microsoft.com/jpwsus/2018/03/08/maintenance-guide/) を参考に、タスクスケジューラへ設定すれば自動化が可能です。

## 4. まとめ

- [WSUS メンテナンス ガイド](https://blogs.technet.microsoft.com/jpwsus/2018/03/08/maintenance-guide/) で紹介されている「置き換えられた更新プログラムを拒否する」スクリプトを試してみました。
- スクリプトの仕様/使用方法を紹介しました。
- スクリプトで置き換えられた更新プログラムを拒否できることを確認しました。

この記事で紹介した内容と、 [WSUS メンテナンス ガイド](https://blogs.technet.microsoft.com/jpwsus/2018/03/08/maintenance-guide/) で紹介されている [2.WSUS のクリーンアップ ウィザードについて](https://blogs.technet.microsoft.com/jpwsus/2017/12/05/43/) の内容を組み合わせることで、拒否された更新プログラムの実態ファイルが削除されるため、クリーンナップ効果を高めることができます。

## 5. 余談
Windows 7 のサポートが2020年1月に終了するため、いよいよ Windows 10 の運用が本格化してくると思います。Windows 10 関連の更新プログラムはサイズが大きいため、今まで以上にWSUSのメンテナンスが重要になってきます。煩わしいWSUS運用の自動化に少しでも寄与できますと幸いです。
今後、紹介したスクリプトを参考にアーキテクチャ(x86/x64/ARM64)単位で、更新プログラムの拒否ができるスクリプトを作成し、紹介したいと思います。
末筆ながら、ここまで読んでいただきまして誠にありがとうございました。