public/Get-PspSoftware.ps1

Function Get-PspSoftware {
    <#
    .SYNOPSIS
    Get the installed software for local or remote machines.
 
    .DESCRIPTION
    Get the installed software for local or remote machines.
    Will try and access the required data through a PowerShell remoting session, but in case this fails reverts to RemoteRegistry.
    This does however require RemoteRegistry to be enabled on the machine.
    Will look for both x86 and x64 installed paths.
 
    .PARAMETER ComputerName
    Provide the computername(s) to query.
    Using this parameter will create a temporary PSSession to obtain the information if available.
    If PowerShell remoting is not available, it will try and obtain the information through ADSI.
    Default value is the local machine.
 
    .PARAMETER Credential
    Provide the credentials for the PowerShell remoting session to be created if current credentials are not sufficient.
 
    .PARAMETER PSSession
    Provide the PowerShell remoting session object to query if this is already available.
    Once the information has been gathered, the PowerShell session will remain available for further use.
 
    .EXAMPLE
    PS C:\> Get-PspSoftware -ComputerName CONTOSO-SRV01,CONTOSO-WEB01,CONTOSO-APP01
 
    ComputerName : CONTOSO-SRV01
    DisplayName : Google Chrome
    Version : 72.0.3626.121
    InstallDate : 3/11/2019 12:00:00 AM
    Publisher : Google LLC
    UninstallString : MsiExec.exe /X{0C8D8E7A-485A-39D9-82C9-DF0955BE2A57}
    InstallLocation :
    InstallSource : C:\Users\Administrator\AppData\Local\Temp\1\Temp1_GoogleChromeEnterpriseBundle64.zip\Installers\
    HelpLink :
    EstimatedSizeMB : 54.5
    InventoryDate : 3/12/2019 10:25:45 AM
 
    ComputerName : CONTOSO-SRV01
    DisplayName : Google Update Helper
    Version : 1.3.33.23
    InstallDate : 3/11/2019 12:00:00 AM
    Publisher : Google Inc.
    UninstallString : MsiExec.exe /I{60EC980A-BDA2-4CB6-A427-B07A5498B4CA}
    InstallLocation :
    InstallSource : C:\Program Files (x86)\Google\Update\1.3.33.23\
    HelpLink :
    EstimatedSizeMB : 0.04
    InventoryDate : 3/12/2019 10:25:45 AM
 
    ComputerName : CONTOSO-WEB01
    DisplayName : VLC media player
    Version : 3.0.6
    InstallDate :
    Publisher : VideoLAN
    UninstallString : "C:\Program Files (x86)\VideoLAN\VLC\uninstall.exe"
    InstallLocation : C:\Program Files (x86)\VideoLAN\VLC
    InstallSource :
    HelpLink :
    EstimatedSize : 0
    InventoryDate : 3/12/2019 10:25:45 AM
 
    ComputerName : CONTOSO-APP01
    DisplayName : Notepad++ (32-bit x86)
    Version : 7.6.4
    InstallDate :
    Publisher : Notepad++ Team
    UninstallString : C:\Program Files (x86)\Notepad++\uninstall.exe
    InstallLocation :
    InstallSource :
    HelpLink :
    EstimatedSize : 4.35
    InventoryDate : 3/12/2019 10:25:45 AM
 
    Gets the installed software for CONTOSO-SRV01, CONTOSO-WEB01 and CONTOSO-APP01.
 
 
    .NOTES
    Name: Get-PspSoftware.ps1
    Author: Robert Prüst
    Module: PSP-Inventory
    DateCreated: 21-02-2019
    DateModified: 12-03-2019
    Blog: http://powershellpr0mpt.com
 
    .LINK
    http://powershellpr0mpt.com
    #>


    [OutputType('PSP.Inventory.Software')]
    [Cmdletbinding(DefaultParameterSetName = 'Computer')]
    param(
        [Parameter(Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Computer')]
        [ValidateNotNullorEmpty()]
        [Alias('CN')]
        [String[]]$ComputerName = $env:COMPUTERNAME,
        [Parameter(ParameterSetName = 'Computer')]
        [PSCredential]$Credential,
        [Parameter(Position = 0, ValueFromPipeline = $true, ParameterSetName = 'Session')]
        [Alias('Session')]
        [System.Management.Automation.Runspaces.PSSession[]]$PSSession
    )
    process {
        if ($PSCmdlet.ParameterSetName -eq 'Computer') {
            $PSSession = @()
            $SessionProperties = @{
                ErrorAction  = 'Stop'
                Computername = ''
            }
            if ($Credential.Username) {
                $SessionProperties.Add('Credential', $Credential)
            }
            foreach ($Computer in $ComputerName) {
                $Computer = $Computer.toUpper()
` $SessionProperties.ComputerName = $Computer
                Try {
                    $PSSession += New-PSSession @SessionProperties
                }
                catch [System.Management.Automation.Remoting.PSRemotingTransportException] {
                    Write-Warning "[$Computer] - Unable to open PS Remoting session. Reverting to Remote Registry"
                    try {
                        $Paths = @("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
                        foreach ($Path in $Paths) {
                            Write-Verbose "[$Computer] - Checking Registry Path: $Path"
                            $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer, 'Registry64')
                            try {
                                $regkey = $reg.OpenSubKey($Path)
                                $subkeys = $regkey.GetSubKeyNames()
                                foreach ($key in $subkeys) {
                                    Write-Verbose "[$Computer] - Checking Registry Key: $Key"
                                    $thisKey = $Path + "\\" + $key
                                    try {
                                        $thisSubKey = $reg.OpenSubKey($thisKey)
                                        $DisplayName = $thisSubKey.getValue("DisplayName")
                                        if ($DisplayName -AND $DisplayName -notmatch '^Update for|rollup|^Security Update|^Service Pack|^HotFix') {
                                            $Date = $thisSubKey.GetValue('InstallDate')
                                            if ($Date) {
                                                try {
                                                    $Date = [datetime]::ParseExact($Date, 'yyyyMMdd', $Null)
                                                }
                                                catch {
                                                    $Date = $Null
                                                }
                                            }
                                            $Publisher = try {
                                                $thisSubKey.GetValue('Publisher').Trim()
                                            }
                                            catch {
                                                $thisSubKey.GetValue('Publisher')
                                            }
                                            $Version = try {
                                                $thisSubKey.GetValue('DisplayVersion').TrimEnd(([char[]](32, 0)))
                                            }
                                            catch {
                                                $thisSubKey.GetValue('DisplayVersion')
                                            }
                                            $UninstallString = try {
                                                $thisSubKey.GetValue('UninstallString').Trim()
                                            }
                                            catch {
                                                $thisSubKey.GetValue('UninstallString')
                                            }
                                            $InstallLocation = try {
                                                $thisSubKey.GetValue('InstallLocation').Trim()
                                            }
                                            catch {
                                                $thisSubKey.GetValue('InstallLocation')
                                            }
                                            $InstallSource = try {
                                                $thisSubKey.GetValue('InstallSource').Trim()
                                            }
                                            catch {
                                                $thisSubKey.GetValue('InstallSource')
                                            }
                                            $HelpLink = try {
                                                $thisSubKey.GetValue('HelpLink').Trim()
                                            }
                                            catch {
                                                $thisSubKey.GetValue('HelpLink')
                                            }
                                            [PSCustomObject]@{
                                                PSTypeName      = 'PSP.Inventory.Software'
                                                ComputerName    = $Computer
                                                DisplayName     = $DisplayName
                                                Version         = $Version
                                                InstallDate     = $Date
                                                Publisher       = $Publisher
                                                UninstallString = $UninstallString
                                                InstallLocation = $InstallLocation
                                                InstallSource   = $InstallSource
                                                HelpLink        = $HelpLink
                                                EstimatedSizeMB = [math]::Round(($thisSubKey.GetValue('EstimatedSize') * 1024) / 1MB, 2)
                                                InventoryDate   = (Get-Date)
                                            }
                                        }
                                    }
                                    catch {
                                        Write-Warning "[$Computer] - Unable to access key: $Key "
                                    }
                                }
                            }
                            catch {}
                            $reg.Close()
                        }
                    }
                    catch {
                        Write-Error "[$Computer] - Unable to open Remote Registry"
                        Continue
                    }

                }
                catch {
                    Write-Warning "[$Computer] - cannot be reached. $($_.Exception.Message)"
                }
            }
        }
        foreach ($Session in $PSSession) {
            _GetSoftwareInfo -PSSession $Session
        }
    }
    End {
        if ($PSCmdlet.ParameterSetName -eq 'Computer' -AND $PSSession.count -gt 0) {
            Remove-PSSession $PSSession
        }
    }
}