I am trying to find the last time Windows update was run on server and report back a list of all servers which need updating. At the moment I am using Get-Hotfix and returning the date of the most recent hotfix install but this does seem to have some problems With date formats and also lots of updates called “File 1” which have no installedon date. Any ideas?

There are a number of articles on the internet about Get-Hotfix and date problems.

This seems the best script I have found so far; strangely, I cannot get it to sort on date.

Get-HotFix -ComputerName win7 | 
where-object {$_.hotfixid -ne "file 1"} |
Select hotfixid,description,installedby,@{label="InstalledOn";e={[DateTime]::Parse($["installedon"].value,$([System.Globalization.CultureInfo]::GetCultureInfo("en-US")))}}

That is the script I “borrowed” :smiley: To use as the centre of my script. I cannot sort it by date either I thought I was going crazy until I read your answer. I would like to hear if anyone else has managed to sort this.

Get-HotFix -ComputerName win7 | 
where-object {$_.hotfixid -ne "file 1"} |
Select hotfixid,description,installedby,@{label="InstalledOn";e={[DateTime]::Parse($["installedon"].value,$([System.Globalization.CultureInfo]::GetCultureInfo("en-US")))}} |
Sort-Object InstalledOn -Descending

I might be misunderstanding the problem, but are you saying that this doesn’t work for you? It seems to work just fine for me.

This works on 95% of computers, but for some reason there is a group of computers which will not sort. As I am trying to retrieve the most recent update installed this causes problems.


  1. The sorting is semi-random, dates mixed up.
  2. Sorts correctly, but misses out latest 2014 updates.

Then it worked perfectly!
I changed to: GetCultureInfo(“en-Uk)” - naturally this failed
I changed to GetCultureInfo(“en-gb)” - Sorted correctly, but no 2014
Changed back to the original GetCultureInfo(“en-us)” it worked!
Now I cannot get it fail in these sense of going back to the original scrambled dates.

Additional info, I am based in the UK.

I managed to get round this by creating a new array and adding each update to it and then sorting the array. Only seems to be needed on servers before 2008 r2 but at least I can continue now. I would like to know if there was a more prefered method though.

get-hotfix will only report the last update - it won’t report the last time Windows Update ran

Need to dig out where the last time of Windows Update running is stored

Select-String -Path $env:windir\WindowsUpdate.log -Pattern ‘successfully installed’ |
ForEach-Object {
$information = $_ | Select-Object -Property Date, LineNumber, Product
$parts = $.Line -split ‘\t’
[DateTime]$information.Date = $parts[0] + ’ ’ + $parts[1].SubString(0,8)
$information.Product = ($
.Line -split 'following update: ')[-1]


} | Format-Table Date,Product -AutoSize

PS I did not write this but I can’t recall where I got it either so I can’t credit the author.

I had a poke in the registry and this shows the last date of checking for updates and the last date an update was installed

$props = [ordered]@{
LastDetect = Get-ItemProperty -Path ‘HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Detect’ -Name LastSuccessTime |
select -ExpandProperty LastSuccessTime

LastInstall = Get-ItemProperty -Path ‘HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Install’ -Name LastSuccessTime |
select -ExpandProperty LastSuccessTime

New-Object -TypeName psobject -Property $props

Great information guys thanks a lot. The script is working great now.

If you’re using WSUS, you can get the info from there. I wrote an article about it here: Check when servers were last patched with Windows Update via COM or WSUS - Svendsen Tech

It strikes me that the code seems a bit overkill, but… That article also has a script that uses COM (locally via PSremoting or remote COM - the latter being a firewall pain) - also in an asynchronous version. This will probably take some time the first time you run it. The only real benefit that I can think of that the COM script offers over Richard’s registry check (which is a lot simpler and faster - why didn’t I think of that) is the name of the update, though (and you can edit the code to get them all, should you need it). The latter COM script exports to CSV and HTML for you automatically (and exposes global variables to the calling shell).

The asynchronous script looks like this on a test run in my lab environment: