Remotely list programs and Features on computer exactly as in appwiz.cpl

Hello everyone,

Could you please help me on below, I am struck.

$list=@()
$css= @"
<style>
h1, h5, th { text-align: center; font-family: Segoe UI; }
h3 {font: bold 15px arial, serif;color: #336699; text-align: left;}
table { margin: auto; font-family: Segoe UI; box-shadow: 10px 10px 5px #888; border: thin ridge grey; }
th { background: #0046c3; color: #fff; max-width: 400px; padding: 5px 10px; }
td { font-size: 11px; padding: 5px 20px; color: #000; }
tr { background: #b8d1f3; }
tr:nth-child(even) { background: #dae5f4; }
tr:nth-child(odd) { background: #b8d1f3; }
</style>
"@

$pcname = "mywinpc"
$InstalledSoftwareKey="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$InstalledSoftware=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$pcname)
$RegistryKey=$InstalledSoftware.OpenSubKey($InstalledSoftwareKey)
$SubKeys=$RegistryKey.GetSubKeyNames()
Foreach ($key in $SubKeys){
$thisKey=$InstalledSoftwareKey+"\\"+$key
$thisSubKey=$InstalledSoftware.OpenSubKey($thisKey)
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "MachineName" -Value $pcname
$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $($thisSubKey.GetValue("DisplayName"))
$obj | Add-Member -MemberType NoteProperty -Name "Publisher" -Value $($thisSubKey.GetValue("Publisher"))
$obj | Add-Member -MemberType NoteProperty -Name "Version" -Value $($thisSubKey.GetValue("DisplayVersion"))

$list += $obj
}
$list | where { $_.Name } | Sort Name|select MachineName, Name, Publisher, Version |ConvertTo-Html -Head $css -Property *|Out-File .\Programs.html

I am trying to get the same report, but the date and other properties seems to be missing, any help would e greatly appreciated. Thanks

What you see in your control panel is a filtered assembly from several different sources. An easy way to come close to a similar list is by using WMI / CIM:

$Win32ProductList = Get-CimInstance -ClassName Win32_Product
$Win32ProductList | Select-Object -Property Name, Vendor, InstallDate, Version

Just an FYI, Win32_Product has it’s drawbacks, the worst of them being that on Windows 10, it triggers a “repair” on every product which takes forever. Just google “win32_product bad idea” for more details.

I wound up writing a function that enumerates both the 64bit and 32bit registry entries, removes duplicates, then pipes that through “Convert-ToHTML”. I could not afford to wait the time Win32_Product takes to enumerate when there might be 100’s of products installed.

Just my $.02

1 Like

I never needed to create a software inventory like this with PowerShell but when I tried to use Win32_Product I’ve never experienced any problems besides the lack of speed generating the list.

Anyway, I think there are a ton of examples for tasks like this out there and I suspect @Rahul20 just picked the worst one of them. :wink: Depending on the purpose of the task there are probably better options than that. To be more helpful we should have more information about the “end goal”. :wink:

Makes sense Olaf. I tried to use it, but the systems I was auditing had over 300 (many over 400) products installed and just this one section of my audit was taking 20+ minutes per system. When I went to the registry approach, it literally went down to a few seconds at best. The original post stated they want the result to look just like Appwiz.CPL … my approach does not do that. I piped the output through Convert-ToHTML. My interest was to sort by date and include the DisplayName, Version, Install Date, Publisher and any comments. I was able to grab all that from the registry.

I tried it on my machine with about 200 products listed and it did not take 30 seconds. I’d expect most of times it does not matter how long it takes for such a task. In a production environment I wouldn’t use this “direct remote” approach as it has other disadvantages. I’d rather set up a task locally on the remote machines generating the list and deliver it to a central share if there is no other dedicated product in place handling this type of task like SCCM for example.

Understood … and makes sense. Thanks.

yeah @tonyd , its taking longer time, can you please help me how can I achieve this

It looks like you are already using the registry approach which is the same method I used. What is your issue? The only difference between what I did and what you posted is that you are not enumerating both the 32bit and 64bit registry. Just add this to your script for 32bit entries:

‘SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall’

1 Like

thanks for the suggestion @tonyd