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