|
|||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionWindows Management Instrumentation (WMI) is a C&C infrastructure that is integrated within Windows. It provides three primary capabilities:
These facilities are a complete instrumentation solution for any Windows application, and multiple system components expose information through the use of WMI providers. This information can be consumed from a multitude of languages and technologies by WMI consumers, using a standard query language (WQL). Managed code support for WMI providers has been extended in .NET 3.5, enabling every capability a native WMI provider can support. This functionality resides in the System.Management and System.Management.Instrumentation assemblies, and is generally referred to as the WMI Provider Extensions for .NET. The primary advantage to using WMI in favor of the multitude of communication technologies that are abound is that WMI is a standardized C&C mechanism which can be consumed by numerous existing C&C frameworks. Another advantage is that most Windows components expose C&C information using WMI, and it is preferable that a single C&C framework is used instead of reinventing a C&C framework for each individual component. This makes a single C&C tool suitable for a variety of configurable and controllable entities. There is a significant number of resources demonstrating what kind of tasks can be accomplished using WMI: WMI Tasks for Scripts and Applications, WMI and .NET in the MSDN Magazine, WMI Code Creator Spotlight ... However, there is no single resource outlining the exact details of creating every kind of provider supported in the WMI Provider Extensions for managed code. This article provides guidance and walkthrough steps for implementing a WMI provider in managed code and consuming the information exposed by that provider from managed code. Hosting ModelWMI providers can be hosted in a separate application, or within the WMI host service. Separately hosted providers are also called decoupled providers. Providers hosted within the WMI host service are also called in-process providers. Decoupled providers expose their information only as long as the application in which they are hosted is running. In-process providers expose their information as long as the WMI infrastructure on the machine is functioning properly. Basic Setup StepsAn assembly that contains a WMI provider must be decorated with the The following code demonstrates setting up an assembly that exposes a WMI provider in the “root\MyApplication” namespace, with a decoupled hosting model: [assembly: WmiConfiguration(@"root\MyApplication",
HostingModel = ManagementHostingModel.Decoupled)]
The following code demonstrates setting up an assembly that exposes a WMI provider in the "root\MyApplication" namespace, with an in-process hosting model requiring the provider to run under the NetworkService account: [assembly: WmiConfiguration(@"root\MyApplication",
HostingModel = ManagementHostingModel.NetworkService)]
To inform the WMI infrastructure that the assembly contains a WMI provider, the assembly must contain an installer class that can be run by the InstallUtil.exe tool. This installer class must derive from the The following code demonstrates the installer class that must be present in the WMI provider's assembly: [RunInstaller(true)]
public class MyApplicationManagementInstaller :
DefaultManagementInstaller { }
With these setup steps in place, all that is left is to implement the actual WMI provider (described in the subsequent sections). Once the assembly is complete, it must be registered using the InstallUtil.exe tool. From a Visual Studio command prompt, the following command registers the assembly with the WMI infrastructure: InstallUtil MyAssembly.dll
To unregister the assembly, the following command can be executed from a Visual Studio command prompt: InstallUtil /u MyAssembly.dll
Read-Only InformationThe most rudimentary kind of WMI provider is a WMI provider that exposes read-only information regarding a configurable entity. The managed model for this kind of WMI provider consists of implementing a class that exposes the information as read-only properties. The class itself must be decorated with the When applying the A multi-instance WMI provider which does not expose at least one property decorated with the A singleton WMI provider which attempts to expose a property decorated with the Finally, the constructor of your class or a static method on your class must be decorated with the The following code demonstrates a singleton WMI class that exposes the number of processors available on the machine as a read-only property: [ManagementEntity(Singleton=true)]
[ManagementQualifier("Description",
Value="Obtain processor information.")]
public class ProcessorInformation
{
[ManagementBind]
public ProcessorInformation()
{
}
[ManagementProbe]
[ManagementQualifier("Descriiption",
Value="The number of processors.")]
public int ProcessorCount
{
get { return Environment.ProcessorCount; }
}
}
To publish the instance to the WMI infrastructure, the hosting process can use the following code: InstrumentationManager.Publish(new ProcessorInformation());
This simple class can now be registered using InstallUtil.exe and then queried from a WMI consumer. Note the use of the The following code demonstrates a multi-instance WMI class that exposes the thread count in each process running on the system as a read-only property. [ManagementEntity]
public class ProcessInformation
{
Process _theProcess;
[ManagementBind]
public ProcessInformation(
[ManagementName("Id")] int id)
{
_theProcess = Process.GetProcessById(id);
}
[ManagementKey]
public int Id
{
get { return _theProcess.Id; }
}
[ManagementProbe]
public int ThreadCount
{
get { return _theProcess.Threads.Count; }
}
}
To publish the process instances to the WMI infrastructure, the hosting process can use the following code: foreach (Process p in Process.GetProcesses())
{
InstrumentationManager.Publish(
new ProcessInformation(p.Id));
}
Changes to object instances made by Consuming the information exposed by the provider developed in the previous section can be performed using the Opening an administrator command prompt and executing the following command will yield a detailed list of wmic /namespace:\\root\MyApplication path ProcessInformation
The WMIC tool supports query syntax for specifying conditions, as well: wmic /namespace:\\root\MyApplication path ProcessInformation where Id=4
Alternatively, the following managed code can output the ManagementObjectSearcher searcher =
new ManagementObjectSearcher(@"root\MyApplication",
"SELECT * FROM ProcessInformation");
foreach (ManagementObject obj in searcher.Get())
Console.WriteLine("Id: " + obj["Id"] +
", ThreadCount: " + obj["ThreadCount"]);
If you’re looking for a strongly-typed accessor, there’s no need to generate it manually. Within Visual Studio’s Server Explorer, expand your server’s node, right click the Management Classes node, and choose Add Classes. Navigate to the root\MyApplication namespace and choose the foreach (ROOT.MYAPPLICATION.ProcessInformation info in
ROOT.MYAPPLICATION.ProcessInformation.GetInstances())
{
Console.WriteLine("Id: " + info.Id +
", ThreadCount: " + info.ThreadCount);
}
Note that the underlying accessor still uses the weakly-typed Read-Write InformationIn the previous section, we have looked into implementing a rudimentary WMI provider which exposes read-only information. In this section, we will make our provider more interesting by exposing read-write information. Read-write information is exposed by defining a read-write property and decorating it with the The following code demonstrates a WMI provider which exposes a read-write property controlling the brightness of the screen. For demonstration purposes, the code to modify screen brightness has been omitted from the sample. [ManagementEntity]
public class BrightnessController
{
[ManagementBind]
public BrightnessController()
{
Id = 1; BrightnessLevel = 500;
}
[ManagementKey]
public int Id { get; private set; }
[ManagementConfiguration]
public int BrightnessLevel { get; set; }
}
Due to limitations in the current WMI Provider Extensions for .NET implementation, a singleton WMI provider cannot expose any updateable properties. Attempting to update a property exposed by a singleton WMI provider will result in an ExecutionEngineException at runtime. The WMIC tool has the capability of writing values to writeable properties of a WMI provider. The following command executed from a command prompt will modify the wmic /namespace:\\root\MyApplication path BrightnessController.Id=1
set BrightnessLevel=400
Note the use of the .Id=1 syntax to specify which brightness controller instance we are updating. Alternatively, query syntax can also be used: wmic /namespace:\\root\MyApplication path BrightnessController where Id=1
set BrightnessLevel=400
Modifying updateable information from managed code generated by Visual Studio is as easy as writing a value to a writeable property. After generating the managed class, the following code will update the brightness controller’s brightness level: foreach (ROOT.MYAPPLICATION.BrightnessController
controller in
ROOT.MYAPPLICATION.BrightnessController.GetInstances(
"Id = 1"))
{
controller.BrightnessLevel = 400;
}
MethodsIn the previous section, we have exposed read-write properties from a WMI provider. Setting a property value is similar to invoking a method; however, similarly to the semantic difference between properties and methods in .NET, there is a difference between properties and methods in the WMI taxonomy. In this section, we will define a method exposed by our WMI provider by decorating it with the The following code demonstrates a WMI provider which exposes a [ManagementEntity]
public class Printer
{
[ManagementBind]
public Printer([ManagementName("Id")] int id)
{
Id = id;
}
[ManagementKey]
public int Id;
[ManagementTask]
public void PrintToScreen(string s)
{
Console.WriteLine(s);
}
}
Due to limitations in the current WMI Provider Extensions for .NET implementation, a singleton WMI provider cannot expose any methods. Attempting to call a method exposed by a singleton WMI provider will result in an ExecutionEngineException at runtime. The WMIC tool has the capability of invoking methods exposed by a WMI provider. The following command executed from a command prompt will invoke the wmic /namespace:\\root\MyApplication path Printer.Id=1 call PrintToScreen Hello!
Invoking provider methods from managed code generated by Visual Studio is as easy as calling a method on an object. After generating the managed class, the following code will invoke the foreach (ROOT.MYAPPLICATION.Printer printer in
ROOT.MYAPPLICATION.Printer.GetInstances("Id = 2"))
{
printer.PrintToScreen("Hello!");
}
EventsThe previous sections described various mechanisms of communication from the WMI consumer to the WMI provider – including read-only properties, read-write properties, and methods. However, publishing events from a WMI provider is the only scalable option of providing changing contextual information as it occurs. Pulling the information on demand is not an option because it doesn’t scale. In this post, we will use the Publishing events from a WMI provider is not supported by the WMI Provider Extensions for .NET 3.5. It is only supported by the .NET 2.0 implementation. Therefore, in order to publish events from your application, the [assembly: Instrumented(@"root\MyApplication")]
[RunInstaller(true)]
public class OldInstaller :
DefaultManagementProjectInstaller {}
Note that using the An event that can be published from a WMI provider is represented as a simple managed class. The class contains properties which constitute the event data. The following code demonstrates an event class that can be published whenever the CPU temperature rises above a certain threshold: public class CpuTemperatureAboveThresholdEvent : BaseEvent
{
public float ActualTemperature { get; private set; }
private CpuTemperatureAboveThresholdEvent(
float actualTemperature)
{
ActualTemperature = actualTemperature;
}
public static void Publish(float actualTemperature)
{
new CpuTemperatureAboveThresholdEvent(
actualTemperature).Fire();
}
}
To publish this event, we can use the static CpuTemperatureAboveThresholdEvent.Publish(85.0f);
An alternative to deriving the event class from the [InstrumentationClass(InstrumentationType.Event)]
public class CpuTemperatureAboveThresholdEvent
{
public float ActualTemperature { get; private set; }
private CpuTemperatureAboveThresholdEvent(
float actualTemperature)
{
ActualTemperature = actualTemperature;
}
public static void Publish(float actualTemperature)
{
Instrumentation.Fire(
new CpuTemperatureAboveThresholdEvent(
actualTemperature));
}
}
Note that the only changes are that the class doesn’t derive from Visual Studio’s Server Explorer features the support necessary for subscribing to events published by a WMI provider. Right click the Management Events node, and select Add Event Query. In the dialog displayed, search for your class name (in our case, The ManagementEventWatcher watcher =
new ManagementEventWatcher(@"root\MyApplication",
"SELECT * FROM CpuTemperatureAboveThresholdEvent");
watcher.EventArrived += (o, e) =>
Console.WriteLine(e.NewEvent["ActualTemperature"]);
watcher.Start();
It is time to outline some of the advanced topics that are outside the scope of this series. References Between WMI ObjectsA reference between WMI objects has to be established using a property decorated with a EnumeratorsWMI classes can implement an enumeration static method to dynamically discover or create WMI object instances. This can be accomplished by decorating a method with the Create and Remove MethodsInstance methods on a WMI class can create a new instance of the WMI class. These methods must have the same signature as the class binding constructor (decorated with Similarly, a method can be denoted as a cleanup method for a MWI class instance. This method must not have any parameters, and must return Dynamic RegistrationInstead of performing registration with the InstallUtil.exe tool, it is possible to dynamically register and unregister assemblies or types containing WMI provider information. The History
|
||||||||||||||||||||||||||||||