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:
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.


/dev/random