I used to use generally win32_product wmi class to fetch installed software list from remote computer systems. But the problem with it is, It only retrieves the installed applications via MSI, However, this WMI class might not list all the installed softwares that show in Add or Remove Programs, appwiz.cpl. One answer to this issue is to collect data on installed softwares/programs from the registry, (note that not all software inscribe to the registry when they are setup on the windows computer)" https://technet.microsoft.com/en-us/library/ee692772.aspx#EBAA WMI requests on class win32_product are repeatedly slow and can yield up to 1-3 minutes for each machine. It essentially runs every MSI to collect the software data information. This could be exploited very easily. In fact for examples, when you do this for certain Intel driver software you reset the default values. This may conflict with your security policy if they are predefined.
Another option is win32reg_addremoveprogams wmi class, but it comes only when you install SCCM client.
Installed software information is stored in registry under below paths.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
There is one more location, but in most of the cases no application or nothing will be listed there.
HKEY_USERS\User_SID\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
This script is based on my earlier articles and requires Remote Registry service up and running.
Part 1: Powershell: Get registry value data from remote computer
Part 1.1: Microsoft Powershell: Export remote registry information to excel
Part 2: Microsoft Powershell: remotely write, edit, modify new registry key and data value
Part 3: Microsoft Powershell: Delete registry key or values on remote computer
Different ways to bypass Powershell execution policy :.ps1 cannot be loaded because running scripts is disabled
Installing, importing and using any module in powershell
Download script here, This is also available on Github. To use this script copy paste in ps1 file and follow above blogs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#function Get-InstalledSoftwareInfo { <# .Synopsis Get installed software information from remote computer. .Description This cmdlet Get-InstalledSoftwareInfo will fetch and retrive information from remote and local computer. This requires remote registry service to be running. .Example Get-InstalledSoftwareInfo -ComputerName Server01 This retrives list from computername server01 .Example Get-InstalledSoftwareInfo -ComputerName Server01 | Export-CSV -Path c:\temp\info.csv Get-InstalledSoftwareInfo -ComputerName Server01 | ft Using pipeline information can be exported to CSV or shows tablewise .OutPuts ComputerName DisplayName DisplayVersion Publisher InstallDate EstimatedSize ------------ ----------- -------------- --------- ----------- -------- Server01 Microsoft Visual C++ 2012 x64 Additional Runtime - 11.0.61030 11.0.61030 Microsoft Corporation 20171225 5.82MB Server01 Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161 9.0.30729.6161 Microsoft Corporation 20170820 1.04MB .Notes NAME: Get-InstalledSoftwareInfo AUTHOR: Kunal Udapi CREATIONDATE: 02 January 2018 LASTEDIT: 7 January 2017 KEYWORDS: Get installed software application information .Link #Check Online version: http://kunaludapi.blogspot.com #Check Online version: http://vcloud-lab.com #Requires -Version 3.0 #> [CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact='Medium', HelpURI='http://vcloud-lab.com')] Param ( [parameter(Position=0, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)] [alias('C')] [String[]]$ComputerName = 'server01' #'.' ) Begin { } Process { Foreach ($Computer in $ComputerName) { if (Test-Connection $Computer -Count 2 -Quiet) { $RegistryHive = 'LocalMachine' $RegistryKeyPath = $('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall') $RegistryRoot= "[{0}]::{1}" -f 'Microsoft.Win32.RegistryHive', $RegistryHive $RegistryHive = Invoke-Expression $RegistryRoot -ErrorAction Stop foreach ($regpath in $RegistryKeyPath) { try { $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryHive, $Computer) $key = $reg.OpenSubKey($regpath, $true) } catch { Write-Host "Check permissions on computer name $Computer, cannot connect registry" -BackgroundColor DarkRed Continue } foreach ($subkey in $key.GetSubKeyNames()) { $Childsubkey = $key.OpenSubKey($subkey) $SoftwareInfo = $Childsubkey.GetValueNames() $Displayname = $Childsubkey.GetValue('DisplayName') [Int]$rawsize = $Childsubkey.GetValue('EstimatedSize') $ConvertedSize = $rawsize / 1024 $SoftwareSize = "{0:N2}MB" -f $ConvertedSize if ($SoftwareInfo -contains 'DisplayName') { $SoftInfo = [PSCustomObject]@{ ComputerName = $Computer DisplayName = $Childsubkey.GetValue('DisplayName') DisplayVersion = $Childsubkey.GetValue('DisplayVersion') Publisher = $Childsubkey.GetValue('Publisher') InstallDate = $Childsubkey.GetValue('InstallDate') EstimatedSize = $SoftwareSize InstallLocation = $Childsubkey.GetValue('InstallLocation') InstallSource = $Childsubkey.GetValue('InstallSource') UninstallString = $Childsubkey.GetValue('UninstallString') RegistryLocation = $Childsubkey.Name } $SoftInfo } $Childsubkey.close() } $key.close() } } else { Write-Host "Computer Name $Computer not reachable" -BackgroundColor DarkRed } } } End { #[Microsoft.Win32.RegistryHive]::ClassesRoot #[Microsoft.Win32.RegistryHive]::CurrentUser #[Microsoft.Win32.RegistryHive]::LocalMachine #[Microsoft.Win32.RegistryHive]::Users #[Microsoft.Win32.RegistryHive]::CurrentConfig } } #Get-InstalledSoftwareInfo -ComputerName Server01, Member01 | ft |
Although if you are using latest PowerShell version 5.x and there is no requirement to gather this information from remote registry, There is by default native command provided Get-Package. It can be easily used with Powershell remoting/ winrm to pull data. This will even get the patches, updates and hotfixes information.
POWERSHELL PS REMOTING BETWEEN STANDALONE WORKGROUP COMPUTERS
Useful Articles
GUI - SETUP AND CONFIGURE POWERSHELL WEB ACCESS SERVER (GATEWAY)
USE POWERSHELL ON MOBILE - SETUP AND CONFIGURE POWERSHELL WEB ACCESS (PSWA)
Powershell Trick : Execute or run any file as a script file
Set Powershell execution policy with Group Policy
Powershell execution policy setting is overridden by a policy defined at a more specific scope