Finding Installed Software using Python

Have you ever wondered what software was installed on your PC? Most people who use Windows would probably go to Add/Remove Programs to find out this information, but they’re not programmers. No, programmers have to script it because it’s just in our blood to do so. I actually had another reason to do so: my boss wanted me to log what was installed on our user’s PCs so we’d know if our users were installing unauthorized software. Thus, there’s also a practical reason to attempt this.

After some research, I discovered that most well-behaved software will store various pieces of information about themselves in the Windows Registry. Specifically, they usually store this information in the following location: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall

It should be noted that not all programs that you install will put that information in the Registry. We have vendors who don’t use the Registry at all, for example. Also, nefarious programs like malware probably won’t put anything there either. However, well over 90% do so this is a good way to get the information. To get more, you’d probably need to do some directory walking with Python’s os module using it’s “walk” methods and look for mismatches from that compared to what’s in the Registry or maybe from some stored image that you’ve kept from a virgin base machine.

Anyway, enough talk. Let’s take a look at the code! Note: if you’d like to follow along then you’ll need to download and install Tim Golden’s WMI module.

import StringIO
import traceback
import wmi
from _winreg import (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, 
                     OpenKey, EnumValue, QueryValueEx)

softFile = open('softLog.log', 'w')
errorLog = open('errors.log', 'w')

r = wmi.Registry ()
result, names = r.EnumKey (hDefKey=HKEY_LOCAL_MACHINE, sSubKeyName=r"Software\Microsoft\Windows\CurrentVersion\Uninstall")

softFile.write('These subkeys are found under "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall"\n\n')
errorLog.write("Errors\n\n")
separator = "*" * 80
keyPath = r"Software\Microsoft\Windows\CurrentVersion\Uninstall"

for subkey in names:
    try:
        softFile.write(separator + '\n\n')
        path = keyPath + "\\" + subkey
        key = OpenKey(HKEY_LOCAL_MACHINE, path, 0, KEY_ALL_ACCESS) 
        try:
            temp = QueryValueEx(key, 'DisplayName')
            display = str(temp[0])
            softFile.write('Display Name: ' + display + '\nRegkey: ' + subkey + '\n')
        except:
            softFile.write('Regkey: ' + subkey + '\n')

    except:
        fp = StringIO.StringIO()
        traceback.print_exc(file=fp)
        errorMessage = fp.getvalue()
        error = 'Error for ' + key + '. Message follows:\n' + errorMessage
        errorLog.write(error)
        errorLog.write("\n\n")

softFile.close()
errorLog.close()

This is a pretty short snippet, but there’s a lot going on here. Let’s unpack it. First we import the modules we need and then open a couple of files: softFile will store all the software our script finds in “softLog.log” whereas our errorLog variable will store any errors we encounter in “errors.log”. Next we use WMI to enumerate over the subkeys in the “Uninstall” key. After that, we write a some title info to each log file to make them easier to read.

The last important piece occurs in the loop structure. Here we loop over the results returned from our WMI call. In our loop, we try to pull out two pieces of information: the Display Name of the software and the key that it’s associated with. There is lots of other information to be had, but there doesn’t seem to be any standards that are adhered to, so I didn’t grab any of that. You would need more complex error handling to extract it nicely (or maybe use generators some how). Anyway, if either of the pieces that we try to pull out fails, we catch the error and keep going. The nested exception handing catches the error related to getting the display name whereas the outer exception handler catches errors related to accessing the Registry. We should probably make these exceptions explicit (for example, the latter should be WindowsError, I think), but this is just a quick and dirty script. Feel free to extend it as much as you deem necessary.

If we encounter an error in either location, we log something. In the nested case, we just log the Regkey’s name to “softLog.log”, whereas in the outer case, we just log an error to “errors.log”. At the end, we clean up by closing the files.

Here’s a partial sample of what I get when I run this script on my Windows XP machine:


These subkeys are found under "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall"

********************************************************************************

Display Name: Windows Driver Package - Garmin (grmnusb) GARMIN Devices (03/08/2007 2.2.1.0)
Regkey: 45A7283175C62FAC673F913C1F532C5361F97841
********************************************************************************

Regkey: AddressBook
********************************************************************************

Display Name: Adobe Flash Player 10 ActiveX
Regkey: Adobe Flash Player ActiveX
********************************************************************************

Display Name: Adobe Flash Player 10 Plugin
Regkey: Adobe Flash Player Plugin
********************************************************************************

Display Name: Python 2.4 adodb-2.00
Regkey: adodb-py2.4
********************************************************************************

Display Name: Agent Ransack
Regkey: Agent Ransack
********************************************************************************

Display Name: Amazon Games & Software Downloader
Regkey: Amazon Games & Software Downloader_is1
********************************************************************************

Display Name: Amazon MP3 Downloader 1.0.3
Regkey: Amazon MP3 Downloader
********************************************************************************

Display Name: ZoneAlarm Spy Blocker Toolbar
Regkey: Ask Toolbar_is1
********************************************************************************

Display Name: Aspell English Dictionary-0.50-2
Regkey: Aspell English Dictionary_is1
********************************************************************************

Now you know how to extract most of the software installed on your Windows box. I’ve tested this primarily on Windows XP with Python 2.5, but it should work on Windows Vista and 7 too. Windows 7 and Vista usually forces the default user to run with lower privileges that XP, so you may be required to run this script as Administrator or impersonate the Administrator. Have fun!

3 thoughts on “Finding Installed Software using Python”

  1. Very handy…this was exactly the type of example code I was looking for 🙂 Nice write up…thanks!

  2. Using python 3.1 and the socketserver module, everything appears correct, but obviously I’m missing something. The socketserver I’ve coded will run, and remain open on the server side until I kill the server. However when a client connects to the socket, it will send a banner as I have programmed it to, but then from the client’s point of view, the socket closes immediately after receiving the banner. Mark part of hemorrhoids treatment team.

Comments are closed.