Help us understand the problem. What is going on with this article?

[小ネタ] Windows Update の実行結果(success/fail)をPowerShellでシンプルに取得する

More than 3 years have passed since last update.

Windows Serverの月例パッチ当て問題

  • ご担当者の皆様、いつも本当におつかれさまです。
  • パッチ当ての自動化をやってる所は多いと思いますが、Windows Updateの実行結果をPowerShellでシンプルに拾って色々捗らせたい (例) 失敗したホストをSlackに通知

そんな時に役立ちそうな方法を見つけたのでメモ。

"win32_reliabilityRecords" vs "Windows Update Agent COM object"

普通に調べると、win32_reliabilityRecordsを使ってWindowsUpdateの結果(success/fail)を取得する参考がたくさん出てきます。

  • win32_reliabilityRecordsを使って失敗したWindowsUpdate一覧を取得するPowerShellの例
Get-WmiObject -Class win32_reliabilityRecords -filter "sourcename = 'Microsoft-Windows-WindowsUpdateClient'" `
| where {$_.message -match 'failure'} `
| select @{LABEL = "date"; EXPRESSION = {$_.ConvertToDateTime($_.timegenerated)}},@{LABEL = "failed updates"; EXPRESSION = {$_.productname}} `
| Format-Table -AutoSize –Wrap

ただこの方法には少々問題がありまして、対象のホストで"reliability WMI provider"が有効になっていないといけません。
全ホストにそんなことやってられない…

そこで、COM objectを使ってWindowsUpdateの結果を取得します。
この方法であれば古いWindows Server2008とかでも特に何か下準備をすることなく使えると思います。

CheckWindowsUpdateResult.ps1
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$HistoryCount = $Searcher.GetTotalHistoryCount()
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa386532%28v=vs.85%29.aspx
$Searcher.QueryHistory(0,$HistoryCount) | ForEach-Object -Process {
    $Title = $null
    if($_.Title -match "\(KB\d{6,7}\)"){
        # Split returns an array of strings
        $Title = ($_.Title -split '.*\((KB\d{6,7})\)')[1]
    }else{
        $Title = $_.Title
    }
    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa387095%28v=vs.85%29.aspx
    $Result = $null
    Switch ($_.ResultCode)
    {
        0 { $Result = 'NotStarted' }
        1 { $Result = 'InProgress' }
        2 { $Result = 'Succeeded' }
        3 { $Result = 'SucceededWithErrors' }
        4 { $Result = 'Failed' }
        5 { $Result = 'Aborted' }
        default { $Result = $_ }
    }
    New-Object -TypeName PSObject -Property @{
        InstalledOn = Get-Date -Date $_.Date;
        Title = $Title;
        Name = $_.Title;
        Status = $Result
    }

} | Sort-Object -Descending:$true -Property InstalledOn |
Select-Object -Property * -ExcludeProperty Name | Format-Table -AutoSize -Wrap

尚、このままだと遡って過去の物も一気に取得してしまうので、
必要に応じて当月分だけを抜き出してあげるようにすれば便利になると思います。

これをベースにすれば簡単に失敗を検知できますね。

出典

jrsyo
Engineer
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away