Last active
September 25, 2024 14:09
-
-
Save indented-automation/32efb05a5fb67ef9eed02bbb8fe90691 to your computer and use it in GitHub Desktop.
Get-InstalledSoftware
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Get-InstalledSoftware { | |
<# | |
.SYNOPSIS | |
Get all installed from the Uninstall keys in the registry. | |
.DESCRIPTION | |
Read a list of installed software from each Uninstall key. | |
This function provides an alternative to using Win32_Product. | |
.EXAMPLE | |
Get-InstalledSoftware | |
Get the list of installed applications from the local computer. | |
.EXAMPLE | |
Get-InstalledSoftware -IncludeLoadedUserHives | |
Get the list of installed applications from the local computer, including each loaded user hive. | |
.EXAMPLE | |
Get-InstalledSoftware -ComputerName None -DebugConnection | |
Display all error messages thrown when attempting to audit the specified computer. | |
.EXAMPLE | |
Get-InstalledSoftware -IncludeBlankNames | |
Display all results, including those with very limited information. | |
#> | |
[CmdletBinding()] | |
[OutputType([PSObject])] | |
param ( | |
# The computer to execute against. By default, Get-InstalledSoftware reads registry keys on the local computer. | |
[Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] | |
[String]$ComputerName = $env:COMPUTERNAME, | |
# Attempt to start the remote registry service if it is not already running. This parameter will only take effect if the service is not disabled. | |
[Switch]$StartRemoteRegistry, | |
# Some software packages, such as DropBox install into a users profile rather than into shared areas. Get-InstalledSoftware can increase the search to include each loaded user hive. | |
# | |
# If a registry hive is not loaded it cannot be searched, this is a limitation of this search style. | |
[Switch]$IncludeLoadedUserHives | |
) | |
begin { | |
$keys = @( | |
'Software\Microsoft\Windows\CurrentVersion\Uninstall' | |
'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' | |
) | |
} | |
process { | |
# If the remote registry service is stopped before this script runs it will be stopped again afterwards. | |
if ($StartRemoteRegistry) { | |
$shouldStop = $false | |
$service = Get-Service RemoteRegistry -Computer $ComputerName | |
if ($service.Status -eq 'Stopped' -and $service.StartType -ne 'Disabled') { | |
$shouldStop = $true | |
$service | Start-Service | |
} | |
} | |
$baseKeys = [System.Collections.Generic.List[Microsoft.Win32.RegistryKey]]::new() | |
$baseKeys.Add([Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName, 'Registry64')) | |
if ($IncludeLoadedUserHives) { | |
try { | |
$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $ComputerName, 'Registry64') | |
foreach ($name in $baseKey.GetSubKeyNames()) { | |
if (-not $name.EndsWith('_Classes')) { | |
Write-Debug ('Opening {0}' -f $name) | |
try { | |
$baseKeys.Add($baseKey.OpenSubKey($name, $false)) | |
} catch { | |
$errorRecord = [System.Management.Automation.ErrorRecord]::new( | |
$_.Exception.GetType()::new( | |
('Unable to access sub key {0} ({1})' -f $name, $_.Exception.InnerException.Message.Trim()), | |
$_.Exception | |
), | |
'SubkeyAccessError', | |
'InvalidOperation', | |
$name | |
) | |
Write-Error -ErrorRecord $errorRecord | |
} | |
} | |
} | |
} catch [Exception] { | |
Write-Error -ErrorRecord $_ | |
} | |
} | |
foreach ($baseKey in $baseKeys) { | |
Write-Verbose ('Reading {0}' -f $baseKey.Name) | |
if ($basekey.Name -eq 'HKEY_LOCAL_MACHINE') { | |
$username = 'LocalMachine' | |
} else { | |
# Attempt to resolve a SID | |
try { | |
[System.Security.Principal.SecurityIdentifier]$sid = Split-Path $baseKey.Name -Leaf | |
$username = $sid.Translate([System.Security.Principal.NTAccount]).Value | |
} catch { | |
$username = Split-Path $baseKey.Name -Leaf | |
} | |
} | |
foreach ($key in $keys) { | |
try { | |
$uninstallKey = $baseKey.OpenSubKey($key, $false) | |
if ($uninstallKey) { | |
$is64Bit = $true | |
if ($key -match 'Wow6432Node') { | |
$is64Bit = $false | |
} | |
foreach ($name in $uninstallKey.GetSubKeyNames()) { | |
$packageKey = $uninstallKey.OpenSubKey($name) | |
$installDate = Get-Date | |
$dateString = $packageKey.GetValue('InstallDate') | |
if (-not $dateString -or -not [DateTime]::TryParseExact($dateString, 'yyyyMMdd', (Get-Culture), 'None', [Ref]$installDate)) { | |
$installDate = $null | |
} | |
[PSCustomObject]@{ | |
Name = $name | |
DisplayName = $packageKey.GetValue('DisplayName') | |
DisplayVersion = $packageKey.GetValue('DisplayVersion') | |
InstallDate = $installDate | |
InstallLocation = $packageKey.GetValue('InstallLocation') | |
HelpLink = $packageKey.GetValue('HelpLink') | |
Publisher = $packageKey.GetValue('Publisher') | |
UninstallString = $packageKey.GetValue('UninstallString') | |
URLInfoAbout = $packageKey.GetValue('URLInfoAbout') | |
Is64Bit = $is64Bit | |
Hive = $baseKey.Name | |
Path = Join-Path -Path $key -ChildPath $name | |
Username = $username | |
ComputerName = $ComputerName | |
} | |
} | |
} | |
} catch { | |
Write-Error -ErrorRecord $_ | |
} | |
} | |
} | |
# Stop the remote registry service if required | |
if ($StartRemoteRegistry -and $shouldStop) { | |
$service | Stop-Service | |
} | |
} | |
} |
@indented-automation the IncludeBlank parameter is present but doesn't do anything that I can see upon quick scan
powershell terminal with administrator privileges: set-executionpolicy unrestricted and after ./GetInstalledSoftware.ps1 return nothing (no error...)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Please consider pulling my fork of this script, as it adds a new switch, that makes the script work even if the Remote Registry service is disabled.
https://gist.github.com/averkios/cca9001a8d18889371853ac7e269ceda