Hoping someone can help me out with the two aspects of my script that I think is causing the most performance hindrance. Recreating the Array $Result
and using the Get-ItemProperty
on each and every key to get the required information. Is there a better way to accomplish this task?
Function Get-SoftwareList {
<#
#>
Param()
New-Variable -Force -ErrorAction SilentlyContinue -Name Result -Value @()
New-Variable -Force -ErrorAction SilentlyContinue -Name Function -Value @{}
$Function.Exclusions = (
"Security Update for Windows",
"Security Update for Microsoft",
"Update for Windows",
"Update for Microsoft",
"Hotfix for Windows",
"Update for Skype",
"Security Update for Skype"
)
If([IntPtr]::Size -eq 8){
$Function.OSArch='64-bit'
} Else{
$Function.OSArch='32-bit'
}
$Function.Registry = Get-Childitem -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
IF ($Function.OSArch -EQ "64-bit") {
$Function.Registry += Get-ChildItem -Path "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
}
ForEach ($Key in $Function.Registry) {
$Key = Get-ItemProperty -Path Registry::$Key
IF ($Key.DisplayName.length -NE 0) {
ForEach ($Exclusion in $Function.Exclusions) {
If ($Key.DisplayName.StartsWith($Exclusion) -EQ $True) {
$Skip = $True
Break
} Else {
$Skip = $False
}
}
IF ($Skip -EQ $False) {
$Result += New-Object PSObject -Property @{
DisplayName = $Key.DisplayName
Version = $Key.DisplayVersion
UninstallString = $Key.UninstallString
Publisher = $Key.Publisher
#ModifyPath = $Key.ModifyPath
InstallDate = $Key.InstallDate
}
}
}
}
Return $Result
}
1 Answer 1
Finding a very quick/reliable solution was actually significantly harder than I was expecting but this is the best I can come up with. It lists about ~130 applications in about 22ms on my computer.
Function Get-InstalledSoftware {
Param (
[Array]$Properties = @('DisplayName','DisplayVersion')
)
$Keys = "Software\Microsoft\Windows\CurrentVersion\Uninstall","SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
$Result = New-Object -TypeName 'System.Collections.ArrayList'
$BaseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$ENV:ComputerName)
ForEach($Key in $Keys) {
$RegKey = $BaseKey.OpenSubkey($key)
If($RegKey -ne $null) {
ForEach($subName in $RegKey.getsubkeynames()) {
foreach($sub in $RegKey.opensubkey($subName)) {
[string]$Name = $sub.getvalue("displayname")
If ($Name.trim().Length -gt 0) {
$HashProperty = @{}
ForEach ($CurrentProperty in $Properties) {
$HashProperty.$CurrentProperty = $sub.GetValue($CurrentProperty)
}#End-ForEach
$Result.add([psCustomObject]$HashProperty)
}#End-IF
}#End-ForEach
}#End-Foreach
}#End-IF
}#End-ForEach
$Result
}
The new script is not only significantly more flexible, but also significantly faster than previous solutions.
Measure-Command {
for($i = 0; $i -lt 100; $i++) {
Get-InstalledSoftware99 -Properties DisplayName,UninstallString,DisplayVersion
}
}
Measure-Command {
for($i = 0; $i -lt 100; $i++) {
Get-SoftwareList
}
}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 925
Ticks : 9259570
TotalDays : 1.07170949074074E-05
TotalHours : 0.000257210277777778
TotalMinutes : 0.0154326166666667
TotalSeconds : 0.925957
TotalMilliseconds : 925.957
Days : 0
Hours : 0
Minutes : 0
Seconds : 14
Milliseconds : 695
Ticks : 146959970
TotalDays : 0.00017009255787037
TotalHours : 0.00408222138888889
TotalMinutes : 0.244933283333333
TotalSeconds : 14.695997
TotalMilliseconds : 14695.997
Explore related questions
See similar questions with these tags.