Earlier this month I posted about getting the installed updates and/or hotfixes.
This got me thinking… what about installed software?
If you want to compare servers to each other, installed software may be just as important as installed updates and/or hotfixes.
However, the first step would be to get the installed software. Only after that, we’ll be able to compare them…
So, here we go. This time I’m not using PowerShell remoting, simply because there is no need to.
Remote WMI is just fine for this 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function Get-InstalledSoftware { param ( [parameter(mandatory=$true)][array]$ComputerName ) foreach ($Computer in $ComputerName) { $OSArchitecture = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture if ($OSArchitecture -like '*64*') { [array]$RegistryPath = 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall','Software\Microsoft\Windows\CurrentVersion\Uninstall' } else { [array]$RegistryPath = 'Software\Microsoft\Windows\CurrentVersion\Uninstall' } $Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer) $Array = @() foreach ($RegPath in $RegistryPath) { $RegistryKey = $Registry.OpenSubKey("$RegPath") $RegistryKey.GetSubKeyNames() | foreach { $Registry.OpenSubKey("$RegPath\$_") | Where-Object {($_.GetValue("DisplayName") -notmatch '(KB[0-9]{6,7})') -and ($_.GetValue("DisplayName") -ne $null)} | foreach { $Object = New-Object -TypeName PSObject $Object | Add-Member -MemberType noteproperty -Name 'Name' -Value $($_.GetValue("DisplayName")) $Object | Add-Member -MemberType noteproperty -name 'ComputerName' -value $Computer $Object } } } } } |
My next post will be a function that utilizes the function above in order to compare installed software between devices. 🙂
*** EDIT ***
As Dave Wyatt pointed out in the comments, the above function doesn’t always work, for example on a x64 system. Next to that, the used WMI class isn’t available on all systems. This is a pesky little issue if you expect the function to work in all situations, which it should.
Dave mentioned registry keys that could be used, so I updated the post.
Then JSchell replied to me on Twitter that I wasn’t looking for apps installed on a x64 system that registered themselves under the x86 registry.
Combine those two feedbacks with my original function and you’ll get the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function Get-InstalledSoftware { param ( [parameter(mandatory=$true)][array]$ComputerName ) foreach ($Computer in $ComputerName) { $OSArchitecture = (Get-WMIObject -ComputerName $Computer win32_operatingSystem -ErrorAction Stop).OSArchitecture if ($OSArchitecture -like '*64*') { $RegistryPath = 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall' } else { $RegistryPath = 'Software\Microsoft\Windows\CurrentVersion\Uninstall' } $Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer) $RegistryKey = $Registry.OpenSubKey("$RegistryPath") $RegistryKey.GetSubKeyNames() | foreach { $Registry.OpenSubKey("$RegistryPath\$_") | Where-Object {($_.GetValue("DisplayName") -notmatch '(KB[0-9]{6,7})') -and ($_.GetValue("DisplayName") -ne $null)} | foreach { $Object = New-Object -TypeName PSObject $Object | Add-Member -MemberType noteproperty -Name 'Name' -Value $($_.GetValue("DisplayName")) $Object | Add-Member -MemberType noteproperty -name 'ComputerName' -value $Computer $Object } } } } |
I got error when I run this: Get-WmiObject : Invalid class “Win32Reg_AddRemovePrograms”
What OS are you running? I’ve tested this on WS208R2 and above…
According to this MSDN blog post: http://blogs.technet.com/b/askds/archive/2012/04/19/how-to-not-use-win32-product-in-group-policy-filtering.aspx , Win32Reg_AddRemovePrograms was a custom WMI class originally added by SMS, but hasn’t been updated since and doesn’t report on 32-bit software when used to query 64-bit operating systems.
All it appears to be doing is querying the HKLMSoftwareMicrosoftWindowsCurrentVersionUninstall subkeys for their DisplayName and DisplayVersion values. To get it working properly on 64-bit systems, you’d have to include HKLMSoftwareWow6432nodeMicrosoftWindowsCurrentVersionUninstall as well.
Hi Dave,
Thanks! I’ll investigate and edit the post appropriately.
Jeff.