You really don't have a choice but to get the information from each computer's registry.
This was the answer that I gave to another user several months ago. That person also had a need to modify the switches on the uninstall command line. You can use it as a template and customize it for your own needs:
$AppNames = @(
'App display name goes here'
)
$MsiExecOtherArgs = "/S /v /qn /norestart"
Function GetStartProcessArgs{
param (
[Parameter(mandatory=$true)]
[string]
$RemovalString,
[Parameter(mandatory=$false)]
[string]
$MoreArgs
)
$props = [ordered]@{}
if ($removalString -like "msiexec.exe *"){
$UninstallApp = $RemovalString -replace "/I", "/X"
$props['FilePath'] = $UninstallApp -replace '^([^ ]+) .*$', '$1' # get the executable name -- expects " /X{<guid>}" to always be there!
$props['ArgumentList'] = $UninstallApp -replace '^[^ ]+ ', '' # get the argument(s) -- expects " /X{<guid>}" to always be there!
if ($MoreArgs -and $MoreArgs.Length -gt 0){ # $MoreArgs can be an empty string too
$props.ArgumentList += (" " + $MoreArgs) # add additional arguments (with leading space to separate from previous args)
}
}
else{
# NOTE: ignores $MoreArgs entirely if msiexec.exe isn't the uninstaller to run
if ($RemovalString -match '^"'){ # a quoted string -- path contains a space
$props['FilePath'] = $RemovalString -replace '^"([^"]+?)" ?.*$', '$1' # keep spaces in path, drop quotes
if ($RemovalString -match '^".+?" ?'){
$potentialargs = $RemovalString -replace '^".+?" ?', '' # remove path, keep arguments
}
else{
$potentialargs = "" # return an empty string to avoid exceptions in code
}
}
else{
$props['FilePath'] = $RemovalString -replace '^([^ ]+?) .*$', '$1' # get the executable name (unquoted path)
$potentialargs = $RemovalString -replace '^[^ ]+ ', '' # get the argument(s), if there are any
}
if ($potentialargs.trim().length -gt 0){ # if no arguments, ignore
$props['ArgumentList'] = $potentialargs
}
}
# return exe and arguments
$props
}
# begin main code
# get 64-bit software on 64-bit systems OR 32-bit software on 32-bit systems
[array]$32_or_64bitsoftware = get-itemproperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
# get 32-bit software ON 64-bit systems
[array]$32_on_64bitsoftware = get-itemproperty 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
$AppNames|
ForEach-Object{
$appname = $_
[array]$32_AND_64bit = @()
# check for software in both locations
$32_AND_64bit = $32_or_64bitsoftware |
Where-Object { $_.DisplayName -like "*$appname*" }
$32_AND_64bit += $32_on_64bitsoftware |
Where-Object { $_.DisplayName -like "*$appname*" }
# was the app's display name found?
if ($32_AND_64bit.count -eq 0){
"'$appname' was not found on this system"
Write-Verbose "'$appname' was not found on this system"
}
else{
# uninstall all versions of this software
$32_AND_64bit |
ForEach-Object{
if ($_.UninstallString.length -gt 0){
$props = GetStartProcessArgs $_.UninstallString $MsiExecOtherArgs
Write-Verbose "Starting '$($props.FilePath)' with arguments '$($props.ArgumentList)'"
"Starting '$($props.FilePath)' with arguments '$($props.ArgumentList)'"
# uncomment next line when you're ready
#Start-Process @props -NoNewWindow -Wait
}
}
}
}