Critical Control 2 - Inventory of Authorized and Unauthorized Software

Published: 2011-10-04
Last Updated: 2011-10-04 20:00:50 UTC
by Rob VandenBrink (Version: 1)
9 comment(s)

From a support point of view, when someone calls the Helpdesk with a "there's something going on with my pc" question, very early in the process you'll want to know what is installed on that computer, and then what versions of each installed application.  It's also handy to know *when* things were installed - if things just started to go wrong, knowing what was just installed is a must-know.  Of course, the person making the call will always say "I didn't install anything", but once you have that list, the hasty "oh, except for that" is generally quickly forthcoming.

So a software inventory is useful for support, but why is it second on the Security Critical Controls list?  Well, if one of  your users has rights to install their own software, they will.  As time goes by is it likely that they'll install patches and updates?  What about version updates?  Did they pay for that app at all?  This highlights the big gaping hole in the "I'll admin my own machine" end-user argument.  6 months after they are given rights to administer their own computer,  their software will be 6 months out of date, and the machine will have 6 months worth of security vulnerabilities on it (and most likely the exploits to match them).  Not a good thing to plug back into the head office LAN.

So, in a Windows environment, how can you easily get a listing of installed software?  Luckily, you can script all this stuff, and better yet, script it to run daily, from a central location, and store the results centrally.

Note, all the script examples are pretty much lifted from a semi-recent GIAC Gold Paper of mine ( ).  I won't put it forth as the be-all and end-all reference for this (I didn't invent any of this stuff), but it was a handy place for me to go to for these stuff, since it's all in one place.  Another great place to go for LOTS of information on scripting is the Command Line Kung Fu site, at

We'll use WMIC (Windows Management Interface Command Line) for the Windows software inventory.  No surprise there - years ago, I would have used VBS files (and I still keep them around, just in case), but these days WMIC is just too easy for this type of reporting.  What you'll also find is that many of the fancy-dancy, for-sale-for-real-dollars inventory applications out there are simply a collection of WMI calls with a tuxedo on (a cool menu and pretty reports) - so you can save yourself some budget dollars and run these reports yourself, using your knowledge of your environment and a little bit of script development time.

To get all installed software in a Windows Domain or subnet range,  you'll only need a few commands:

wmic os get name
Get the OS installed on the station
wmic os get servicepackmajorversion
Next, the Service Pack
wmic qfe list brief And the list of patches and updates (QFE = Quick Fix Engineering)
wmic service list Next, list the services installled
wmic product get vendor, name, version, installdate, packagecache, description, identifyingnumber
Finally, for all installed applications, list the information we might find useful in this context

For all of these commands, we'll tack on a formating option to pretty up the output, presenting the report in an HTML table:

Now, we have the bare bones of a script.  Let's put it all together, in a short script we'll called inven.cmd (short for inventory)
inven will run all the associated reports, and drop them into a separate subdirectory named for each hostname being inventoried.  (note from the environment variables that I pulled this little script out of a much larger one).

=========== inven.cmd =========

set HOST=%1
set DIRNAME=%1
set UID=%2
set PWD=%3


wmic /output:%DIRNAME%\patches.htm /user:%UID% /password:%PWD% /node:%HOST% qfe list brief /format:htable
wmic /output:%DIRNAME%\os.htm /user:%UID% /password:%PWD% /node:%HOST% os list full /format:hform
wmic /output:%DIRNAME%\products.htm /user:%UID% /password:%PWD% /node:%HOST% product get vendor,name,version,installdate,packagecache,description,identifyingnumber /format:htable
wmic /output:%DIRNAME%\services.htm /user:%UID% /password:%PWD% /node:%HOST% service list /format:htable


Wait, but I said we'd run that for the entire Windows AD Domain - how do we do that?

First, get a simple list of all computers in the domain - we'll use DSQUERY for that.  The easiest way to run this is from a Domain Controller.  Note that I'm using "cut" to only give me just the names of the computers in a list - you can get "cut" by installing Microsoft Services for Unix (SFU), or use GNUTILS like throwbacks like me (I'm still getting around to installing SFU everywhere I need it, whereas the GNU utilities are all self-contained exe's)

dsquery computer  -s DCname  -u domainname\administrator -p adminpassword -limit 10000  | cut -d "," -f1 | cut -d "=" -f2 >>hostlist.txt

(you could use "dsquery servers"  to inventory server class computers)

Now that we have inven.cmd and the list of hosts in hostlist.txt, let's combine them and get the full report, by creating DOMLOOP.CMD, which will contain a single line (Note that USERID and PASSWORD will need rights to login to the remote hosts and run the WMIC commands)


Now, you say, what about malware?  Oddly enough, lots of the malware out there (many of the FAKE-AV packages for instance), actually use the Windows installer and register themselves.  You can any apps that *don't* register using variations on  "dir c:\*.exe /s", or, if you are looking for hidden and/or system files, you can use variants on "attrib c:\*.exe /s" (or whatever file type, not just exe's).

What's that, you have Linux stations and servers?  Even easier, there are only about a dozen ways to get the same info out of Linux.  I'll hit one method for each of the variants I normally see

============ Redhat ==============

For startup services (and when they are configured to start), use chkconfig –list

[robv@pt01 ~]$ chkconfig --list
NetworkManager     0:off    1:off    2:on    3:on    4:on    5:on    6:off
abrtd              0:off    1:off    2:off    3:on    4:off    5:on    6:off
acpid              0:off    1:off    2:on    3:on    4:on    5:on    6:off
atd                0:off    1:off    2:off    3:on    4:on    5:on    6:off
auditd             0:off    1:off    2:on    3:on    4:on    5:on    6:off
avahi-daemon       0:off    1:off    2:off    3:on    4:on    5:on    6:off
bluetooth          0:off    1:off    2:off    3:on    4:on    5:on    6:off
btseed             0:off    1:off    2:off    3:off    4:off    5:off    6:off
... and so on ...

to list all installed packages:
rpm -qa

... (and so on)

for more information on a specific package, use rpm -qi

[robv@pt01 ~]$ rpm -qi python
Name        : python                       Relocations: (not relocatable)
Version     : 2.6.4                             Vendor: Fedora Project
Release     : 27.fc13                       Build Date: Fri 04 Jun 2010 02:22:55 PM EDT
Install Date: Sat 19 Mar 2011 08:21:36 PM EDT      Build Host:
Group       : Development/Languages         Source RPM: python-2.6.4-27.fc13.src.rpm
Size        : 21238314                         License: Python
Signature   : RSA/SHA256, Fri 04 Jun 2010 02:36:33 PM EDT, Key ID 7edc6ad6e8e40fde
Packager    : Fedora Project
URL         :
Summary     : An interpreted, interactive, object-oriented programming language
Description :
Python is an interpreted, interactive, object-oriented programming
language often compared to Tcl, Perl, Scheme or Java. Python includes
(and so on)

For more information, on all packages (perhaps too much), use rpm -qia

================ Debian, Ubuntu and the like ===================
To get a list of installed applications:

dpkg --get-selections
to get more information in the list:
dpkg -l

Name                                 Version                                         Description
acpi-support                         0.136.1                                         scripts for handling many ACPI events
acpid                                1.0.10-5ubuntu2.1                               Advanced Configuration and Power Interface e
adduser                              3.112ubuntu1                                    add and remove users and groups
adium-theme-ubuntu                   0.1-0ubuntu1                                    Adium message style for Ubuntu
adobe-flash-properties-gtk                              GTK+ control panel for Adobe Flash Player pl
.... and so on ....

to get startups, I often just install chkconfig, and run it as on Redhat variants:
sudo apt-get install chkconfig
chkconfig --list

alternatively, sysv-rc-conf is an alternate package to do this (this will often also need an install)
sudo apt-get install sysv-rc-conf
sysv-rc-conf  --list



Finally, we're interested in how you tackle the software inventory problem.  Please use our comment form - let us know of any cool tools you use, or post any scripts you may have written to help out !



Rob VandenBrink

9 comment(s)


Shouldn't "set HOSTNAME=%1" say "set HOST=%1"?

I'm asking because right below you have "/node:%HOST%"

I was trying to run this script as a test on a local machine but not sure what "set HOSTNAME" should be.

If I'm wrong (cuz I'm also a newb) what should "set Hostname" be and just below what should "/node:%HOST%" be? Could I please have an example of both? I'm thinking the "/node:%HOST%" should probably be an IP address? I'm confused at this hour, but would really like to get the script working :)

Thank you in advance.
Correct, good catch !
I guess that's what happens when you cut from a larger script to make a small one.

Thanks very much!
Great tip, however when it's run on a Win7 box, i had a little trouble, error message;
"Invalid XSL format (or) file name."

After googling a little i found the solution, before running any wmic command that outputs to a formated file, we should first tell the PATH to look in "C:\Windows\System32\wbem\en-US" that's were the format "template" is.

Again very nice tip to make a simple "inventory"
If you don't have cut like me, this seems to work instead:

for /F "tokens=2 delims=,=" %i in ('dsquery computer -s DCname -u domainname\administrator -p adminpassword -limit 10000') do @echo %i
Hey Rob,

Just wanted to note that if your hostnames have any special characters in them such as dashes, you will get an 'invalid global variable' error and your folders will be empty.

the way around this is to put %HOST% and %DIRNAME%\filename.htm in single quotes:

wmic /output:'%DIRNAME%\os.htm' /user:%UID% /password:%PWD% /node:'%HOST%' os list full /format:hform
I would also like to know how others tackle the "users having admin privileges" problem? It almost seems that it's common sense for users NOT to be admins but I rarely seen that enforced in my experience thus far. I'll have to check if there's a poll already on how many companies restrict their users.
Collecting this info on a Windows domain can be done with the Microsoft Assessment and Planning Toolkit. It is a free download and does not require installation of an agent, and is pretty easy to use.
In any system, U*ix, Linux, or M$, even a non-admin can install an executable binary in their own directory. While this may not be under the OS's package control system, it can still be loaded and run, and thus constitute a potential problem. How does one deal with that?
OpenAudIT is an INCREDIBLE open source auditing tool.
install xampp with defaults and then openaudit pretty much just works, can be integrated with AD and audits EVERYTHING on a machine in great detail

Diary Archives