Collecting Hardware Information using C# and WMI

I’ve been playing around with C# lately putting together a little app that would collect hardware information about the computer it was running on. Stuff like CPU speed, amount of installed memory, CPU manufacturer, amount of cache, make and model of the machine and etc. I know that there is stuff out there that does this soft of thing well – for example CPU-Z which is excellent. What I wanted though was something a bit more idiot friendly.

The reasoning behind this is simple: users are idiots. Whenever I do any sort of support calls or troubleshooting with my users I spend most of the time trying to extract information out of them. What kind of computer do they have (standard answer: a laptop), how fast it is, how much memory there is, what is their IP address, subnet and default gateway, what DNS server they are using, the applications they have installed, the services they are currently running and etc… No one ever knows these details of the top of their head, and explaining to them how to check these details is time consuming. I mean, if you never had to explain to someone what a pingoogle is, then you probably haven’t done much network troubleshooting over the phone (for the record, that is what a luser will type if you don’t say SPACE between ping and google.com).

Wouldn’t it be nice if I could just offload all that diagnostic bullshit onto a piece of software that would extract bunch of important system information and display it on the screen so that the user could read it to me, or paste it into email. Or better yet, have the app periodically submit all this information to an online form somewhere so that I would have an ongoing record of the users machine and changes that were made to it. Yes, it would be great. I’d just need to write such a thing – and I could customize it specifically to my needs.

I already know how to send HTTPS POST requests with C# so I just needed to figure out how to extract the hardware information from the bowels of the users machine. After doing some research I found out that all I need is to learn how to talk to WMI.

In case you didn’t know WMI is a little magical gnome that lives inside your computer case, and communicates using (of all things) SQL. You can send that little guy an SQL like query and he will hop over to the CPU, lift the heat sink and read the clock speed off the device for you. Speak to him however you will need to add a System.Management reference to your project:

Add the System.Management reference

Once it is done, you need to familiarize yourself with Mr. ManagementObjectSearcher who is the dude that goes and pokes the gnome with the stick, hands him SQL queries and retrieves the results back for you. You initialize him with an SQL query like so:

ManagementObjectSearcher searcher = 
   new ManagementObjectSearcher("SELECT * FROM Win32_Processor");

No, seriously, that’s how it works. The name of the “tables” and attributes you can use in your queries can be found in the WMI documentation on MSDN. For example, if you want to find out information about the CPU you want to query the Win32_Processor class. If you read the docs you will find out that it has few dozen attributes such as Name which returns a string containing a human readable description of the CPU or MaxClockSpeed which returns maximum clock speed in Hz as an unsigned 32 bit integer.

Once you initialize your searcher object with an appropriate query, you will need to retrieve the results. Let me show you how to do this below:

ManagementObjectSearcher searcher = 
   new ManagementObjectSearcher("SELECT 
                                   maxclockspeed, 
                                   datawidth, 
                                   name, 
                                   manufacturer 
                                FROM 
                                   Win32_Processor");
 
ManagementObjectCollection objCol = searcher.Get();

The Get method of our searcher object rerurns a ManagementObjectCollection instance populated with our results. In theory all the WMI queries can return multiple “data rows” (for example, if you have multiple CPU’s you will get a ManagementObject associated with each of them), and so the answers get bundled into a collection. In practice however we usually just get a single answer so the whole collection thing is a bit unnecessary – and unwieldy to work with. The least verbose method of extracting our data I can think of is to plug it into a foreach loop like this:

foreach (ManagementObject mgtObject in objCol)
{
     Console.Write(mgtObject["maxclockspeed"].ToString()+ Environment.NewLine);
     Console.Write(mgtObject["datawidth"].ToString()+ Environment.NewLine);
     Console.Write(mgtObject["name"].ToString()+ Environment.NewLine);
     Console.Write(mgtObject["manufacturer"].ToString() + Environment.NewLine);              
}

Since 90% of the time we only expect to see a single object inside the collection this is fairly quick, single iteration loop. You can actually test whether or not your collection has more than a single item by inspecting it’s Count attribute.

Word of warning though – WMI is a bit slow, or so I’ve been told. Now, the slowness is not really noticeable – my prototype app for example was making around 10 WMI queries at startup without noticeable delay. But it is arguably the slower ways to extract this type of information. I have seen many examples of much more optimized code on StackOverflow but frankly I didn’t really. Premature optimization is often a one way ticket to maintenance hell. WMI queries as described above have been fast enough for me, and I don’t really feel like looking for alternatives at the moment – especially since all the data I want can be obtained using the same exact pattern.

This entry was posted in programming. Bookmark the permalink.



6 Responses to Collecting Hardware Information using C# and WMI

  1. ths GERMANY Mozilla Firefox Windows Terminalist says:

    there is software on sourceforge.net to solve your exact problem: a WMI inventory scanner which can post its results via http/https.
    I still use the predecessor winventory, while the development continues under the new name openIT.
    It is VBS code, not C#, but basically it does the same: it collects lots of information and posts it.
    The early version winventory creates SQL, not http, which suits me better, while the latter version makes more sense in a distributed environment where you don’t trust foreign SQL ;)

    Reply  |  Quote
  2. Mart SINGAPORE Mozilla Firefox Windows Terminalist says:

    WMI has its own console it you want to poke around using just the Windows command line. Just hit “wmic”.

    I discovered this when I was researching how to automagically uninstall Windows applications silently using a batch file. It’s pretty cool.

    Reply  |  Quote
  3. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ ths:

    Cool, I check out that app. Nevertheless I sort of wanted to write my own – you know, for shits and giggles. :)

    @ Mart:

    I did not know that. This will probably be useful at some point. Thanks. Still, I’m trying to roll that into an app so that I can get that info without making users deal with command line.

    Reply  |  Quote
  4. Jay SINGAPORE Google Chrome Mac OS says:

    C# requires the .NET environment which I’m fairly certain XP do not come with out of the box.

    Getting the average luser to install the runtime from Windows Update might just be even worse IMO…

    Reply  |  Quote
  5. Abhishek INDIA Internet Explorer Windows says:

    Thanks a lot. This was really helpful :)

    Reply  |  Quote
  6. Zahra Internet Explorer Windows says:

    thanks alot.how can I print these information?(hardware information)

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>