適用する更新プログラムが無くなるまで Windows Update を実施するのが面倒だったので自動化しました。
Windows Update PowerShell Module の導入
Windows Update PowerShell Module を下記 URL からダウンロードしました。
https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc
任意のディレクトリに解凍します。
今回は C:\InstallWindowsUpdate\Module に解凍しました。
構成
C:\InstallWindowsUpdate
┣Functions
┃┣Enable-AutoLogon.ps1
┃┣Install-WindowsUpdate.ps1
┃┣Register-InstallWindowsUpdateTask.ps1
┃┣Remove-InstallWindowsUpdateTask.ps1
┃┗Test-InstallWindowsUpdateTask.ps1
┣Module
┃┗PSWindowsUpdate
┗Script
┣Config.ps1
┣Index.ps1
┗Install-WindowsUpdate.ps1
スクリプト
概要
- 適用する必要がある更新プログラムが無くなるまでただただ更新プログラムを適用し続けます。
- 再起動後にスクリプトを再実行する必要があります。
- 再起動するようにレジストリを設定します。
- タスクスケジューラーにスクリプトを登録します。
- 適用する必要がある更新プログラムが無くなったらタスクを消します。
実行
管理者権限で PowerShell を起動して下記コマンドを実行するだけです。
$ Set-Location C:\InstallWindowsUpdate
$ .\Install-WindowsUpdate.ps1
中身
. ("{0}/Index.ps1" -f (Split-Path $MyInvocation.MyCommand.Path -Parent))
Install-WindowsUpdate
# スクリプトのルートパス
Set-Variable -Name IndexRoot -Value (Split-Path $MyInvocation.MyCommand.Path -Parent) -Option Constant
# 設定ファイル
. ("{0}\Config.ps1" -f $IndexRoot)
# 関数
Set-Variable -Name functionsRoot -Value ("{0}\Functions" -f $IndexRoot) -Option Constant
Get-ChildItem -Path $functionsRoot | ForEach-Object { . ("{0}\{1}" -f $functionsRoot, $_)}
# スクリプトのルートパス
set-variable -name ConfRoot -value (Split-Path $MyInvocation.MyCommand.Path -Parent) -option constant
#-- Windows Updateインストール設定 start --#
# PowerShellのモジュールが置かれているパス
Set-Variable -Name PSModulePath -Value "C:\Windows\System32\WindowsPowerShell\v1.0\Modules" -Option Constant
# ダウンロードしたWindowsUpdateのPSモジュール名
Set-Variable -Name PSWindowsUpdateModuleName -Value "PSWindowsUpdate" -Option Constant
# ダウンロードしたWindowsUpdateのPSモジュールがあるパス
Set-Variable -Name PSWindowsUpdateModulePath -Value ("{0}\Module\{1}" -f $ConfRoot, $psWindowsUpdateModuleName) -Option Constant
# タスク名
Set-Variable -Name TaskName -Value "InstallWindowsUpdate" -Option Constant
# PowerShellの実行パス
Set-Variable -Name PowerShellExePath -Value "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -Option Constant
# タスクの引数(スクリプトのパス)
Set-Variable -Name TaskArg -Value ('-Command "{0}\Install-WindowsUpdate.ps1"' -f $ConfRoot) -Option Constant
# タスク実行ユーザー
Set-Variable -Name TaskExecuteUser -Value "executor" -Option Constant
# タスク実行ユーザーパスワード
Set-Variable -Name TaskExecutePass -Value "executorpass" -Option Constant
#-- Windows Updateインストール設定 end --#
#-- 自動ログオン設定 start --#
# ログオンユーザー
Set-Variable -Name LogonUser -Value "logonuser" -Option Constant
# ログオンユーザーパスワード
Set-Variable -Name LogonPass -Value "logonuserpass" -Option Constant
# ログオンユーザーのドメイン
Set-Variable -Name LogonDomain -Value "somedomain" -Option Constant
#-- 自動ログオン設定 end --#
function Enable-AutoLogon(){
<#
.SYNOPSIS
マシン起動時に自動ログオンするように設定します.
.DESCRIPTION
Configでログオンアカウントを指定してください.
#>
$regLogonKey = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Set-ItemProperty -path $regLogonKey -name "AutoAdminLogon" -value 1
Set-ItemProperty -path $regLogonKey -name "DefaultUsername" -value $LogonUser
Set-ItemProperty -path $regLogonKey -name "DefaultPassword" -value $LogonPass
if ($LogonDomain -ne "") {
Set-ItemProperty -path $regLogonKey -name "DefaultDomainName" -value $LogonDomain
}
}
function Install-WindowsUpdate(){
<#
.SYNOPSIS
適用できる更新プログラムが無くなるまでWindows Updateを適用します.
.DESCRIPTION
#>
if(-not (Test-Path ("{0}\{1}" -f $PSModulePath, $PSWindowsUpdateModuleName))){
New-Item ("{0}\{1}" -f $PSModulePath, $PSWindowsUpdateModuleName) -ItemType Directory
robocopy $PSWindowsUpdateModulePath ("{0}\{1}" -f $PSModulePath, $PSWindowsUpdateModuleName) /MIR
}
if(-not (Test-InstallWindowsUpdateTask)){
Register-InstallWindowsUpdateTask
}
# Windows Updateをダウンロード
$microsoftPatch = Get-WUList -MicrosoftUpdate
$windowsPatch = Get-WUList -WindowsUpdate
$windowsServerPatch = Get-WUList
if ($windowsServerPatch -or $microsoftPatch -or $windowsPatch) {
Enable-AutoLogon
# Windows Updateをインストール
if($microsoftPatch){
Get-WUInstall -AcceptAll -IgnoreReboot -MicrosoftUpdate
}
if($windowsPatch){
Get-WUInstall -AcceptAll -IgnoreReboot -WindowsUpdate
}
if($windowsServerPatch){
Get-WUInstall -AcceptAll -IgnoreReboot
}
shutdown -r -t 0 -f
} else {
Remove-InstallWindowsUpdateTask
}
}
function Register-InstallWindowsUpdateTask(){
<#
.SYNOPSIS
Windows Updateを適用するタスクをタスクスケジューラーに登録します.
.DESCRIPTION
タスクはマシン起動時に実行されるように設定されます.
タスクでは再度Instal-WindowsUpdateを実行します.
#>
if((Get-WmiObject Win32_OperatingSystem).version -eq "6.1.7601"){
# Windows7ではRegister-ScheduledTaskが使えない
schtasks.exe /Create /tn $TaskName /tr ("{0} {1}" -f $PowerShellExePath, $TaskArg) /sc onstart /ru $TaskExecuteUser /rp $TaskExecutePass
}else{
$trigger = New-ScheduledTaskTrigger -AtStartUp
$action = New-ScheduledTaskAction -Execute $PowerShellExePath -Argument $TaskArg
Register-ScheduledTask -TaskName $TaskName -Trigger $trigger -Action $action -User $TaskExecuteUser -Password $TaskExecutePass
}
}
function Remove-InstallWindowsUpdateTask(){
<#
.SYNOPSIS
Windows Updateを適用するタスクをタスクスケジューラーから削除します.
.DESCRIPTION
適用できる更新プログラムが無くなったらこの関数でタスクを削除するようにしてください.
#>
if((Get-WmiObject Win32_OperatingSystem).version -eq "6.1.7601"){
# Windows7ではnregister-ScheduledTaskが使えない
schtasks /delete /tn $TaskName
}else{
Get-ScheduledTask | Where-Object { $_.TaskName -match $TaskName } | Unregister-ScheduledTask -Confirm:$false
}
}
function Test-InstallWindowsUpdateTask(){
<#
.SYNOPSIS
Windows Updateを適用するタスクが登録されているか確認します.
.DESCRIPTION
確認するタスクはInstall-WindowsUpdateによって登録されます.
#>
$task = $null
if((Get-WmiObject Win32_OperatingSystem).version -eq "6.1.7601"){
# Windows7ではGet-ScheduledTaskが使えない
$task = schtasks /query /fo csv | ConvertFrom-Csv | Where-Object {$_."タスク名" -eq $TaskName}
}else{
$task = Get-ScheduledTask | Where-Object { $_.TaskName -match $TaskName }
}
if($task){
return $true
}else{
return $false
}
}