Getting inventory data from remote computers is always fun and exciting. Most people can’t get enough of it. I’ve been told people will forego silly things like food, water or sex, just to have more fulfilling time with inventory reporting. Wars have been fought over it; cultures have formed religious rituals; all focused on the glory of the almighty inventory report.

There are many ways to confine inventory queries to a specific subset of all devices. If you have an endpoint management product like MEM/MECM/MEMCM/ConfigMgr/Intune/WhateverMicrosoftRenamesThem, or some other (third-party) tool, it’s usually built-in somewhere. Otherwise, you can often filter the devices using script (PowerShell, etc.) against some data source like AD, Azure AD, SQL, or even flat files (.txt, .csv, etc.).
But let’s just say, for the sake of mindless rambling, you have an environment without the benefit of an endpoint management product (yes, some of you will gasp in horror and shock, but these do exist), and maybe you happen to use WSUS to patch your Windows devices. And let’s just suppose that you need to quickly search for a particular registry value across all of the computers in a given WSUS computer group, for instance, your boss says something like “I need to know which machines in Patching Group 1 have VMware Tools, so I can find out how many Dwayne installed and go kick his ass!“.
The steps, in order, would look like the following:
- Get the members of the WSUS computer group
- Query the members (computers) for a particular registry key/value
You might think this would require a lot of code (and a lot of me blabbering some mindless gibberish about why, and whatever) but it actually doesn’t require a lot of code. Here’s one example…
[CmdletBinding()]
param (
[parameter()][string] $TargetGroupName = 'Patching Group 1',
[parameter()][string] $ProductName = 'VMware Tools*',
[parameter()][switch] $x86
)
Import-Module UpdateServices
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer()
$groups = $wsus.GetComputerTargetGroups()
Write-Verbose "$($groups.Count) groups returned"
$mygroup = $groups | Where-Object {$_.Name -eq "$TargetGroupName"}
$computers = $mygroup.GetComputerTargets() | Select-Object -ExpandProperty FullDomainName
Write-Verbose "$($members.Count) members returned"
if (!$x86) {
$RegKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
} else {
$RegKey = 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
}
Write-Verbose "querying remote registry key: $RegKey"
Invoke-Command -ComputerName ($computers) -ErrorAction SilentlyContinue -ScriptBlock {
$x = Get-ChildItem $Using:RegKey -ErrorAction SilentlyContinue |
Where-Object {$_.GetValue('DisplayName') -like $Using:ProductName}
$n = $x | ForEach-Object {$_.GetValue('DisplayName')}
$v = $x | ForEach-Object {$_.GetValue('DisplayVersion')}
[pscustomobject]@{
Computer = $env:COMPUTERNAME
Product = $n
Version = $v
}
}
Requirements / Caveats:
- A real, working WSUS environment, with at least one (1) computer group, that has at least one (1) computer in it, and real computers that you can connect to over your network
- This script is intended to be executed on the WSUS host, or a machine with the WSUS console installed (and the associated “UpdateServices” module), and MUST be executed within an elevated (aka “Administrator”) PowerShell session.
- The -ProductName parameter is intended to be a wildcard match string. If you wish to search for exact matches, remove the “*” and change the ScriptBlock line to use -eq instead of -like
- Exception handling? That’s funny.