PowerShellでWindowsUpdateを自動化する方法まとめ

PowerShell

適用する更新プログラムが無くなるまで 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
    }
}

参考

タイトルとURLをコピーしました