I first played with the CIM IDE when working on a chapter of my book. I decided to jump further in depth with it in my spare time to try and create a native WMI provider that would produce native PowerShell cmdlets. I wanted to be able to further document what is described in the white paper that I’ve attached to this post (I can’t find where it was available for download). After several hours using the CIM IDE I have to admit, I wasn’t successful. I’m hoping that through this blog post some one will be able to point out what I’m doing wrong.
Getting up and running with the CIM IDE
The CIM IDE is available here. It is an extension that is installed into Visual Studio and provides two new projects for developing providers, MOF syntax highlighting, and a CIM explorer to quickly view MOF files in a designer. Once installed, you’ll have access to the two new project types.
- CIM Providers – This project type is used to create the definition for classes that will be available in the CIM provider that we are writing. Class definitions are authored via MOF in the new MOF editor.
- CIM Authoring – This project type is used to define the business logic for the CIM provider. It is more or less a C project that utilizes the new MI APIs. The APIs offer macros and functions that make working with the CIM system much easier.
Creating a Provider
The first step is to create a CIM Provider project to define the MOF for our provider. We’ll be creating a Gremlin provider that exposes a Win32_Gremlin class. The Gremlin class will do little more than return a collection of Gremlins that are defined in the system. Once our CIM Provider project is created we can define a new CIM Class. We can do this by selecting Add->New Item->CIM Class. This will bring up the Add Class window where we can define the superclass and numerous other properties of the class.
Once we press Add, we will be presented with the MOF editor window. The CIM IDE providers syntax highlighting and validation. We can override the CIM_LogicalElement’s Name property and use it as the key property. The CIM IDE will not generate the correct C method in the provider skeleton if we do not define at least one Key property. Any errors in the MOF will be shown in the Error Window.
Once our MOF has been defined we can view the class in the CIM Explorer and CIM Details view. The CIM Explorer has a list of all the classes that were imported into the CIM IDE when it was first run. In addition to the list of standard classes, we will find out Win32_Gremlin class. Double clicking the class will bring up the CIM Details view that contains a list of all the Properties, Methods and Associations. This is tool window is read-only.
Now that we have our MOF defined we can use the other CIM project to define the implementation details of the Win32_Gremlin class. The first step is to create a CIM Authoring project. The project will be empty at first. In order to generate the provide skeleton we need to open the CIM Explorer, select the Win32_Gremlin class and click the Generate Code tool bar button.
The Generate Provider window will be shown that will allow us to define further options for the generated code. The drop down allows for selection of the CIM Authoring project to define the code within.
Once we select OK, the authoring project will be inflated with all the necessary source and header files.
The file that we are most interested in is the Win32_Gremlin.c source file. It contains all the methods that are used to define the implementation details for the class. For this post, we are only focused on the EnumerateInstances function. It’s goal is to return the instances of the class that are currently on the system.
We can see that there are several pre-defined functions used within EnumerateInstances. These have been generated for us by the CIM IDE.
- Win32_Gremlin_Construct – This function accepts a pointer to the Win32_Gremlin instance we wish to instantiate along with the context.
- Win32_Gremlin_Set_Name – This function is used to specify the value for the name. For each property there will be such a function defined. There will also be an accompanying Get function. I had lot’s of problems using this function. It always threw an access violation. After some research, it looks like the function pointer for the underlying SetElementAt function is null for some reason. This should have been populated by the Construct call. I haven’t been able to figure out why this isn’t working. Instead, I set the value on the property directly.
- Win32_Gremlin_Post – This function behaves somewhat like the WriteObject method does for PowerShell, in that it posts the instance of the class as a result of the call.
- Win32_Gremlin_Destruct – This function cleans up the memory allocated by the Construct call. This function was also throwing an access violation but for an unknown reason. According to the documentation, the Post function will make a copy of the instance so we can safely clean up the memory at this juncture.
- MI_PostResult – This function returns the overall success or failure of the EnumerateInstances call.
- MI_WriteVerbose – Writes verbose log messages. There is also a MI_WriteMessage that can be used to log more general messages.
Creating PowerShell MetaData
In order to create native PowerShell cmdlets, metadata XML needs to be generated to define the mapping between the CIM class and a cmdlet. This mapping is accomplished with an XML file with a CD1XML extension. To generate this file we can use the CIM IDE. This is accmplished by right clicking on the Win32_Gremlin class and selecting Add PowerShell Metadata. This will bring up the metadata options window.
After the file has been added we can use the CIM IDE to add cmdlets. Since our class is enumerable, a Queryable cmdlet will be defined. We can add a queryable parameter by using the PowerShell Metadata tool window. Below, the Name has been added.
Registering the Provider and Using the Cmdlets
First, we need to register the provider. There is a new tool that accompanies the CIM IDE. We can use the following command line to register our provider. This has to be done from an elevated command prompt.
Register-CIMProvider.exe -Namespace root\adam -ProviderName Gremlin -Path Gremlin.dll
Once registered, we will be able to utilize the cmdlet metadata that we generated earlier. The CD1XML file can be consumed using the Import-Module cmdlet just like we would if we were to consume a DLL or PS1.
Import-Module -Path Gremlin.CD1XML
Now we will be able to use our cmdlet. Notice that the Name parameter is specified and we get a CimSession parameter for free.
It’s also possible to query our class using the CIM cmdlets like so.
Get-CimInstance -ClassName Win32_Gremlin -Namespace root\adam
I really wish it would have worked for me. It seems like a really cool concept and is a whole new paradigm on cmdlet development. Maybe someone from Microsoft can shed some light on why this wasn’t working for me.