4
\$\begingroup\$

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
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.