
かつて山市良と呼ばれたおじさんのブログ
セイテクエンジニアのブログ かつて山市良と呼ばれたおじさんのブログ vol.125 ”更新を個別インストールしたい”を叶えるPowerShellスクリプト|Windowsトラブル解決
2025年07月28日配信
2025年07月28日更新
執筆者:山内 和朗
前回(vol.124)は、Microsoftが公開しているWindows Update用のサンプルスクリプト「WUA_SearchDownloadInstall.vbs」の一部の機能をPowerShellスクリプト化しました。その理由は、運用環境向けでない(Microsoftがサポートしないスクリプト)であること、Cscriptエンジンがアプリケーションエラーで異常終了することがあること、そしてVBScriptは非推奨になったことがあるからです。前回は、更新プログラムを個別にインストールする機能の実装を棚上げしましたが、今回はその機能を別スクリプトとして作成しました。
現在のWindowsおよびWindows Serverは、Windows 7やWindows XP(もう知らない人も多いと思いますが)のときのように、更新プログラムを個別に選択してインストールするGUI機能を備えていません。
Windows Serverについては、以前からSconfigユーティリティ(Server Core向けのユーティリティですが、GUI環境でも利用できます)の「6) 更新プログラムのインストール」に、更新プログラムを個別にインストール機能があります(画面1)。しかし、Windows Server 2022以降では日本語環境において、ローカライズの問題で個別インストール機能をまったく利用できないという残念な状況にあります(画面2)。Windows Server 2022において、Sconfigは従来のWSH(Windows Script Host)ベースのものからPowerShellベースのものに変更されました。その際、日本語を表示するUIの部分が各所で表示が乱れ、期待通りに機能しなくなっている部分があるのです。
画面1 Windows ServerのSconfigを使用すると、更新プログラムを個別に選択してインストールできる。Windows Server 2022以降は従来のWSHベースからPowerShellベースに変更された
画面2 Windows Server 2022以降の日本語版では、ローカライズの問題により、個別インストール機能が利用できない状態。すべてをインストールする(A)か中止(Enter)は利用可能
Windows Admin CenterやAzure Update Managerを使用すれば、更新プログラムを選択的にインストールすることは可能です。しかし、そういった管理ツールなしで実現できるPowerShellスクリプトがあれば便利だと考えました。
というわけで、前回の「WUA_SearchDownloadInstall.ps1」をベースに、更新プログラムの個別インストールに対応した「WUA_SearchDownloadInstallS.ps1」を作成しました。
「WUA_SearchDownloadInstallS.ps1」で使用可能なパラメーター/スイッチの一覧を以下に示します。
コマンドラインスイッチ/パラメーター | 説明 |
-Criteria "検索条件" | 検索条件の指定。既定(省略時)は、-Criteria "IsInstalled=0 and Type='Software' and IsHidden=0" |
-RebootToComplete | インストール後に再起動が必要な場合に自動的に再起動する |
コマンドラインパラメーターやスイッチを何も指定せずに実行すると、既定の検索条件を使用してWindows Update(Microsoft Update)を検索し、利用可能な更新プログラムを一覧表示します。インストールしたい更新プログラムの番号を入力すれば、ダウンロード、インストールを実行してくれ、再起動が必要であれば再起動するかどうかを問い合わせてくれます(画面3)。-RebootToCompleteパラメーターを指定すれば、再起動が必要な場合に自動的に再起動を開始します。
画面3 更新プログラムの個別インストールに対応した「WUA_SearchDownloadInstallS.ps1」
[WUA_SearchDownloadInstallS.ps1](プレーンテキストで表示)
param(
[string]$Criteria = "IsInstalled=0 and Type='Software' and IsHidden=0",
[switch]$RebootToComplete
)
function InstallationResultToText($result) {
switch ($result) {
2 { "Succeeded" }
3 { "Succeeded with errors" }
4 { "Failed" }
5 { "Cancelled" }
default { "Unexpected ($result)" }
}
}
#Write-Host "### Command line parameters you specify. ###"
#Write-Host "-Criteria: $Criteria"
#Write-Host "-RebootToComplete: $RebootToComplete"
#Write-Host ""
Write-Host "### Running Windows Update (for indivisual update) ###"
Write-Host "Searching for updates..."
Write-Host ""
$updateSession = new-object -com "Microsoft.Update.Session"
$updateSearcher = $updateSession.CreateupdateSearcher()
$searchResult = $updateSearcher.Search($criteria)
Write-Host "List of applicable items on the machine:"
if ($searchResult.Updates.Count -eq 0) {
Write-Host "There are no applicable updates."
exit 0
} else {
$downloadReq = $False
$i = 0
foreach ($update in $searchResult.Updates){
$i++
if ( $update.IsDownloaded ) {
Write-Host $i">" $update.Title "(downloaded)"
} else {
$downloadReq = $true
Write-Host $i">" $update.Title "(not downloaded)"
}
}
}
Write-Host ""
if ($i -eq 1) {
$response = Read-Host "1 update found. Do you want to install it ?(Y/N)"
} else {
$response = Read-Host "Enter the number of the update you wish to install (Type C to abort)"
}
if ($response -match '^[Yy]$') {
} elseif ($response -match '^[Cc]$') {
Write-Host "Aborted."
exit 0
} elseif ($response -as [int]) {
if ($response -gt $i) {
Write-Host "Aborted."
exit 0
}
}
$targetupdatetitle = $searchResult.Updates.item($response - 1).Title
if ( $downloadReq ) {
Write-Host "Creating collection of updates to download..."
$updatesToDownload = new-object -com "Microsoft.Update.UpdateColl"
foreach ($update in $searchResult.Updates){
if ($update.Title -eq $targetupdatetitle) {
$updatesToDownload.Add($update) | out-null
}
}
Write-Host "Downloading updates..."
$downloader = $updateSession.CreateUpdateDownloader()
$downloader.Updates = $updatesToDownload
$downloader.Download()
Write-Host "List of downloaded updates:"
$i = 0
foreach ($update in $searchResult.Updates){
$i++
if ( $update.IsDownloaded ) {
Write-Host $i">" $update.Title "(downloaded)"
#} else {
# Write-Host $i">" $update.Title "(not downloaded)"
}
}
} else {
Write-Host "All updates are already downloaded."
}
$updatesToInstall = new-object -com "Microsoft.Update.UpdateColl"
Write-Host ""
Write-Host "Creating collection of downloaded updates to install..."
foreach ($update in $searchResult.Updates){
if ( $update.IsDownloaded ) {
$updatesToInstall.Add($update) | out-null
}
}
$returnValue = 1
if ( $updatesToInstall.Count -eq 0 ) {
Write-Host "Not ready for installation."
} else {
Write-Host "Installing" $updatesToInstall.Count "updates..."
$installer = $updateSession.CreateUpdateInstaller()
$installer.Updates = $updatesToInstall
$installationResult = $installer.Install()
if ( $installationResult.ResultCode -eq 2 ) {
Write-Host "One update installed successfully."
} else {
Write-Host "Update could not installed."
}
}
if ( $installationResult.RebootRequired ) {
Write-Host "One update are requiring reboot."
} else {
Write-Host "Finished. Reboot are not required."
}
Write-Host ""
Write-Host "Listing of updates installed and indivisual installation results:"
$i = 0
foreach ($update in $updatesToInstall){
$result = $installationResult.GetUpdateResult($i)
$i++
Write-Host $i">" $update.Title ":" $(InstallationResultToText $result.ResultCode) ", HRESULT:" $($result.HResult)
}
if ($installationResult.RebootRequired) {
if ($RebootToComplete) {
Write-Host "After 60 seconds, the system will initiate a restart automatically. To abort , press Ctrl+C. (-RebootToComplete)"
for ($i = 60; $i -gt 0; $i--) {
Write-Host "." -NoNewLine
Start-Sleep -Seconds 1
}
restart-Computer -Force
} elseif (-not $Automate) {
$response = Read-Host "Reboot is pending. Would you like to reboot? (Y/N)"
if ($response -match '^[Yy]$') {
Write-Host "Reboot now!..."
sleep -Seconds 3
restart-Computer -Force
} else {
Write-Host "You need to reboot this device later."
}
}
}
Exit $returnValue
実は、前回作成した「WUA_SearchDownloadInstall.ps1」には、「WUA_SearchDownloadInstallS.ps1」の呼び出しを事前に仕込んでおきました。「WUA_SearchDownloadInstallS.ps1」を「WUA_SearchDownloadInstall.ps1」と同じパスに配置すれば、対話的な実行時に利用可能な更新プログラムの一覧のプロンプトで「S」を入力すれば、「WUA_SearchDownloadInstallS.ps1」が実行されます(画面4)。
画面4 「WUA_SearchDownloadInstall.ps1」で「S」を入力すると、「WUA_SearchDownloadInstallS.ps1」が実行され、個別インストールを開始できる
[WUA_SearchDownloadInstall.ps1(抜粋)](プレーンテキストで表示)
$ScriptforSigleUpdatePath = ".\WUA_SearchDownloadInstallS.ps1"
...
if (-not $Automate ) {
$response = Read-Host "Next step: download all updates(Y) or donload/install single update(S). May I continue? (Y/N/S)"
if ($response -match '^[Yy]$') {
Write-Host "Proceed to the next step: download all updates."
} elseif ($response -match '^[Ss]$') {
Write-Host "Proceed to the next step: download/install single update."
If (Test-Path $ScriptforSigleUpdatePath) {
. $ScriptforSigleUpdatePath
exit $LASTEXITCODE
} else {
Write-Host "$ScriptforSigleUpdatePath not found."
exit 0
}
・・・
ご参考まで...Microsoft提供のものではありませんが、PowerShellを使用したWindows Updateについては、PowerShell Galleryで公開されているMichalGajda氏作成のPSWindowsUpdateモジュールのコマンドレットを使用する方法もあります。
https://www.powershellgallery.com/packages/PSWindowsUpdate/