Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

A PC Audit Application in C#

4.29/5 (13 votes)
27 Feb 20073 min read 3   6.9K  
A basic PC audit developed in C#.

Introduction

One of the many challenges I run up against in my day to day work is getting an accurate audit of computers on my network. I've looked at buying several different packages, the last one coming in at $4,500 to keep an eye on 250 systems, but never wanted to drop the money for it. Then, I got thinking about how easy it would be to write my own audit program that would take care of it without having to spend the money.

Using the code

I started looking, and found several ways to retrieve system information I was looking for, by using the System.Environment class, WMI data, and the Windows Registry. I was able to get basic information, such as computer name, current user, and the OS version through the System.Environment class. One issue I noticed was that I was only able to return the current user logged in. So the last user to sign in to the computer would show up as the user for that system. Instead, I decided to track the number of times a user has logged into a computer. This way, I can populate the user field with who's signed in to that computer the most.

C#
computerName = Environment.MachineName;
userName = Environment.UserName;
osVersion = Environment.OSVersion.ToString();

This was good and all, but I also wanted to pull information on software installed, memory, local disk information, and other hardware details. WMI provided the means to pull all of the hardware information. I downloaded a WMI browser, and quickly found all the bits I was looking for. WMI is searched by using the ManagementObjectSearcher and ManagementObjectCollection objects.

C#
//Computer model and memory information
ManagementObjectSearcher query1 = 
  new ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem");
ManagementObjectCollection queryCollection1 = query1.Get();

foreach (ManagementObject mo in queryCollection1)
{
    model = mo["model"].ToString();
    memory = Convert.ToInt32(mo["totalphysicalmemory"]);
}

//Processor type and speed
query1 = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");
queryCollection1 = query1.Get();

foreach (ManagementObject mo in queryCollection1)
{
    processor = mo["Name"].ToString();
}

//disk drives, total capacity and free space
ManagementObjectSearcher query1 = 
  new ManagementObjectSearcher("SELECT * FROM Win32_LogicalDisk");
ManagementObjectCollection queryCollection1 = query1.Get();

foreach (ManagementObject mo in queryCollection1)
{
    sSql = "INSERT INTO diskDrives (deviceID, description, " 
        + "freeSpace, size, computerId) values ('"
        + mo["DeviceID"] + "', '"
        + mo["Description"] + "', '"
        + mo["Freespace"] + "', '"
        + mo["Size"] + "', "
        + computerID + ")";

    oComm = new SqlCommand(sSql, oConn);
    oComm.ExecuteNonQuery();
}

I also found that in WMI, I was able to get more detailed information about the installed memory, such as the number of memory chips installed and the size of those chips.

C#
ManagementObjectSearcher query1 = 
  new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory");
ManagementObjectCollection queryCollection1 = query1.Get();

foreach (ManagementObject mo in queryCollection1)
{
    sSql = "INSERT INTO memory (capacity, location, computerId) values ("
        + mo["Capacity"] + ", '"
        + mo["DeviceLocator"] + "', "
        + computerID + ")";

    oComm = new SqlCommand(sSql, oConn);
    oComm.ExecuteNonQuery();
}

The last piece I wanted to find was applications that were currently installed. Since registered Windows applications are required to put an entry in the uninstall registry key, that was the cleanest way to get the required information. Windows also keeps an entry for most of the patches it installs, which was one thing I was not interested in, since I have a separate patch management server to take care of that. So, I decided to filter out any entries that begin with KB (the usual designation of a Microsoft patch).

C#
RegistryKey regKey, regSubKey;

regKey = Registry.LocalMachine;
regKey = regKey.OpenSubKey("SOFTWARE").OpenSubKey("Microsoft").
                OpenSubKey("Windows").OpenSubKey("CurrentVersion").
                OpenSubKey("Uninstall");

string[] foo = regKey.GetSubKeyNames();
for (int i = 0; i < foo.Length; i++)
{
    string bar = foo[i].ToString();
    if (String.Compare(bar, 0, "KB", 0, 2) != 0)
    {
        regSubKey = regKey.OpenSubKey(foo[i]);
        if (regSubKey.GetValue("DisplayName") != null)
        {                            
            string software = regSubKey.GetValue("DisplayName").ToString();
            software = software.Replace("'", "''");
            sSql = "INSERT INTO software (computerId, " + 
                   "softwareName) values (" + id + ", '" + software + "')";
            oComm = new SqlCommand(sSql, oConn);
            oComm.ExecuteNonQuery();
        }
    }
}

That took care of all the code work, the only other part was getting it out to the masses. Because of .NET security features, the application is required to run off a local drive. So, a simple bat file in the logon script mounts a network share where the executable is found, copies it to the local temp directory, executes the audit, then removes itself and the file share.

audit.bat

net use z: \\networkShare
z:
cd audit
copy audit.exe %temp%
c:
net use z: /delete
cd %temp%
audit.exe
del audit.exe

The last part that I needed was a way to report on the data collected. A simple web application with a GridView displayed the data.

Screenshot - display.jpg

Points of Interest

Being unfamiliar with WMI's capabilities before diving in to this, I was quite surprised to find just how much detail about a system is stored in there. By using a simple WMI browser, I was able to quickly find everything I was looking for, and quite a few things that were quite useful.

History

  • 2/27/07 - Uploaded code to the web interface.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here