The simplest way to accomplish what you're looking for in PowerShell is by using the following WMI query to grab packages that belong to an UpgradeCode family.
$UpgradeCode = '{AA783A14-A7A3-3D33-95F0-9A351D530011}'
$ProductGUIDs = @(Get-WmiObject -Class Win32_Property | Where-Object {$_.Property -eq 'UpgradeCode' -and $_.value -eq $UpgradeCode}).ProductCode
Get-WmiObject -Class Win32_Product | Where-Object {$ProductGUIDs -Contains $_.IdentifyingNumber}
The only downside to this it that both the Win32_Property and Win32_Product classes are slow, if time isn't a huge factor you can use that. If you need faster performance you can get similar information from the registry like this
function Decode-GUID {
param( [string]$GUID )
$GUIDSections = @( 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 )
$Position = 0
$result = @()
ForEach($GUIDSection In $GUIDSections)
{ $arr = $GUID.SubString($Position, $GUIDSection) -split "";
[array]::Reverse($arr);
$result = $result +($arr -join '').replace(' ','');
$Position += $GUIDSection }
return "{$(($result -join '').Insert(8,'-').Insert(13, '-').Insert(18, '-').Insert(23, '-'))}"
}
function Encode-GUID {
param( [string]$GUID )
$GUID = $GUID -creplace '[^0-F]'
$GUIDSections = @( 8, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2 )
$Position = 0
$result = ""
ForEach($GUIDSection In $GUIDSections)
{ $arr = $GUID.substring($Position, $GUIDSection) -split "";
[array]::Reverse($arr);
$result = $result + ($arr -join '').replace(' ','');
$Position += $GUIDSection }
return $result
}
function Get-Bitness {
param( [string]$Location )
if([Environment]::Is64BitOperatingSystem){
if($_.PSPath -match '\\SOFTWARE\\Wow6432Node'){
return '32'
}else{
return '64'
}
} else {
Return '32'
}
}
#Enter the UpgradeCode here
$UpgradeCode = Encode-GUID "{AA783A14-A7A3-3D33-95F0-9A351D530011}"
$ProductGUIDs = (Get-Item HKLM:"SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes\$UpgradeCode", HKLM:"SOFTWARE\Classes\Installer\UpgradeCodes\$UpgradeCode").Property |
Select-Object -Unique |
ForEach-Object {Decode-GUID $_}
Get-ChildItem HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
Where-Object {$ProductGUIDs -contains $_.PSChildName} |
Get-ItemProperty |
Select-Object -Property @{Name='PackageCode';Expression={$_.PSChildName}}, DisplayName, Publisher, DisplayVersion, InstallDate, PSParentPath, @{Name='Bitness';Expression={Get-Bitness $_.PSPath}}
In the registry the GUIDs used in the "Installer" sections are encoded to match the way C++ would natively use them. The Decode and Encode functions in the example above are based on the technique used in this Roger Zander blog post. Please excuse the messiness of some of the code, if you need any part of this explained please let me know. Hope this helps you.