none
Date of most recently installed update

    Question

  • Hi All,

    I'm looking for a PowerShell script that help me manage my Windows servers who receive updates from our internal WSUS server.  We are using WSUS 3.0 running on a single Windows 2012 R2 machine.

    In simple terms, I need a PowerShell script that can produce a simple table showing the following:

    1. The date of the most recently installed update for each server
    2. Email these results to a specified email address.

    I am not interested in which update was installed – I am only concerned about when the last update was installed on each server.

    I have seen a very good script posted by Aman Dhally on his IT blog, the script does exactly what I need (minus the emailing part), but it only returns results for the machine where the script is run from, here is the script:

    First enter:

    $windowsUpdateObject = New-Object -ComObject Microsoft.Update.AutoUpdate

    Then enter:

    $windowsUpdateObject.Results

    This produces a very simple table showing the date of the last successful update that was installed.

    (to my frustration I cannot post URL's or images of the result, as my account has yet to be verified!)

    What I would like is for the above to query a list of my Servers and produce the results exactly in the same way as above, one line per server.  So column 1 =computername, column 2=LastSearchSuccessDate, column 3=LastInstallationSuccessDate

    For example, I have a text file: C:\Computers.txt, which contains a list of all my Windows Servers. Would it be feasible to produce a script that could say get-content c:\Computers.txt and for each computer listed, show me the date of the most recent Windows Update that was installed?

    I hope this makes sense, I’d be grateful for any assistance.  I should add that I’m a PowerShell newbie, so there is still a lot to learn for me.

    Many thanks



    • Edited by Koncise Friday, March 21, 2014 11:58 AM 2 typos!
    Friday, March 21, 2014 11:33 AM

Answers

  • In case you do not have PowerShell Remoting enabled in your environment:

    Function Get-UpdateStatus {
        [cmdletbinding()]
        Param (
            [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
            [Alias('Name','__Server','IPAddress')]
            [string[]]$Computername=$env:COMPUTERNAME
        )
        Begin {$ErrorActionPreference='Stop'}
        Process {
            ForEach ($Computer in $Computername) {
                Try {
                    $AutoUpdate = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.AutoUpdate",$computer))
                    [pscustomobject]@{
                        Computername = $Computer
                        LastSearchSuccessDate = $AutoUpdate.results.LastSearchSuccessDate
                        LastInstallationSuccessDate = $AutoUpdate.results.LastInstallationSuccessDate
                    }
                } Catch {
                    Write-Warning "$($Computer): $_"
                }
            }
        }
        End {$ErrorActionPreference='Continue'}
    }

    You can then run it like this:

    Get-Content c:\Computers.txt | Get-UpdateStatus


    Boe Prox
    Blog | Twitter
    PoshWSUS | PoshPAIG | PoshChat | PoshEventUI
    PowerShell Deep Dives Book


    • Edited by Boe ProxMVP Friday, March 21, 2014 1:06 PM pipeline support and error handling
    • Proposed as answer by Rhys W Edwards Friday, March 21, 2014 1:06 PM
    • Marked as answer by AnnaWYModerator Tuesday, April 8, 2014 5:10 AM
    Friday, March 21, 2014 1:02 PM
  • Yes, you could just paste it into powershell, but make sure you're running powershell as admin.  You could also copy the text into a file with a .ps1 extension and in powershell, in the directory where the file is, type

    .\filename.ps1

    In Boe's more efficient and structured example, you would paste it into powershell and type the command he provided.  Or copy both sections of code he provided into a file and proceed as above.

    Besides the structure of the code he provided, you're more likely to be successful with his version if you aren't actively using Powershell in your environment already.  My example relies on Powershell remoting being enabled, which it normally wouldn't be by default.  Enabling that is a bit more complex, but you should look into it if you want to use Powershell to manage your servers.  Here are a few links that should be helpful:

    http://technet.microsoft.com/en-us/magazine/ff700227.aspx
    http://technet.microsoft.com/en-us/library/hh849694.aspx
    http://powershell.org/wp/2012/08/06/ebook-secrets-of-powershell-remoting/

    Good luck!

    Friday, March 21, 2014 1:14 PM

All replies

  • On my way out the door, hopefully this will get you on the right track.  I can't test or verify your property names though...

    $Results = @()
    $Computers = Get-Content c:\computers.txt
    Foreach ($Computer in $Computers {
       $Result = Invoke-Command -ComputerName $Computer -FilePath c:\script.ps1
       $LastSearchSuccessDate = ($Result | sort LastSearchSuccessDate).LastSearchSuccessDate
       $LastInstallationSuccessDate = ($Result | sort LastInstallationSuccessDate).LastInstallationSuccessDate
       $Results += New-Object PSObject -property @{
          Computer=$Computer
          LastSearchSuccessDate=$LastSearchSuccessDate
          LastInstallationSuccessDate=$LastInstallationSuccessDate
       }
    }
    $Results

    Hope this helps!


       

    Friday, March 21, 2014 11:53 AM
  • Hi Rhys, thanks for the quick reply, I am unsure what exactly I should be doing with this script, do I paste it into Windows PowerShell?

    Friday, March 21, 2014 12:43 PM
  • In case you do not have PowerShell Remoting enabled in your environment:

    Function Get-UpdateStatus {
        [cmdletbinding()]
        Param (
            [parameter(ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
            [Alias('Name','__Server','IPAddress')]
            [string[]]$Computername=$env:COMPUTERNAME
        )
        Begin {$ErrorActionPreference='Stop'}
        Process {
            ForEach ($Computer in $Computername) {
                Try {
                    $AutoUpdate = [activator]::CreateInstance([type]::GetTypeFromProgID("Microsoft.Update.AutoUpdate",$computer))
                    [pscustomobject]@{
                        Computername = $Computer
                        LastSearchSuccessDate = $AutoUpdate.results.LastSearchSuccessDate
                        LastInstallationSuccessDate = $AutoUpdate.results.LastInstallationSuccessDate
                    }
                } Catch {
                    Write-Warning "$($Computer): $_"
                }
            }
        }
        End {$ErrorActionPreference='Continue'}
    }

    You can then run it like this:

    Get-Content c:\Computers.txt | Get-UpdateStatus


    Boe Prox
    Blog | Twitter
    PoshWSUS | PoshPAIG | PoshChat | PoshEventUI
    PowerShell Deep Dives Book


    • Edited by Boe ProxMVP Friday, March 21, 2014 1:06 PM pipeline support and error handling
    • Proposed as answer by Rhys W Edwards Friday, March 21, 2014 1:06 PM
    • Marked as answer by AnnaWYModerator Tuesday, April 8, 2014 5:10 AM
    Friday, March 21, 2014 1:02 PM
  • Yes, you could just paste it into powershell, but make sure you're running powershell as admin.  You could also copy the text into a file with a .ps1 extension and in powershell, in the directory where the file is, type

    .\filename.ps1

    In Boe's more efficient and structured example, you would paste it into powershell and type the command he provided.  Or copy both sections of code he provided into a file and proceed as above.

    Besides the structure of the code he provided, you're more likely to be successful with his version if you aren't actively using Powershell in your environment already.  My example relies on Powershell remoting being enabled, which it normally wouldn't be by default.  Enabling that is a bit more complex, but you should look into it if you want to use Powershell to manage your servers.  Here are a few links that should be helpful:

    http://technet.microsoft.com/en-us/magazine/ff700227.aspx
    http://technet.microsoft.com/en-us/library/hh849694.aspx
    http://powershell.org/wp/2012/08/06/ebook-secrets-of-powershell-remoting/

    Good luck!

    Friday, March 21, 2014 1:14 PM
  • Thanks very much for you replies, this works a treat, I have just created a batch file which runs the commands all in one so that's great.

    My other question was to know how to possibly amend this so the results are:

    1. Presented in a simple HTML table, and

    2. Have this emailed to a specified email address

    I will then create a scheduled task to have this batch file run every Monday morning as part of my morning checks to help automate this report for us without us having to logon to a server and run the command manually.

    I would be most grateful for any advice or feedback

    Thanks

    Koncise

    Wednesday, April 9, 2014 1:47 PM
  • Hi,
    1. Presented in a simple HTML table

    Take a look at ConvertTo-HTML:

    http://ss64.com/ps/convertto-html.html

    2. Have this emailed to a specified email address

    You can use Send-MailMessage to send email via PowerShell:

    http://ss64.com/ps/send-mailmessage.html


    Don't retire TechNet! - (Don't give up yet - 12,830+ strong and growing)

    Wednesday, April 9, 2014 1:52 PM
    Moderator
  • This works nicely for most of the hosts in my input hosts file, but for a couple I am getting the following error message:

    WARNING: a_hostname: Exception calling "CreateInstance" with "1" argument(s): "Retrieving the COM class factory for remote component with CLSID {BFE18E9C-6D87-4450-B37C-E02F0B373803} from machine a_hostname failed due to the following error: 800706ba a_hostname."

    The target hosts are running and reachable via RDP.

    - if anyone has an idea how to get around this, or why I might be getting this error, that would be very fine.

    Thanks very much!

    Tuesday, March 3, 2015 12:50 PM
  • Hi adrianzde,

    I am also getting the same error 

    WARNING: computer name: Exception calling "CreateInstance" with "1" argument(s): "Retrieving the COM class factory for remote component with CLSID {B
    FE18E9C-6D87-4450-B37C-E02F0B373803} from machine computer name failed due to the following error: 800706ba computer name."

    Can some one suggest a fix?

    Friday, January 6, 2017 9:49 AM
  • Hi Boe,

    I am getting the below error for few servers.

    WARNING: computer name: Exception calling "CreateInstance" with "1" argument(s): "Retrieving the COM class factory for remote component with CLSID {B
    FE18E9C-6D87-4450-B37C-E02F0B373803} from machine computer name failed due to the following error: 800706ba computer name."

    Can some one suggest a fix?

    Friday, January 6, 2017 10:01 AM
  • same error here!
    Thursday, January 12, 2017 4:28 AM
  • Just want to let you know, that this commands doesn't work on newer systems like Windows 10/Server 2016.

    The command itself works flawless, but the values aren't correct anymore. I guess it's because of the Windows Defender definitions which get treated as a "full" update.

    Proof: https://i.imgur.com/tCj2dQG.png

    Thursday, November 2, 2017 4:37 PM
  • I would love a script like this but when i run it theres no Output no matter how i run it. I get no errors but just get nothing out of it at all. 
    Thursday, May 3, 2018 7:40 AM
  • Hello,

    I want to run the same script but not worked for me , thrown error mentioned below :

    Please help me.

    Get-UpdateStatus : The term 'Get-UpdateStatus' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was
    included, verify that the path is correct and try again.
    At line:1 char:32
    + Get-Content C:\Computers.txt | Get-UpdateStatus
    +                                ~~~~~~~~~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (Get-UpdateStatus:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException


    Amit Kumar

    Friday, May 18, 2018 3:00 PM
  • This process works in my home lab..But trying it in office environment I am facing multiple issues..with no success..one of them is like Get-UpdateStatus is not recognized as the name of the cmdlet...Please help me..I am novice in PS
    Saturday, July 14, 2018 8:03 PM
  • From my perspective there are at least 3 things to learn for you. First: learn the basics of Powershell from scratch. This way you know what an error means and how to debug. Second: read really carefully this thread. Get-UpdateStatus is a function you have to define before you can use it. The post is marked as one answer. ;-) Three: do not "overtake" old and already answered threads here in the forum. Especially when you don't have to contribute something helpful to the original question. If you need create a new own thread and quote this one if helpful or needed.

    Best regards,

    (79,108,97,102|%{[char]$_})-join''

    Saturday, July 14, 2018 8:27 PM