Finding all WMI class names within a WMI namespace with .NET C#

In this post we saw an example of using WMI objects such as ConnectionOptions, ObjectQuery and ManagementObjectSearcher to enumerate all local drives on a computer. Recall the SQL-like query we used:

ObjectQuery objectQuery = new ObjectQuery("SELECT Size, Name FROM Win32_LogicalDisk where DriveType=3");

We’ll now see a technique to list all WMI classes within a WMI namespace. First we get hold of the WMI namespaces:

private static List<String> GetWmiNamespaces(string root)
{
	List<String> namespaces = new List<string>();
	try
	{
		ManagementClass nsClass = new ManagementClass(new ManagementScope(root), new ManagementPath("__namespace"), null);
		foreach (ManagementObject ns in nsClass.GetInstances())
		{
			string namespaceName = root + "\\" + ns["Name"].ToString();
			namespaces.Add(namespaceName);
			namespaces.AddRange(GetWmiNamespaces(namespaceName));
		}
	}
	catch (ManagementException me)
	{
		Console.WriteLine(me.Message);
	}

	return namespaces.OrderBy(s => s).ToList();
}

We call this method as follows to list all WMI namespaces on the local computer:

List<String> namespaces = GetWmiNamespaces("root");

The following method will retrieve all classes from a WMI namespace using the ManagementObjectSearcher object and a query:

private static List<String> GetClassNamesWithinWmiNamespace(string wmiNamespaceName)
{
	List<String> classes = new List<string>();
	ManagementObjectSearcher searcher = new ManagementObjectSearcher
				(new ManagementScope(wmiNamespaceName),
				new WqlObjectQuery("SELECT * FROM meta_class"));
	List<string> classNames = new List<string>();
	ManagementObjectCollection objectCollection = searcher.Get();
	foreach (ManagementClass wmiClass in objectCollection)
	{
		string stringified = wmiClass.ToString();
		string[] parts = stringified.Split(new char[] { ':' });
		classes.Add(parts[1]);
	}
	return classes.OrderBy(s => s).ToList();
}

The ManagementClass ToString method attaches the class name to the namespace with a colon hence the Split method.

You can then call this method for each namespace name:

foreach (String namespaceName in namespaces)
{
	List<String> classNames = GetClassNamesWithinWmiNamespace(namespaceName);
}

Listing all class names within all namespaces can take a lot of time though.

You can view all posts related to Diagnostics here.

Finding all local drives using WMI in C# .NET

WMI – Windows Management Instrumentation – provides a set of tools to monitor the system resources, such as devices and applications. WMI is represented by the System.Management library that you set a reference to in a .NET project.

We’ll quickly look at how to enumerate all local drives on a computer in your network. You might need to run Visual Studio as an administrator:

ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Username = "andras.nemes";
connectionOptions.Password = "p@ssw0rd";
			
ManagementPath managementPath = new ManagementPath();
managementPath.Path = "\\\\machinename\\root\\cimv2";

ManagementScope managementScope = new ManagementScope(managementPath, connectionOptions);

ObjectQuery objectQuery = new ObjectQuery("SELECT Size, Name FROM Win32_LogicalDisk where DriveType=3");

ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher(managementScope, objectQuery);
ManagementObjectCollection objectCollection = objectSearcher.Get();

foreach (ManagementObject managementObject in objectCollection)
{
	Console.WriteLine("Resource name: {0}", managementObject["Name"]);
	Console.WriteLine("Resource size: {0}", managementObject["Size"]);
}

First we set up the user information to access the other computer with the ConnectionOptions object. Then we declare the path to the WMI namespace where the resource exists. In this case it’s “root\\cimv2”.

Further down you’ll see how to list all WMI namespaces.

Next we build a ManagementScope object using the management path and connection options inputs. Then comes the interesting part: an SQL-like syntax to query the resource, in this case Win32_LogicalDisk. This page lists all selectable properties of Win32_LogicalDisk including the values for DriveType.

ManagementObjectSearcher is the vehicle to run the query on the declared scope. The Get() method of ManagementObjectSearcher enumerates all management objects that the query returned. The loop prints the properties that we extracted using the query.

Here’s how you can print the WMI namespaces of a root:

private static List<String> GetWmiNamespaces(string root)
{
	List<String> namespaces = new List<string>();
	try
	{
		ManagementClass nsClass = new ManagementClass(new ManagementScope(root), new ManagementPath("__namespace"), null);
		foreach (ManagementObject ns in nsClass.GetInstances())
		{
			string namespaceName = root + "\\" + ns["Name"].ToString();
			namespaces.Add(namespaceName);
			namespaces.AddRange(GetWmiNamespaces(namespaceName));
		}
	}
	catch (ManagementException me)
	{
		Console.WriteLine(me.Message);
	}

	return namespaces;
}

If you’d like to enumerate the WMI namespaces on your local PC then you can call this function like…

List<String> namespaces = GetWmiNamespaces("root");

You can view all posts related to Diagnostics here.

Creating a new performance counter on Windows with C# .NET

In this post we saw how to list all performance counter categories and the performance counters within each category available on Windows. The last time I checked there were a little more than 27500 counters and 148 categories available on my local PC. That’s quite a lot and will probably cover most diagnostic needs where performance counters are involved in a bottleneck investigation.

However, at times you might want to create your own performance counter. The System.Diagnostics library provides the necessary objects. Here’s how you can create a new performance counter category and a counter within that category:

string categoryName = "Football";
			
if (!PerformanceCounterCategory.Exists(categoryName))
{
	string firstCounterName = "Goals scored";
	string firstCounterHelp = "Goals scored live update";
	string categoryHelp = "Football related real time statistics";
				
	PerformanceCounterCategory customCategory = new PerformanceCounterCategory(categoryName);
	PerformanceCounterCategory.Create(categoryName, categoryHelp, PerformanceCounterCategoryType.SingleInstance, firstCounterName, firstCounterHelp);
}

You’ll need to run Visual Studio as an administrator to create the category and counter.

Don’t forget to check if the category exists otherwise you’ll get an exception. The new category and counter turns up in the Performance Monitor window:

Custom category and counter creation result

A slightly different way of creating a new counter is through the CounterCreationData object:

PerformanceCounterCategory customCategory = new PerformanceCounterCategory(categoryName);
CounterCreationData counterCreationData = new CounterCreationData(firstCounterName, firstCounterHelp, PerformanceCounterType.NumberOfItems32);
CounterCreationDataCollection collection = new CounterCreationDataCollection();
collection.Add(counterCreationData);
PerformanceCounterCategory.Create(categoryName, categoryHelp, collection);

If you add that counter to the Performance Monitor then there will be no data yet of course.

At first the counter will be set as read-only but it can be changed easily. The PerformanceCounter object has the Increment() and IncrementBy() methods. Increment() adds 1 to the counter value and IncrementBy() increments the value by the specified amount. You can pass a negative value to decrement the current counter value.

Let’s see these methods in action:

string categoryName = "Football";
string counterName = "Goals scored";
PerformanceCounter footballScoreCounter = new PerformanceCounter(categoryName, counterName);
footballScoreCounter.ReadOnly = false;
while (true)
{
	footballScoreCounter.Increment();
	Thread.Sleep(1000);
	Random random = new Random();
	int goals = random.Next(-5, 6);
	footballScoreCounter.IncrementBy(goals);
	Thread.Sleep(1000);
}

Performance Monitor starts putting the values in the graph:

Goals scored performance counter in Performance Monitor

You can view all posts related to Diagnostics here.

Reading the value of a performance counter on Windows with C# .NET

In this post we saw how to list all performance categories and the performance counters within each category. It’s equally straightforward to read the value of a performance counter. You’ll need at least the category and the name of the performance counter. If the counter is available in multiple instances then you’ll need to specify the instance name as well.

The following code will read the CPU usage and memory usage counters:

private static void ReadValuesOfPerformanceCounters()
{
	PerformanceCounter processorTimeCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
	PerformanceCounter memoryUsage = new PerformanceCounter("Memory", "Available MBytes");			
	Console.WriteLine("CPU usage counter: ");
	Console.WriteLine("Category: {0}", processorTimeCounter.CategoryName);
	Console.WriteLine("Instance: {0}", processorTimeCounter.InstanceName);
	Console.WriteLine("Counter name: {0}", processorTimeCounter.CounterName);
	Console.WriteLine("Help text: {0}", processorTimeCounter.CounterHelp);
	Console.WriteLine("------------------------------");
	Console.WriteLine("Memory usage counter: ");
	Console.WriteLine("Category: {0}", memoryUsage.CategoryName);
	Console.WriteLine("Counter name: {0}", memoryUsage.CounterName);
	Console.WriteLine("Help text: {0}", memoryUsage.CounterHelp);
	Console.WriteLine("------------------------------");
	while (true)
	{
		Console.WriteLine("CPU value: {0}", processorTimeCounter.NextValue());
		Console.WriteLine("Memory value: {0}", memoryUsage.NextValue());
		Thread.Sleep(2000);
        }
}

Here’s an excerpt of the output:

Reading values of performance counters

You can view all posts related to Diagnostics here.

Listing all performance counters on Windows with C# .NET

Performance counters in Windows can help you with finding bottlenecks in your application. There’s a long range of built-in performance counters in Windows which you can view in the Performance Monitor window:

Performance Monitor window

Right-click anywhere on the larger screen to the right and select Add Counters to add your counters to the graph. The Add Counters window will show the categories first. You can then open a category and select one or more specific counters within that category. The graph will show the real-time data immediately:

Performance Monitor with added pre-built categories

The System.Diagnostics namespace has a couple of objects that let you find the available performance categories and counters on the local machine or on another machine. Each performance category has a name, a help text and a type. It’s straightforward to find the categories available on a machine:

PerformanceCounterCategory[] categories = PerformanceCounterCategory.GetCategories();
foreach (PerformanceCounterCategory category in categories)
{
	Console.WriteLine("Category name: {0}", category.CategoryName);
	Console.WriteLine("Category type: {0}", category.CategoryType);
	Console.WriteLine("Category help: {0}", category.CategoryHelp);
}

GetCategories() has an overload where you can specify a computer name if you’d like to view the counters on another computer within the network.

At the time of writing this post I had 161 categories on my machine. Example:

Name: WMI Objects
Help: Number of WMI High Performance provider returned by WMI Adapter
Type: SingleInstance

Once you got hold of a category you can easily list the counters within it. The below code prints the category name, type and help text along with any instance names. If there are separate instances within the category then we need to called the GetCounters method with the instance name if it exists otherwise we’ll get an exception saying that there are multiple instances.

PerformanceCounterCategory[] categories = PerformanceCounterCategory.GetCategories();
foreach (PerformanceCounterCategory category in categories)
{
	Console.WriteLine("Category name: {0}", category.CategoryName);
	Console.WriteLine("Category type: {0}", category.CategoryType);
	Console.WriteLine("Category help: {0}", category.CategoryHelp);
	string[] instances = category.GetInstanceNames();
	if (instances.Any())
	{
		foreach (string instance in instances)
		{
			if (category.InstanceExists(instance))
			{
				PerformanceCounter[] countersOfCategory = category.GetCounters(instance);
				foreach (PerformanceCounter pc in countersOfCategory)
				{
					Console.WriteLine("Category: {0}, instance: {1}, counter: {2}", pc.CategoryName, instance, pc.CounterName);
				}
			}
		}
	}
	else
	{
		PerformanceCounter[] countersOfCategory = category.GetCounters();
		foreach (PerformanceCounter pc in countersOfCategory)
		{
                	Console.WriteLine("Category: {0}, counter: {1}", pc.CategoryName, pc.CounterName);
		}
	}	
}

Each counter in turn has a name, a help text and a type. E.g. here’s a counter with the “Active Server Pages” category:

Name: Requests Failed Total
Help: The total number of requests failed due to errors, authorization failure, and rejections.
Type: NumberOfItems32

You can view all posts related to Diagnostics here.

4 ways to enumerate processes on Windows with C# .NET

A Process object in the System.Diagnostics namespace refers to an operating-system process. This object is the entry point into enumerating the processes currently running on the OS.

This is how you can find the currently active process:

Process current = Process.GetCurrentProcess();
Console.WriteLine(current);

…which will yield the name of the process running this short test code.

It’s probably very rare that you’ll use the above method for anything as it’s not too useful.

You can locate a Process by its ID as follows:

try
{
	Process processById = Process.GetProcessById(7436);
	Console.WriteLine(processById);
}
catch (ArgumentException ae)
{
	Console.WriteLine(ae.Message);
}

I opened the Windows Task Manager and took a process ID from the list. Process ID 7436 at the time of writing this post belonged to Chrome, hence the Console printed “chrome”. The GetProcessById throws an argument exception if there’s no Process with that id: “Process with an Id of 1 is not running”.

There’s an overload of GetProcessById where you can specify the name of the machine in your network where to look for the process.

You can also look for processes by their name:

Process[] chromes = Process.GetProcessesByName("chrome");
foreach (Process process in chromes)
{
	Console.WriteLine("Process name: {0}, ID: {1}", process.ProcessName, process.Id);				
}

I had 4 “chrome” processes running when writing this post with the following ids: 7544, 7436, 6620, 7996. GetProcessesByName also has a machine name overload to check the processes on another machine.

Finally you can enumerate all processes on a machine by the GetProcesses method. The no-args method will enumerate the processes on the local computer. Otherwise provide the computer name in the overloaded version.

try
{
	Process[] allProcessesOnLocalMachine = Process.GetProcesses();
	foreach (Process process in allProcessesOnLocalMachine)
	{
		Console.WriteLine("Process name: {0}, ID: {1}", process.ProcessName, process.Id);
	}
}
catch (Exception ex)
{
	Console.WriteLine(ex.Message);
}

You can view all posts related to Diagnostics here.

Reading and clearing a Windows Event Log with C# .NET

In this post we saw how to create a custom event log and here how to the write to the event log. We’ll briefly look at how to read the entries from an event log and how to clear them.

First let’s create an event log and put some messages to it:

string source = "DemoTestApplication";
string log = "DemoEventLog";
EventLog demoLog = new EventLog(log);
demoLog.Source = source;
demoLog.WriteEntry("First message", EventLogEntryType.Information, 101);
demoLog.WriteEntry("Hello!!", EventLogEntryType.Error, 980);
demoLog.WriteEntry("Bye", EventLogEntryType.Warning);
demoLog.WriteEntry("Long live Mondays", EventLogEntryType.Information, 200);
demoLog.WriteEntry("This is a demo", EventLogEntryType.Information, 250);

This is what it looks like in the Event Viewer:

Filling test event log

Reading from a log is also straightforward:

string log = "DemoEventLog";
EventLog demoLog = new EventLog(log);
EventLogEntryCollection entries = demoLog.Entries;
foreach (EventLogEntry entry in entries)
{
	Console.WriteLine("Level: {0}", entry.EntryType);
	Console.WriteLine("Event id: {0}", entry.InstanceId);
	Console.WriteLine("Message: {0}", entry.Message);
	Console.WriteLine("Source: {0}", entry.Source);
	Console.WriteLine("Date: {0}", entry.TimeGenerated);
	Console.WriteLine("--------------------------------");
}

…which gives the following output:

Reading from event log

Clearing a log is very easy:

demoLog.Clear();

…and the log entries are gone:

Cleared demo event log

You can view all posts related to Diagnostics here.

Writing to the Windows Event Log with C# .NET

In this post we saw how to create and delete event logs. We’ve also seen a couple examples of writing to the event log. Here come some more examples.

Say you want to send a warning message to the System log:

string source = "DemoSourceWithinApplicationLogSystem";
EventLog systemEventLog = new EventLog("System");
if (!EventLog.SourceExists(source))
{
	EventLog.CreateEventSource(source, "System");
}
systemEventLog.Source = source;
systemEventLog.WriteEntry("This is warning from the demo app to the System log", EventLogEntryType.Warning, 150);

As there is no such source yet in any event log it must be registered first. In the CreateEventSource method you can specify which log the source will belong to. The WriteEntry method has 5 overloads, of which you can see one above with a message, an entry type and an event ID. The event ID is an arbitrary integer that you can specify. It is an optional parameter which is set to 0 by default. The warning occurs like this in the event viewer:

Writing a warning to the System log

Say you’d like to send a warning message to the Application log instead with no event ID:

string source = "DemoSourceWithinApplicationLog";
string log = "Application";
if (!EventLog.SourceExists(source))
{
	EventLog.CreateEventSource(source, log);
}
EventLog.WriteEntry(source, "This is a warning from the demo log", 
	EventLogEntryType.Warning);

Here it is:

Writing a warning to the application log

If you know that the source has already been registered then you can send a message in a shorter format:

string source = "DemoSourceWithinApplicationLog"
EventLog.WriteEntry(source, "This is an error messsage from the demo log", EventLogEntryType.Error, 100);

Error message in application log

You can view all posts related to Diagnostics here.

Creating and deleting event logs with C# .NET

The Windows event viewer contains a lot of useful information on what happens on the system:

Windows event viewer

Windows will by default write a lot of information here at differing levels: information, warning, failure, success and error. You can also write to the event log, create new logs and delete them if the code has the EventLogPermission permission. However, bear in mind that it’s quite resource intensive to write to the event logs. So don’t use it for general logging purposes to record what’s happening in your application. Use it to record major but infrequent events like shutdown, severe failure, start-up or any out-of-the-ordinary cases.

There are some predefined Windows logs in the event log: Application, Security and System are the usual examples. However, you can create your own custom log if you wish. The key is the EventLog object located in the System.Diagnostics namespace:

string source = "DemoTestApplication";
string log = "DemoEventLog";
EventLog demoLog = new EventLog(log);
demoLog.Source = source;
demoLog.WriteEntry("This is the first message to the log", EventLogEntryType.Information);

The new log type was saved under the Applications and Services log category:

First custom log

You’ll probably have to restart the Event Viewer to find the new log type.

You can write to one of the existing Windows logs as well by specifying the name of the log. So we can create a log source within the Application log as follows:

string source = "DemoSourceWithinApplicationLog";
string log = "Application";
if (!EventLog.SourceExists(source))
{
	EventLog.CreateEventSource(source, log);
}
EventLog.WriteEntry(source, "First message from the demo log within Application", EventLogEntryType.Information);

The log entry is visible within the Application log:

Log entry in the Application log

It’s very easy to delete your custom log:

string log = "DemoEventLog";
EventLog.Delete(log);

The log will be deleted. Again, you’ll have to restart the event viewer to see that changes.

You can view all posts related to Diagnostics here.

Create code at runtime with Reflection in .NET C#: Properties

In the previous post of this short series we saw how to add a field to our custom type using Reflection. In this finishing post we’ll look at properties and how to save our dynamic assembly.

Properties can be created in two ways. First we can use the PropertyBuilder class:

PropertyBuilder priceProperty = simpleType.DefineProperty("Price", PropertyAttributes.None, typeof(int), Type.EmptyTypes);

This will create a standard property called Price which returns an integer and has no input parameters. You’d write it like this in Visual Studio:

public int Price { get; set; }

For some reason the PropertyAttributes enumeration doesn’t let you refine the characteristics of the property as much as e.g. MethodAttributes or FieldAttributes do. In case you’d like to define the visibility of the property you need to turn to the MethodBuilder object and use it in a special way. The methods will perform the get/set methods separately. The following code example creates a get and set method:

MethodAttributes pricePropertyAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder getPriceBuilder = simpleType.DefineMethod("get_Price", pricePropertyAttributes, typeof(int), Type.EmptyTypes);
MethodBuilder setPriceBuilder = simpleType.DefineMethod("set_Price", pricePropertyAttributes, null, new Type[] { typeof(int) });
priceProperty.SetGetMethod(getPriceBuilder);
priceProperty.SetSetMethod(setPriceBuilder);

The SpecialName and HideBySig values indicate that these methods are special and will not be part of the public interface. The name of the get/set methods must follow a convention: “get_XXX” and “set_XXX” where ‘XXX’ is the name of the property like get_Price.

The special methods can be associated with the property using the SetGetMethod and SetSetMethod methods of the PropertyBuilder object.

Once you’re done with your custom assembly then it can be persisted on disk using the Save method of AssemblyBuilder:

assemblyBuilder.Save(assemblyFileName);

View all posts on Reflection here.

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

ARCHIVED: Bite-size insight on Cyber Security for the not too technical.