Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to Win32_Product?

After playing around with querying Win32_Product to find a software version, I couldn't understand why the results were so dog-slow. As much as 15 times slower than querying Win32_service or Win32_process. So coming here to see if I'm missing something, I find that others have reported the same issue, and this article explains why.

The most-often suggested alternative to finding installed software is querying a registry entry or three. That was going to be my first solution, except my company hasn't moved to configure servers to accept PSRemoting yet. Any reg queries just return Kerberos authentication errors. I can enable PSRemoting on individual servers, but my team supports 30K systems. So that solution is out.

Bottom line, we're upgrading Symantec Endpoint Protection from v. 11 to v. 12, and I want a simple check to find what version is installed on a server. Are there any alternatives to find the version other than Win32_Product and registry queries?

like image 702
James Brown Avatar asked Aug 12 '14 15:08

James Brown


1 Answers

I use the registry remotely, without PSRemoting. Here's the function I wrote and use daily to query software.

Function Get-RemoteSoftware{
<#
.SYNOPSIS 
Displays all software listed in the registry on a given computer.

.DESCRIPTION
Uses the SOFTWARE registry keys (both 32 and 64bit) to list the name, version, vendor, and uninstall string for each software entry on a given computer.

.EXAMPLE
C:\PS> Get-RemoteSoftware -ComputerName SERVER1
This shows the software installed on SERVER1.
#>

param (
    [Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
    # Specifies the computer name to connect to
    $ComputerName
)

Process {
    foreach ($Computer in $ComputerName)
    {
        #Open Remote Base
        $reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)

        #Check if it's got 64bit regkeys
        $keyRootSoftware = $reg.OpenSubKey("SOFTWARE")
        [bool]$is64 = ($keyRootSoftware.GetSubKeyNames() | ? {$_ -eq 'WOW6432Node'} | Measure-Object).Count
        $keyRootSoftware.Close()

        #Get all of they keys into a list
        $softwareKeys = @()
        if ($is64){
            $pathUninstall64 = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
            $keyUninstall64 = $reg.OpenSubKey($pathUninstall64)
            $keyUninstall64.GetSubKeyNames() | % {
                $softwareKeys += $pathUninstall64 + "\\" + $_
            }
            $keyUninstall64.Close()
        }
        $pathUninstall32 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
        $keyUninstall32 = $reg.OpenSubKey($pathUninstall32)
        $keyUninstall32.GetSubKeyNames() | % {
            $softwareKeys += $pathUninstall32 + "\\" + $_
        }
        $keyUninstall32.Close()

        #Get information from all the keys
        $softwareKeys | % {
            $subkey=$reg.OpenSubKey($_)
            if ($subkey.GetValue("DisplayName")){
                $installDate = $null
                if ($subkey.GetValue("InstallDate") -match "/"){
                    $installDate = Get-Date $subkey.GetValue("InstallDate")
                }
                elseif ($subkey.GetValue("InstallDate").length -eq 8){
                    $installDate = Get-Date $subkey.GetValue("InstallDate").Insert(6,".").Insert(4,".")
                }
                New-Object PSObject -Property @{
                    ComputerName = $Computer
                    Name = $subkey.GetValue("DisplayName")
                    Version = $subKey.GetValue("DisplayVersion")
                    Vendor = $subkey.GetValue("Publisher")
                    UninstallString = $subkey.GetValue("UninstallString")
                    InstallDate = $installDate
                }
            }

            $subkey.Close()
        }
        $reg.Close()
    }
}  

}

like image 126
Chris N Avatar answered Sep 21 '22 12:09

Chris N