Tech Off Thread

5 posts

how-to: Print/List installed programs/applications sorted by date

Back to Forum: Tech Off
  • androidi

    I wanted to copy the list of apps I've installed from control panel add/remove programs (programs and features - uninstall or change a program).

    Of course that doesn't work (in win7). And well since I prefer C# over powershell, here's a quick console app to print the stuff from the registry keys.

            static void Main(string[] args)
            {
                var apps = new List<InstalledApp>();
                using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")) GetInstalledAppValues(key, apps);
                using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")) GetInstalledAppValues(key, apps);
                using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall")) GetInstalledAppValues(key, apps);
                foreach (var a in apps.OrderBy(x => x.InstallDate.HasValue ? x.InstallDate.Value : DateTime.MinValue).ThenBy(x => x.Publisher).ThenBy(x => x.DisplayName))
                {
                    Console.WriteLine("{0,-10} {1,-35} {2} ",a.InstallDate.HasValue ? a.InstallDate.Value.ToShortDateString(): "",a.Publisher,a.DisplayName);
                }
            }
    
    
            private static void GetInstalledAppValues(RegistryKey key, List<InstalledApp> apps)
            {
                if (key == null) return;
                foreach (String keyName in key.GetSubKeyNames())
                {
                    var ia = new InstalledApp();
    
                    ia.DisplayName = (GetValue(key, keyName, "DisplayName") ?? "").Trim();
                    ia.DisplayVersion = GetValue(key, keyName, "DisplayVersion");
                    ia.InstallLocation = GetValue(key, keyName, "InstallLocation");
                    ia.InstallSource = GetValue(key, keyName, "InstallSource");
                    ia.Publisher = GetValue(key, keyName, "Publisher");
                    var dt = GetValue(key, keyName, "InstallDate");
                    if (dt != null)
                    {
                        DateTime res;
                        if (!DateTime.TryParseExact(dt, new string[] { "yyyyMMdd", "M/d/yyyy", "d" }, System.Threading.Thread.CurrentThread.CurrentCulture, System.Globalization.DateTimeStyles.AllowWhiteSpaces, out res))
                            DateTime.TryParseExact(dt, new string[] { "yyyyMMdd", "M/d/yyyy", "d" }, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AllowWhiteSpaces,out res);
                        if (res > DateTime.MinValue) ia.InstallDate = res;
                    }
                    if (!string.IsNullOrEmpty(ia.DisplayName)) apps.Add(ia);
                }
            }
    
            private static string GetValue(RegistryKey key, String keyName, string valueName)
            {
                RegistryKey subkey = key.OpenSubKey(keyName);
                return subkey.GetValue(valueName) as string;;
            }
    
            public class InstalledApp
            {
                public string DisplayName { get; set; }
                public string DisplayVersion { get; set; }
                public DateTime? InstallDate { get; set; }
                public string InstallLocation { get; set; }
                public string InstallSource { get; set; }
                public string Publisher { get; set; }
            }

  • androidi

    There is probably a bug in the InstallDate parsing. The date values in the registry came in probably 5 different formats and it seems it's not currently parsing all of the formats.

    edit: Looks like the control panel Programs and features is getting the install date of some applications from some other location than registry. But I couldn't see where in process monitor. I think I'm going to just check the possible file from UninstallString for the filedate.

  • androidi

    There appears to be easier ways to list the programs but they don't list all of the apps the above code does. This code however seems to also list stuff that has been uninstalled already but has left behind some stuff in the uninstall registry.

    Here's the other ways I found:

    powershell one liner, pretty awesome I'd say

    ((gp HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*) + (gp HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*) + (gp HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*)) | Select DisplayName,  DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString | ogv

    source: http://channel9.msdn.com/Forums/TechOff/PowerShell-How-to-concat-multiple-Get-ItemProperty-results-into-Out-GridView

    or

    Get-WmiObject -Class Win32_Product

    cmd prompt:

    wmic product

    (last two are very slow and incomplete, see notes at:

    http://blogs.technet.com/b/askds/archive/2012/04/19/how-to-not-use-win32-product-in-group-policy-filtering.aspx

    )

  • itsnotabug

    This looks good! I've done something similar by scraping the *.nfo output of MSINFO32 command line but this looks a lot better. 

  • androidi

    I wasn't happy that some of the apps didn't show the install date, so I'm now parsing the uninstaller string and getting the last write date but some of the apps have the file dates all set to the time the developer made the app instead of the install time...

    There's also a way to query MSI for install date also.

    These changes made the class so big I'm not bothering to paste it here.

    There are also some special cases with the uninstaller string that make the parsing complicated and it would need more testing that I have time for.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.