Private/_GetInstalledSoftware.ps1

Function _GetInstalledSoftware {
    <#
    .SYNOPSIS
        Get-InstalledSoftware retrieves a list of installed software
    .DESCRIPTION
        Get-InstalledSoftware opens up the specified (remote) registry and scours it for installed software. When found it returns a list of the software and it's version.
    .PARAMETER ComputerName
        The computer from which you want to get a list of installed software. Defaults to the local host.
    .EXAMPLE
        Get-InstalledSoftware DC1
 
        This will return a list of software from DC1. Like:
        Name Version Computer UninstallCommand
        ---- ------- -------- ----------------
        7-Zip 9.20.00.0 DC1 MsiExec.exe /I{23170F69-40C1-2702-0920-000001000000}
        Google Chrome 65.119.95 DC1 MsiExec.exe /X{6B50D4E7-A873-3102-A1F9-CD5B17976208}
        Opera 12.16 DC1 "C:\Program Files (x86)\Opera\Opera.exe" /uninstall
    .EXAMPLE
        Import-Module ActiveDirectory
        Get-ADComputer -filter 'name -like "DC*"' | Get-InstalledSoftware
 
        This will get a list of installed software on every AD computer that matches the AD filter (So all computers with names starting with DC)
    .INPUTS
        [string[]]Computername
    .OUTPUTS
        PSObject with properties: Name,Version,Computer,UninstallCommand
    .NOTES
        Author: Anthony Howell
 
        To add directories, add to the LMkeys (LocalMachine)
    .LINK
        [Microsoft.Win32.RegistryHive]
        [Microsoft.Win32.RegistryKey]
    #>

    Param(
        [Parameter()]
        [string]$Identity
    )
    Begin {
        if (!(Test-Connection -ComputerName $Identity -Count 1 -Quiet)) {
            Write-Error -Message "Unable to contact $Identity. Please verify its network connectivity and try again." -Category ObjectNotFound -TargetObject $Identity
            Break
        }

        $ScriptBlock = { $lmKeys = 'Software\Microsoft\Windows\CurrentVersion\Uninstall', 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
            $lmReg = [Microsoft.Win32.RegistryHive]::LocalMachine
            $cuKeys = 'Software\Microsoft\Windows\CurrentVersion\Uninstall'
            $cuReg = [Microsoft.Win32.RegistryHive]::CurrentUser
            $masterKeys = @()
            $remoteCURegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($cuReg, $Identity)
            $remoteLMRegKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($lmReg, $Identity)
            foreach ($key in $lmKeys) {
                $regKey = $remoteLMRegKey.OpenSubkey($key)
                foreach ($subName in $regKey.GetSubkeyNames()) {
                    foreach ($sub in $regKey.OpenSubkey($subName)) {
                        $masterKeys += (New-Object PSObject -Property @{
                                'ComputerName'     = $env:COMPUTERNAME
                                'Name'             = $sub.getvalue('displayname')
                                'SystemComponent'  = $sub.getvalue('systemcomponent')
                                'ParentKeyName'    = $sub.getvalue('parentkeyname')
                                'Version'          = $sub.getvalue('DisplayVersion')
                                'UninstallCommand' = $sub.getvalue('UninstallString')
                                'InstallDate'      = if ($sub.getvalue('InstallDate')) {
                                    Get-Date ([datetime]::parseexact($sub.getvalue('InstallDate'), 'yyyyMMdd', $null)) -Format 'MM/dd/yyyy'
                                }
                                else {
                                    'Unknown'
                                }
                                'RegPath'          = $sub.ToString()
                            })
                    }
                }
            }
            foreach ($key in $cuKeys) {
                $regKey = $remoteCURegKey.OpenSubkey($key)
                if ($null -ne $regKey) {
                    foreach ($subName in $regKey.getsubkeynames()) {
                        foreach ($sub in $regKey.opensubkey($subName)) {
                            $masterKeys += (New-Object PSObject -Property @{
                                    'ComputerName'     = $env:COMPUTERNAME
                                    'Name'             = $sub.getvalue('displayname')
                                    'SystemComponent'  = $sub.getvalue('systemcomponent')
                                    'ParentKeyName'    = $sub.getvalue('parentkeyname')
                                    'Version'          = $sub.getvalue('DisplayVersion')
                                    'UninstallCommand' = $sub.getvalue('UninstallString')
                                    'InstallDate'      = if ($sub.getvalue('InstallDate')) {
                                        Get-Date ([datetime]::parseexact($sub.getvalue('InstallDate'), 'yyyyMMdd', $null)) -Format 'MM/dd/yyyy'
                                    }
                                    else {
                                        'Unknown'
                                    }
                                    'RegPath'          = $sub.ToString()
                                })
                        }
                    }
                }
            }
            $woFilter = { $null -ne $_.name -AND $_.SystemComponent -ne '1' -AND $null -eq $_.ParentKeyName }
            $props = 'Name', 'Version', 'ComputerName', 'Installdate', 'UninstallCommand' #, 'RegPath'
            $masterKeys = ($masterKeys | Where-Object $woFilter | Select-Object $props | Sort-Object Name)
            $masterKeys
        }
    }
    Process {
        if ($Identity -eq $env:COMPUTERNAME) {
            $Output = Invoke-Command -ScriptBlock $ScriptBlock
        }
        else {
            $Session = New-PSSession -ComputerName $Identity -ErrorAction SilentlyContinue
            If (!($Session)) {
                Return 'Offline'
            }

            $Output = Invoke-Command -Session $Session -ScriptBlock $ScriptBlock
        }
    }
    End {
        return $Output
    }
}