Updated – Get-Product PowerShell CMDLET – Version 2.0

Hmmm… After 50 downloads in TechNet. Nobody actually commented in TechNet on these bugs in Q and A section for so long. Maybe it isn’t that popular for Administrator to perform an application audit or most of them rely on SCCM for application reports. Not until a colleague of mine started using it and notified me.

And a bug is still a bug, so I found some time to fix those bugs and make major improvements.

Improvements
– Added a ShowError parameter to display every server that has WMI error
– Removed CSVOutput and ErrorOutput parameter feature as an additional feature for output to CSV file
– Added the capability to allow Get-Product to be pipelined to another command
– Added more EXAMPLE in the Get-Help comment section

Bugs Found
– Unable to pipeline a list of hostname in a text file to Get-Product cmdlet
– Scanning of computer objects for hostname in Active Directory generates a 0 value causing issue when exporting output to CSV file

Bugs Fixes
– Fixed the pipeline issue in Get-Product cmdlet
– Fixed the 0 value when the scanning of computer object in Active Directory

Download Link – http://gallery.technet.microsoft.com/Get-Product-8da22470

function Get-Product {  
<#     
.SYNOPSIS     
 
    Get product installed within the host  
    
.DESCRIPTION 
 
    Allow Administrators to query WMI namespace on installed product and determine the number of host with the product   
    in the Domain. Administrators can also manually query WMI namespace on installed product on localhost or multiple  
    hosts remotely. 
  
.PARAMETER ComputerName  
 
    This parameter allows you to input a specific hostname.  
   
.PARAMETER Domain  
 
    This parameter allows you to scan the computers within the domain.  
  
.PARAMETER Caption  
 
    This parameter allows you to filter the output for the specified caption.  
  
.PARAMETER Description  
 
    This parameter allows you to filter the output for the specified description.  
  
.PARAMETER InstallDate  
 
    This parameter allows you to filter the output for the specified install date.  
  
.PARAMETER InstallLocation  
 
    This parameter allows you to filter the output for the specified install location.  
  
.PARAMETER Name  
 
    This parameter allows you to filter the output for the specified name.  
  
.PARAMETER Vendor  
 
    This parameter allows you to filter the output for the specified vendor.  
  
.PARAMETER Version  
 
    This parameter allows you to filter the output for the specified version.  
  
.PARAMETER ShowError 
 
    This parameter allows you to output probe error on Win32_Product through WMI  
  
.EXAMPLE 
    This example shows how to use Get-Product to list any installed application 
    from this vendor. 
 
    PS C:\> Get-Product -Vendor "Sun Microsystems, Inc." 
 
 
    PSComputerName    : Redmond 
    Name              : Java(TM) SE Runtime Environment 6 Update 1 
    Version           : 1.6.0.10 
    InstallState      : 5 
    __GENUS           : 2 
    __CLASS           : Win32_Product 
    __SUPERCLASS      : CIM_Product 
    __DYNASTY         : CIM_Product 
    __RELPATH         : Win32_Product.IdentifyingNumber="{3248F0A8-6813-11D6-A77B-00B0D0160010}",Name="Java(TM) SE Runtime 
                        Environment 6 Update 1",Version="1.6.0.10" 
    __PROPERTY_COUNT  : 27 
    __DERIVATION      : {CIM_Product} 
    __SERVER          : Redmond 
    __NAMESPACE       : root\cimv2 
    __PATH            : \\Redmond\root\cimv2:Win32_Product.IdentifyingNumber="{3248F0A8-6813-11D6-A77B-00B0D0160010}",Name 
                        ="Java(TM) SE Runtime Environment 6 Update 1",Version="1.6.0.10" 
    AssignmentType    : 1 
    Caption           : Java(TM) SE Runtime Environment 6 Update 1 
    Description       : Java(TM) SE Runtime Environment 6 Update 1 
    HelpLink          : http://java.com 
    HelpTelephone     : 
    IdentifyingNumber : {3248F0A8-6813-11D6-A77B-00B0D0160010} 
    InstallDate       : 20130924 
    InstallDate2      : 
    InstallLocation   : 
    InstallSource     : C:\Users\ContosoUser\AppData\LocalLow\Sun\Java\jre1.6.0_01\ 
    Language          : 0 
    LocalPackage      : C:\Windows\Installer\d3407e3c.msi 
    PackageCache      : C:\Windows\Installer\d3407e3c.msi 
    PackageCode       : {3248F0A6-6813-11D6-A77B-00B0D0160010} 
    PackageName       : jre1.6.0_01.msi 
    ProductID         : none 
    RegCompany        : 
    RegOwner          : Windows User 
    SKUNumber         : 
    Transforms        : 
    URLInfoAbout      : http://java.com 
    URLUpdateInfo     : http://java.sun.com 
    Vendor            : Sun Microsystems, Inc. 
    WordCount         : 0 
    Scope             : System.Management.ManagementScope 
    Path              : \\Redmond\root\cimv2:Win32_Product.IdentifyingNumber="{3248F0A8-6813-11D6-A77B-00B0D0160010}",Name 
                        ="Java(TM) SE Runtime Environment 6 Update 1",Version="1.6.0.10" 
    Options           : System.Management.ObjectGetOptions 
    ClassPath         : \\Redmond\root\cimv2:Win32_Product 
    Properties        : {AssignmentType, Caption, Description, HelpLink...} 
    SystemProperties  : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} 
    Qualifiers        : {dynamic, Locale, provider, UUID} 
    Site              : 
    Container         : 
 
 
.EXAMPLE  
    This example shows any error with WMI connection to WIN32_Product when you receive no output. 
 
    PS C:\> Get-Product -ComputerName Contoso -ShowError 
 
 
    __SERVER        : Contoso 
    OperatingSystem : 
    ErrorCode       : -2147023174 
    Message         : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA) 
 
 
.EXAMPLE 
    This example shows how to use Get-Product to probe the entire domain. 
 
    PS C:\> Get-Product -Domain 
 
 
.EXAMPLE 
    This example shows how to use Get-Product to probe a few server from text file. 
 
    PS C:\> Get-Content C:\Temp\ServerList.txt | Get-Product 
 
      
.OUTPUT  
    By default, the Get-Product output is returned to the screen. In order to out to CSV file, 
    pipe the command to Export-Csv cmdlet like below. 
 
    Get-Product | Export-Csv C:\Temp\Get-Product-Output.csv -NoTypeInformation 
 
 
.NOTES     
    Author  : Ryen Kia Zhi Tang  
    Date    : 06/03/2013  
    Blog    : ryentang.wordpress.com  
    Version : 2.0 
 
    Change Log 
    06/11/2013 - Updated this Get-Product to version 2.0 
                 Updated with more EXAMPLE on how to use Get-Product. 
                 Fixed bugs when being used in a pipeline. 
                 Removed -CSVOutput and -ErrorOutput parameter. You can pipeline to Export-CSV cmdlet. 
                 Changed handling Error output with a new parameter to show error seperately. 
                 Added new -ShowError parameter. 
 
#>  
  
[CmdletBinding(  
    SupportsShouldProcess=$True,  
    ConfirmImpact='High')]  
      
param (  
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$True,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $ComputerName = $Env:ComputerName,  
      
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$True,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [Switch] $Domain,  
      
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $Caption, 
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $Description, 
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $InstallDate, 
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $InstallLocation, 
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $Name, 
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $Vendor = "",  
  
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
      
    [String] $Version,  
      
[Parameter(  
    Mandatory=$False,  
    ValueFromPipeline=$False,  
    ValueFromPipelineByPropertyName=$True)]  
          
    [Switch] $ShowError 
  
)  
  
BEGIN {}  
  
PROCESS {  
    $ErrorActionPreference = "SilentlyContinue"  
  
    #Create an object to store data  
    $Object = New-Object PSObject 
  
    if($Domain) {  
      
        #Create directory entry object  
        $objDomain = New-Object System.DirectoryServices.DirectoryEntry  
  
        #Create directory searcher object  
        $objSearcher = New-Object System.DirectoryServices.DirectorySearcher  
        $objSearcher.SearchRoot = $objDomain  
  
        #Input custom filter  
        $objSearcher.Filter = ("(&(objectCategory=Computer)(operatingSystem=Windows Server *))")  
  
  
        if($PSBoundParameters['Verbose']) { Write-Verbose "Scanning the Domain..." }  
          
        #Get properties  
        $propertieslist = "*"  
        foreach ($i in $propertieslist){$objSearcher.PropertiesToLoad.Add($i) | Out-Null}  
        $items = $objSearcher.FindAll()  
          
        $totalComputerObject = $($items | Measure-Object | %{$_.Count})  
        $counterComputerObject = 1  
  
        foreach($item in $items) {  
              
            $item = $item.Properties  
            $ComputerName = [string] $item.name  
              
            if($PSBoundParameters['Verbose']) { Write-Verbose "Checking $ComputerName for Product..." }  
  
            Write-Progress -Id 0 -Activity "Scanning the Domain..." -Status "Found $ComputerName" -PercentComplete ($counterComputerObject++ / $totalComputerObject*100) -CurrentOperation "Establishing Connection..."  
              
            $Object = Find-Product $ComputerName $Caption $Description $InstallDate $InstallLocation $Name $Vendor $Version  
             
            #Verify any error from returned object 
            if($Object.ErrorCode -eq $null) {  
                  
                if($ShowError -ne $TRUE) { $Object | Select * } 
              
            }else{  
                  
                if($ShowError -eq $TRUE) { $Object | Select * } 
              
            }  
  
        }  
          
    }else{  
      
         if($PSBoundParameters['Verbose']) { Write-Verbose "Checking $ComputerName for Product..." }  
          
         $Object = Find-Product $ComputerName $Caption $Description $InstallDate $InstallLocation $Name $Vendor $Version  
          
         if($Object.ErrorCode -eq $null) {  
          
            if($ShowError -ne $TRUE) { $Object | Select * } 
          
         }else{  
 
            if($ShowError -eq $TRUE) { $Object | Select * } 
          
         }  
      
    }  
 
}  
  
END { if($PSBoundParameters['Verbose']) { Write-Verbose "Done!!!" } }  
  
}  
  
  
  
function Find-Product($ComputerName, $Caption, $Description, $InstallDate, $InstallLocation, $Name, $Vendor, $Version) {  
  
BEGIN {}  
  
PROCESS { 
 
    $Result = @()  
    $Object = gwmi -ComputerName $ComputerName -Class Win32_Product -Impersonation Impersonate -Authentication PacketPrivacy -ErrorVariable err | Select-Object *  
  
    if($err) {  
      
        if($PSBoundParameters['Verbose']) { Write-Host $err -ForegroundColor Red }  
  
        $OperatingSystem = gwmi -ComputerName $ComputerName -Class Win32_OperatingSystem -Impersonation Impersonate -Authentication PacketPrivacy -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Caption          
          
        #Create an object to store data  
        $Error = New-Object PSObject  
          
        $Error | Add-Member -MemberType noteproperty -Name "__SERVER" -Value $ComputerName  
        $Error | Add-Member -MemberType noteproperty -Name "OperatingSystem" -Value $OperatingSystem  
        $Error | Add-Member -MemberType noteproperty -Name "ErrorCode" -Value $($err | Select -ExpandProperty Exception).ErrorCode  
        $Error | Add-Member -MemberType noteproperty -Name "Message" -Value $($err | Select -ExpandProperty Exception).Message  
  
        return $Error 
      
    }else{  
          
        $totalInstalledProduct = $($Object | Measure-Object | %{$_.Count})  
        $counterInstalledProduct = 1  
  
        foreach($item in $Object) {  
      
            Write-Progress -Id 1 -ParentId 0 -Activity "Scanning $ComputerName..." -Status "Checking All Programs" -PercentComplete ($counterInstalledProduct++ / $totalInstalledProduct*100) -CurrentOperation "Checking installed product: $($item | Select -ExpandProperty Name)"  
                     
            if($($item | Select -ExpandProperty Caption) -like $Caption) {  
              
                $Result += $item  
              
            }elseif($($item | Select -ExpandProperty Description) -like $Description) {  
              
                $Result += $item  
              
            }elseif($($item | Select -ExpandProperty InstallDate) -like $InstallDate) {  
              
                $Result += $item  
              
            }elseif($item.InstallLocation -ne $null) {  
              
                if($($item | Select -ExpandProperty InstallLocation) -like $InstallLocation) {  
                      
                    $Result += $item  
                  
                }  
              
            }elseif($($item | Select -ExpandProperty Name) -like $Name) {  
              
                $Result += $item  
              
            }elseif($($item | Select -ExpandProperty Vendor) -like $Vendor) {  
              
                $Result += $item  
              
            }elseif($($item | Select -ExpandProperty Version) -like $Version) {  
              
                $Result += $item  
              
            }elseif(($Caption -eq "") -and ($Description -eq "") -and ($InstallDate -eq "") -and ($InstallLocation -eq "") -and ($Name -eq "") -and ($Vendor -eq "") -and ($Version -eq "")){ 
             
                $Result += $item  
 
            }  
              
        }  
          
        Write-Progress -Id 1 -ParentId 0 -Activity "Scanning $ComputerName..." -Status "Completed" -Completed  
   }  
 
}  
  
END { return $Result }  
  
}  
  
Export-ModuleMember -Function Get-Product