This code is great!... but with Server 2008 onward, Microsoft has changed the way the OS reports Installed Updates.
After some research, I'm able to get the non-OS Installed Updates (MS Office hotfixes, SQL Server Service Packs) using this code:
(This goes inside Private Shared Function InternalGetInstalledPrograms, between the lines "Next" and "'Close the registry keys")
Code:
'-- Windows 2008 - JFoushee (2/2012)
Dim key As RegistryKey = HklmPath.OpenSubKey("Software\Microsoft\Windows NT\CurrentVersion\")
Dim strTemp As String = key.GetValue("CurrentVersion").ToString()
If IsNumeric(strTemp) Then
Dim dblReturn As Double = Convert.ToDouble(strTemp)
If dblReturn >= 6.0 Then
'-- Windows 2008 non-QFE Patches
Dim Win2K8PatchKey As RegistryKey = HklmPath.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products")
ProgramList = Get2008NonQFEPatches(Win2K8PatchKey, HklmPath, ProgramList)
'not sure how to get QFEs by Registry
End If
End If
and this is a new function to go in the "Private Methods" region:
Code:
Private Shared Function Get2008NonQFEPatches(ByVal SystemKey As RegistryKey, ByVal HklmRootKey As RegistryKey, ByVal ExistingProgramList As List(Of InstalledProgram)) As List(Of InstalledProgram)
' addition provided by JFoushee (2/2012). No warranties/guarantees.
If Not SystemKey Is Nothing Then
Dim LmProductGuids() As String = SystemKey.GetSubKeyNames
For Each LmProductGuid As String In LmProductGuids
Dim InstallPropKey As RegistryKey = HklmRootKey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\" & LmProductGuid & "\InstallProperties")
If InstallPropKey IsNot Nothing Then
If Not CInt(InstallPropKey.GetValue("SystemComponent", 0)) = 1 Then
Dim ParentName As String = CStr(InstallPropKey.GetValue("DisplayName", String.Empty))
Dim Vendor As String = CStr(InstallPropKey.GetValue("Publisher", String.Empty))
Dim PatchesKey As RegistryKey = HklmRootKey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\" & LmProductGuid & "\Patches")
If PatchesKey IsNot Nothing Then
Dim LmPatchGuids() As String = PatchesKey.GetSubKeyNames
For Each LmPatchGuid As String In LmPatchGuids
If Not CInt(PatchesKey.OpenSubKey(LmPatchGuid).GetValue("State", 1)) = 2 Then
Dim Name As String = CStr(PatchesKey.OpenSubKey(LmPatchGuid).GetValue("DisplayName", String.Empty))
Dim InstallDate As String = ""
Try
InstallDate = CStr(PatchesKey.OpenSubKey(LmPatchGuid).GetValue("Installed", String.Empty))
Catch ex As Exception
End Try
If Not Name = String.Empty AndAlso Not IsProgramInList(Name, ExistingProgramList) Then
ExistingProgramList.Add(New InstalledProgram(Name, ParentName, True, "1", Vendor, "", "", InstallDate))
End If
End If
Next
End If
End If
End If
Next
End If
Return ExistingProgramList
End Function
Now, if someone could figure out the Windows 2008 OS-level hotfixes from the Registry...
(Yes, I 'could' use WMI's Win32_QuickFixEngineering... but then I have two security points-of-failure if someone blocked WMI access.)