I am trying to write a PowerShell script that will query all the servers in Active Directory and see the last date a Windows Update was applied.
I was having some trouble, so just to get it done, I created two scripts, one in Powershell to get the servers and the other in VBScript to query the last date. I found a this Powershell module that allows me to query the last install date, but it is extremely slow, especially on remote servers.
Here is the PS code:
Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' -Properties * |
Select-Object Name | Sort-Object Name |
ForEach-Object {
Get-WUHistory -ComputerName $_.Name | Sort-Object Date,ComputerName -Descending |
Select-Object -First 1
}
Its so slow, its practically unusable.
I have some VBScript which I cobbled together that is much faster. See below:
On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile ("servers.csv", 1)
server = ""
Do Until file.AtEndOfStream
line = file.Readline
server = line
'wscript.echo server
Set objSession = CreateObject("Microsoft.Update.Session", server)
If Err.Number <> 0 Then
'WScript.Echo server & " Error: " & Err.Number & " Error (Hex): " & Hex(Err.Number) & " Source: " & Err.Source & " Description: " & Err.Description
WScript.Echo server & " Communications Error"
Err.Clear
Else
Set objSearcher = objSession.CreateUpdateSearcher
Set colHistory = objSearcher.QueryHistory(1, 1)
For Each objEntry in colHistory
Wscript.Echo server & " " & objEntry.Date
Next
End If
Loop
file.Close
Is there an easy way to get the speed of the VBScript into the Powershell code?
Here is the working Powershell code (modified again) if anyone is interested:
$ErrorActionPreference= 'silentlycontinue'
Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' -Properties * | Select-Object Name |
ForEach-Object {
If (Test-Connection $_.Name -Count 1){
Get-HotFix -ComputerName $_.Name | Sort-Object InstalledOn -Descending | Select-Object -First 1
}
else {
Write-host $_.Name " Connection Error"
}
} |
Sort-Object InstalledOn
Tim Ferrill already provided you the answer but for the record you could have done something like this
$ScriptBlock = {
$hash=@{}
$Session = New-Object -ComObject Microsoft.Update.Session
$Searcher = $Session.CreateUpdateSearcher()
$hash[$env:Computername] = $Searcher.QueryHistory(1,1) | select -ExpandProperty Date
$hash
}
Invoke-Command -ComputerName $serverlist -ScriptBlock $ScriptBlock
This would get you something like
Name Value
---- -----
Server1 5/16/2014 2:11:42 PM
Server2 4/14/2014 1:55:03 PM
Server3 5/6/2014 5:36:51 PM