2018/12/13

Windows Scripting: Windows Update をスクリプトから(WindowsUpdateProvider 版)

(12/14 追記:より改善したコード SearchAndInstallUpdate.ps1 を TechNet スクリプト センターに公開しました。一番下の 12/14 の追記を参照↓)

Windows Server 2019 (LTSC) の Server Core および Windows Server, Semi-Annual Channel (SAC、ver 1709 以降)での利用を想定した、Windows Update スクリプト CheckandInstallUpdates.ps1 を作成してみました。Sconfig (サーバー構成ユーティリティ)の「6) 更新プログラムのダウンロードとインストール」は進捗状況がわかりにくかったので。加えて、書籍「IT プロフェッショナル向け Windows トラブル解決コマンド&テクニック集」の訂正も。

8 年以上前に Windows Update をスクリプト(VBScript や PowerShell)から実行するスクリプトを紹介しましたが...

Windows Scripting: Windows Update をスクリプトから ( WindowsUpdate.vbs ) (2010/07/02)
Windows Scripting: Windows Update をスクリプトから ( WindowsUpdate.ps1 ) (2010/07/05)

拙著「IT プロフェッショナル向け Windows トラブル解決コマンド&テクニック集」にもコマンドラインやスクリプトから実行する方法をまとめています。その中で、 第 1 章のコラム「Windows 10バージョン1709以降の WindowsUpdateProvider モジュール」に訂正があります。正しくは Get-WUIsPendingReboot と書くべきところを、存在しない Get-WUPendingUpdate と書いてしまいました。お詫びして訂正します。


P.21
誤: if (Get-WUPendingUpate) {Restart-Computer}
正: if (Get-WUIsPendingReboot) {Restart-Computer -Force}

 <ここから PR>

ITプロフェッショナル向け
Windowsトラブル解決コマンド&テクニック集

価格  2,700円(税込)
ISBN  978-4-8222-5381-3
発行日 2018年10月16日
著者名 山内 和朗(山市 良) 著
発行社 日経BP社
判型等 B5変/264ページ

日経BPブックナビ
https://www.nikkeibp.co.jp/atclpubmkt/book/18/P53810/
オンラインストア
amazon.co.jpRakutenブックス
<ここまで PR>

お詫びのついでに、WindowsUpdateProvider モジュールを使用した更新プログラムの確認&インストール スクリプト CheckandInstallUpdates.ps1 を書いてみました。Windows Server, version 1709 以降の Server Core 環境を想定して書いたものですが、Windows 10 バージョン 1709 以降(つまり RS3 以降)で動くはず。バージョン 1703 以前は WindowsUpdateProvider モジュールが存在しないはずなので、即終了します。

CheckandInstallUpdates.ps1]
Import-Module WindowsUpdateProvider -ErrorAction SilentlyContinue
$checkmodule = (Get-Module WindowsUpdateProvider)
if ($checkmodule -eq $null) {
  Write-Host "This script can be run on Windows 10/Server ver 1709(RS3) or later."
  exit
}

Write-Host "Last Check date: "
 (Get-WULastScanSuccessDate).DateTime
Write-Host "Last Installation date:"
 (Get-WULastInstallationDate).DateTime
Write-Host "Checking for available updates..."

$updates = Start-WUScan
if ($updates.Count -gt 0) {
    Write-Host $updates.Count "updates were found."
    foreach ($update in $updates) {
        Write-Host $update.Title
    }
    [ValidateSet("y","n")] $res = Read-Host "Will you install these updates ? (y/n) "
    if ($res -eq "y") {
        Install-WUUpdates -Updates $updates
        if (Get-WUIsPendingReboot) {
            [ValidateSet("y","n")] $res = Read-Host "A reboot is required to complete the update installation. Do you want to restart now ? (y/n)"
            if ($res -eq "y") {
                 Restart-Computer -Force
            }
        }
    } else {
        Write-Host "Installation canceled."
    }
} else {
    Write-Host "There are no updates available."
}
(初出時 14 時頃のスクリプトはバグがありました。誤:$updates.Title、正:$update.Title、その後、モジュールの確認や最終チェック/インストール日の出力機能を追加しました。12/14 追記:より改善したコードを TechNet スクリプト センターに公開しました。一番下の 12/14 の追記を参照↓)

CheckandInstallUpdates.ps1 (Windows Server 2016 以前では使用できません)はダウンロードとインストールの進捗状況が表示されるという利点があります。また、このスクリプトだと、C パッチや D パッチは検出しないはず。

1/25 追記)
RS5 で 1 月の Preview CU for .NET Framework KB4481031 が検出されてしまうことがわかりました(この KB4481031 は当初自動配布されてましたが、1/24 にオプション化されました。でも検出してしまいます)。次のように変更すれば、検出しないようになります。この変更により、Windows Server の Sconfig 6 > R(推奨される更新プログラム)を選択したのと同じ挙動になります。このように変更すると、"Start-WUScan: Scan hit error: @{PSComputerName=}.ReturnValue" エラーが発生しにくくなるかも。

# Search all applicable updates
# Write-Host "`r`nSearching for all applicable updates..."
# $updates = Start-WUScan
# Search only recommended updates
Write-Host "`r`nSearching for recommended updates..."
$updates = Start-WUScan -SearchCriteria "IsInstalled=0 and Type='Software' and AutoSelectOnWebsites=1"



エラー処理はしていませんので、コマンドレットのエラーはそのまま返ってくると思います。こんな風に。
ほとんどテストしていませんし、WindowsUpdateProvider モジュールのコマンドレットもよくエラーをはくので(エラーの出る環境と出ない環境の差異がわからない、タイムアウト的な何か? それとも、単に出たてのモジュールで成熟していないから?)、その点はご了承ください。12/12 の B パッチ デーにほとんどの環境を更新してしまったので、確認できないのでした。

追記:ちょっとだけ確認。

Windows Server 2016 では動かないので OK。
Windows 10 ver 1809 で更新実行 OK。


インストールに失敗したらもう1回実行すればいい。

ついでに最終チェック日時と最終インストール日時を追加など。

重要:Windows 10、Windows Server ともに、自動更新が有効な環境だと、自動更新が同時に走って先に再起動待ち状態になり、タイミングによってはこちらのスクリプトが終わらない状態になる可能性があります。利用するなら、手動更新設定(Server は Sconfigの メニュー: 5→ 手動更新: M で設定可能)+スクリプトで。つまりは、Windows 10 向きではありません。

WindowsUpdateProvier モジュールと、このモジュールが依存する RS3 以降の新しいCIMクラス MSFT_WUOperations については、こちらで以前に記事にしました。

面倒な“Windows 10の更新”をスクリプト化できる新たな選択肢(その2)@IT
http://www.atmarkit.co.jp/ait/articles/1808/22/news011.html

12/14 追記) 
更新プログラムごとのインストール結果の表示と個別の更新プログラムの選択インストール、および現在の更新状況(OSビルドなど)の表示に対応した改良版 SearchAndInstallUpdates.ps1を TechNet スクリプト センターで公開しました。また、Server Core だと、最終スキャン日時とインストール日時が 1601/1/1 00:00:00 UTC のまま更新されないことがあるようです。

Search and Install updates for Server Core by PowerShell (for RS3 or later)
https://gallery.technet.microsoft.com/scriptcenter/Search-and-Install-updates-083cf7d6

2019/2/14 追記)
Criteria についてはこちら

UpdateSearcher::Search method
https://docs.microsoft.com/ja-jp/windows/desktop/api/wuapi/nf-wuapi-iupdatesearcher-search

でもなんか RS5 だと言うことを聞いてくれないような気がするので、B リリース(第二火曜日の翌日)用のSearchAndInstallUpdates.ps1($updates = Start-WUScan)と C/D リリース用のSearchAndInstallUpdatesR.ps1($updates = Start-WUScan -SearchCriteria "IsInstalled=0 and Type='Software' and AutoSelectOnWebsites=1")の 2 本立てでしばらく運用してみる。

1 件のコメント:

山市 良 さんのコメント...

新スクリプト SearchAndInstallUpdates.ps1 は、"start-WUScan : Scan hit error: @{PSComputerName=}.ReturnValue" エラーには対応できないけど、インストール失敗には対応しました。

Start-WUScan のエラーは、C:\Windows\System32\WindowsPowerShell\v1.0\Modules\WindowsUpdateProvider\MSFT_WUOperations.psm1 内の "$scanres = Invoke-CimMethod -Namespace root/Microsoft/Windows/WindowsUpdate -ClassName MSFT_WUOperations -MethodName ScanForUpdates -Arguments @{SearchCriteria=$SearchCriteria}" が長い時間返ってこない時に発生するみたい。たぶん時間かかりすぎのとき。