Using C# to Find Out What Your Computer is Made of

What do you know about the PC your currently sitting in front of, reading this on?

You probably know who built it, how many hard drives are in it, what it's general speed is, the usual stuff. If you're a bit more technical, you might know what type of CPU you have, or how many USB ports, but in most cases that would be about it.

It might surprise you, however, that there's a bewildering amount more to be found out than just those basic details.

The .NET framework has classes and namespaces available that can find out some very, very surprising things about your PC. From information such as which patches and hotfixes have been applied through to the manufacturer of your PC's BIOS, the amount of information you can find out should you want to is staggering.

In this post, we'll take a high level view of some of what's available, and make a small command line tool that can output various details both to the console and in a text file that you then can save.

First, the Basics

There are two main places to find system information from on any Windows-based system. The first is System.Environment; the second is System.Managment.

Of the two. system.environment is the easier to use; it's a simple static collection of details that you can read any time you like. system.environment contains information about your operating system version, where your operating system is installed, number of CPUs, number of hard disk drives, and PC name.

system.managment, on the other hand, although reasonably easy to use, takes a little bit of getting used to, and generally requires you to do a lot of data processing to get at even just a handful of details. Where system.managment shines, however, is in the volume of information available.

First, however, let's take a look system.environment.

Fire up Visual Studio, and create yourself a simple command line program.

Made1
Figure 1: Creating a command line program

Normally, if I'm not using them, I remove the Args argument from main, but I have an idea for that, in this post, so I'm leaving it present for the moment.

Add the following single line of code to your Main program section:

Console.WriteLine(Environment.OSVersion);

While you're typing, you might see your IntelliSense pop open, showing you the different static properties available in he environment class:

Made2
Figure 2: IntelliSense is trying to help

If you run your command line program with just that single line in, you should see that it displays your current Windows version:

Made3
Figure 3: Displaying your Windows version

Let's build out our code a little bit, and get our application to display more of our info.

static void Main(string[] args)
{
   Console.WriteLine("Windows version: {0}",
      Environment.OSVersion);
   Console.WriteLine("64 Bit operating system? : {0}",
      Environment.Is64BitOperatingSystem ? "Yes" : "No");
   Console.WriteLine("PC Name : {0}",
      Environment.MachineName);
   Console.WriteLine("Number of CPUS : {0}",
      Environment.ProcessorCount);
   Console.WriteLine("Windows folder : {0}",
      Environment.SystemDirectory);
   Console.WriteLine("Logical Drives Available : {0}",
         String.Join(", ", Environment.GetLogicalDrives())
      .TrimEnd(',', ' ')
      .Replace("\\", String.Empty));
}

If you now run this again, you'll see there's far more in there than there was before:

Made4
Figure 4: There's much more information now

Let's add some other code to our program: first, a class to hold our information, called "BasicInfo.cs", as follows:

using System;
using System.Text;

namespace sysinfo_blogpost
{
   public class BasicInfo
   {
      public string OsVersion { get; set; }
      public bool Os64 { get; set; }
      public string PcName { get; set; }
      public int NumberOfCpus { get; set; }
      public string WindowsFolder { get; set; }
      public string[] LogicalDrives { get; set; }

      public override string ToString()
      {
         StringBuilder output = new StringBuilder();
         output.AppendFormat("Windows version: {0}\n", OsVersion);
         output.AppendFormat("64 Bit operating system? : {0}\n",
            Os64 ? "Yes" : "No");
         output.AppendFormat("PC Name : {0}\n", PcName);
         output.AppendFormat("Number of CPUS : {0}\n", NumberOfCpus);
         output.AppendFormat("Windows folder : {0}\n", WindowsFolder);
         output.AppendFormat("Logical Drives Available : {0}\n",
               String.Join(", ", LogicalDrives)
            .Replace("\\", String.Empty));
         return output.ToString();
      }
   }
}

Remember to change the namespace to fit your own project. Note also that we've added an overridden "ToString" method to format our object as a string. You'll see why in just a moment.

With this class, let's now fill it in with the values we want, rather than displaying them:

class Program
{
   static void Main(string[] args)
   {
      BasicInfo myInfo = new BasicInfo
      {
         OsVersion = Environment.OSVersion.ToString(),
         Os64 = Environment.Is64BitOperatingSystem,
         PcName = Environment.MachineName,
         NumberOfCpus = Environment.ProcessorCount,
         WindowsFolder = Environment.SystemDirectory,
         LogicalDrives = Environment.GetLogicalDrives()
      };

      Console.WriteLine(myInfo);
   }
}

This code should give us the display we had previously.

Now, right-click References, open your NuGet package manager, and install "Newtonsoft.Json" into your project:

Made5
Figure 5: Installing "Newtonsoft.Json" into your project

Then change this line:

Console.WriteLine(myInfo);

in your program, to this:

string json = JsonConvert.SerializeObject(myInfo,
   Formatting.Indented);
Console.WriteLine(json);

and if everything has worked, you should get the following:

Made6
Figure 6: Seeing more information about your computer

Which, as you can see, is now formatted in an output suitable to be sent to a web page as Json Data ready for display.

One more final tweak to our program results in this code:

using System;
using System.Linq;
using Newtonsoft.Json;

namespace sysinfo_blogpost
{
   class Program
   {
      static void Main(string[] args)
      {
         BasicInfo myInfo = new BasicInfo
         {
            OsVersion = Environment.OSVersion.ToString(),
            Os64 = Environment.Is64BitOperatingSystem,
            PcName = Environment.MachineName,
            NumberOfCpus = Environment.ProcessorCount,
            WindowsFolder = Environment.SystemDirectory,
            LogicalDrives = Environment.GetLogicalDrives()
         };

         if(args.Contains("-h"))
         {
            Console.WriteLine("Sysinfo Utility:");
            Console.WriteLine("  -h : This help.");
            Console.WriteLine("  -j : Output results as JSON");
            return;
         }

         if(args.Contains("-j"))
         {
            string json = JsonConvert.SerializeObject(myInfo,
               Formatting.Indented);
            Console.WriteLine(json);
         }
         else
         {
            Console.WriteLine(myInfo);
         }
      }
   }
}

If you now run this, you should get your first version of the output, but if you now run the program and specify "-j" after it, you'll get the Json output.

Why is this useful? Well, you now have a small program, that can be used to create a Json file with system info in a web site. Simply by running:

sysinfo.exe -j > info.json

in a folder that your web server can see. You're now able to generate a Json file that you can then use JavaScript or some other web technology to load and display in a web page.

Now you could, in theory, simply just make the appropriate calls to read the data you want, directly in your web applications code using regular C#, and this would work great for something as simple (and more importantly as quick) as System.Environment, but once you start playing with System.Managment, you'll quickly see that in some cases it can easily take 5, 10, 15 seconds or longer to get some of the information back you request.

Now, doing this in real time in a web application is a big no, no because it'll severely delay your page response time. A better approach is, instead, to have a small command line application that is run on a regular schedule, say once every 12 hours, and produces this small Json file for your application to use.

A Quick Look at System.Managment

There's simply not enough space in these posts to cover everything that the system.managment namespace can find out for you. Accessing it is not hard, but it's quite strange if you've not seen the way it's done before.

Before you start, however, you need to add a reference to "System.Managment" to your program by using an add reference from your References right-click menu.

Properties returned from the system.managment namespace are not returned in a nice, easy to remember class, with easy to remember property names.

Instead, there are 430 property access strings that you use to request the information subset that your interested in. For example, if you want to know what your CPU can do, you need to ask for information in the

Win32_Processor

information class.

You access the data by creating a ManagmentClass object as follows:

ManagementClass myManagementClass =
   new ManagementClass("Win32_Processor");

and then a property accessor for that class:

ManagementObjectCollection myManagementCollection =
   myManagementClass.GetInstances();
PropertyDataCollection myProperties =
   myManagementClass.Properties;

Which you can then loop through, using two nested for-each loops:

foreach (ManagementObject obj in myManagemenCollection)
{
   foreach (PropertyData property in myProperties)
   {
      // Access your properties here using 'property'
   }
}

The 'property' variable exposed in the inner loop will hold things like the property key name and an accessor for the value, and value type.

You could at this point use some reflection, or a mapper of some kind, to then hydrate your own concrete base classes. For purposes of demonstration, however, I'm just going to use a dictionary.

Putting all of this together, we can use the following code to get a dictionary of our CPU information:

using System;
using System.Collections.Generic;
using System.Management;

namespace sysinfo_blogpost
{
   class Program
   {
      static void Main(string[] args)
      {
         ManagementClass myManagementClass = new
            ManagementClass("Win32_Processor");
         ManagementObjectCollection myManagementCollection =
            myManagementClass.GetInstances();
         PropertyDataCollection myProperties =
            myManagementClass.Properties;
         Dictionary<string, object> myPropertyResults =
            new Dictionary<string, object>();

         foreach (var obj in myManagementCollection)
         {
            foreach (var myProperty in myProperties)
            {
               myPropertyResults.Add(myProperty.Name,
                  obj.Properties[myProperty.Name].Value);
            }
         }

         foreach (var myPropertyResult in myPropertyResults)
         {
            Console.WriteLine("{0}: {1}", myPropertyResult.Key,
               myPropertyResult.Value);
         }
      }

   }
}

Which, when run on my machine, gives me:

Made7
Figure 7: A larger list of your computer's information

I'm not going to repeat a full list of known classes in this post. Instead, you can find them all listed on MSDN right here:

https://msdn.microsoft.com/en-us/library/aa389273(v=vs.85).aspx

I'll leave turning the dictionary into a set of objects up to you.

Got a .NET itch you can't quite scratch? Gimme a shout; you usually can find me lurking around Twitter as @shawty_ds or just leave a comment below.



Related Articles

Comments

  • Cpu temperature wanted...

    Posted by Dino on 07/03/2015 12:55am

    Nice post, even if I already knew these classes. Just one question: I discovered all these classes trying to find out how to detect cpu temperature and related fan speed, without success. May be you can give me a hint? I hope so. Regards Dino

    • RE: Cpu temperature wanted

      Posted by Peter Shaw on 07/06/2015 02:55pm

      Hi Dino, If you look on the MSDN page that I provided a link to, all the classes you want are in the first section of that page under the heading "Cooling Classes" Be fore warned though, NOT all motherboards support the official Microsoft interfaces, and not all motherboard drivers support the code needed for these calls to work. In many cases (Especially on older boards) you may never be able to read the info you want, it however shouldn't be a huge problem on more modern hardware. Shawty

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date