Scripts/Get-InstalledPrograms.ps1
#Requires -Version 3.0 [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '')] [CmdletBinding()] Param() $RegQueryInfoKey = @' [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKeyW")] public static extern int RegQueryInfoKey(Microsoft.Win32.SafeHandles.SafeRegistryHandle hKey, IntPtr lpClass, IntPtr lpcchClass, IntPtr lpReserved, IntPtr lpcSubKeys, IntPtr lpcbMaxSubKeyLen, IntPtr lpcbMaxClassLen, IntPtr lpcValues, IntPtr lpcbMaxValueNameLen, IntPtr lpcbMaxValueLen, IntPtr lpcbSecurityDescriptor, out UInt64 lpftLastWriteTime); '@ if (!('PSWinGlue.GetInstalledPrograms' -as [Type])) { $AddTypeParams = @{ } if ($PSVersionTable.PSObject.Properties['PSEdition'] -and $PSVersionTable.PSEdition -eq 'Core') { $AddTypeParams['ReferencedAssemblies'] = 'Microsoft.Win32.Registry' } Add-Type -Namespace PSWinGlue -Name GetInstalledPrograms -MemberDefinition $RegQueryInfoKey @AddTypeParams } $Results = New-Object -TypeName Collections.ArrayList $TypeName = 'PSWinGlue.InstalledProgram' Update-TypeData -TypeName $TypeName -DefaultDisplayPropertySet @('Name', 'Publisher', 'Version', 'Scope') -Force # Programs installed system-wide in native bitness $ComputerNativeRegPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall' # Programs installed only under the current-user (any bitness) $UserRegPath = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall' # Programs installed system-wide under the 32-bit emulation layer (64-bit Windows only) $ComputerWow64RegPath = 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' # Retrieve all installed programs from available keys $UninstallKeys = Get-ChildItem -Path $ComputerNativeRegPath if (Test-Path -Path $ComputerWow64RegPath -PathType Container) { $UninstallKeys += Get-ChildItem -Path $ComputerWow64RegPath } if (Test-Path -Path $UserRegPath -PathType Container) { $UninstallKeys += Get-ChildItem -Path $UserRegPath } # Filter out all the uninteresting installation results foreach ($UninstallKey in $UninstallKeys) { $Program = Get-ItemProperty -Path $UninstallKey.PSPath # Skip any program which doesn't define a display name if (!$Program.PSObject.Properties['DisplayName']) { continue } # Ensure the program either: # - Has an uninstall command # - Is marked as non-removable if (!($Program.PSObject.Properties['UninstallString'] -or ($Program.PSObject.Properties['NoRemove'] -and $Program.NoRemove -eq 1))) { continue } # Skip any program which defines a parent program if ($Program.PSObject.Properties['ParentKeyName'] -or $Program.PSObject.Properties['ParentDisplayName']) { continue } # Skip any program marked as a system component if ($Program.PSObject.Properties['SystemComponent'] -and $Program.SystemComponent -eq 1) { continue } # Skip any program which defines a release type if ($Program.PSObject.Properties['ReleaseType']) { continue } $Result = [PSCustomObject]@{ PSTypeName = $TypeName PSPath = $Program.PSPath Name = $Program.DisplayName Publisher = $null InstallDate = $null EstimatedSize = $null Version = $null Location = $null Uninstall = $null Scope = $null } if ($Program.PSObject.Properties['Publisher']) { $Result.Publisher = $Program.Publisher } # Try and convert the InstallDate value to a DateTime if ($Program.PSObject.Properties['InstallDate']) { $RegInstallDate = $Program.InstallDate if ($RegInstallDate -match '^[0-9]{8}') { try { $Result.InstallDate = New-Object -TypeName DateTime -ArgumentList $RegInstallDate.Substring(0, 4), $RegInstallDate.Substring(4, 2), $RegInstallDate.Substring(6, 2) } catch { } } if (!$Result.InstallDate) { Write-Warning -Message ('[{0}] Registry key has invalid value for InstallDate: {1}' -f $Program.DisplayName, $RegInstallDate) } } # Fall back to the last write time of the registry key if (!$Result.InstallDate) { [UInt64]$RegLastWriteTime = 0 $Status = [PSWinGlue.GetInstalledPrograms]::RegQueryInfoKey($UninstallKey.Handle, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero, [ref]$RegLastWriteTime) if ($Status -eq 0) { $Result.InstallDate = [DateTime]::FromFileTime($RegLastWriteTime) } else { Write-Warning -Message ('[{0}] Retrieving registry key last write time failed with status: {1}' -f $Program.DisplayName, $Status) } } if ($Program.PSObject.Properties['EstimatedSize']) { $Result.EstimatedSize = $Program.EstimatedSize } if ($Program.PSObject.Properties['DisplayVersion']) { $Result.Version = $Program.DisplayVersion } if ($Program.PSObject.Properties['InstallLocation']) { $Result.Location = $Program.InstallLocation } if ($Program.PSObject.Properties['UninstallString']) { $Result.Uninstall = $Program.UninstallString } if ($Program.PSPath.startswith('Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE')) { $Result.Scope = 'System' } else { $Result.Scope = 'User' } $null = $Results.Add($Result) } return ($Results | Sort-Object -Property Name) |