Today I’m writing about an elusive problem with a management pack that I was authoring recently. I was writing a generic datasource for a registry discovery; that is a discovery that will instantiate a class based on the existence of a registry key on the Target machine, and generic because I will use a single RegistryProbe datasource for discovery of multiple different class types. (This will save me some time down the road when using the VSAE Discovery template group in Visual Studio). If the registry key exists, the specified class will be discovered. When I attempted to initiate a build (something I do incrementally after minor changes to verify that what I just changed is valid) I encountered an ambiguous error:
—— Build started: Project: WF.Fax, Configuration: Debug x86 ——
Starting MP Build for WF.Fax.
Starting Fragment Verification
Resolving Project References
Starting Merge Management Pack Fragments
Starting Pre Processing
Starting MP Verify
Service Model\Classes.mpx(10,9): warning TypeDefinitionInUnsealedMP: Unsealed management packs should not contain type definitions. The element WF.Fax.RightFax.Server.Class of type ManagementPackClass found in an unsealed management pack. (Path = WF.Fax.RightFax.Server.Class)
C:\Program Files (x86)\MSBuild\Microsoft\VSAC\Microsoft.SystemCenter.OperationsManager.targets(270,5): error : Failed to verify module reference [Type=ManagementPackElement=System.Discovery.ClassSnapshotDataMapper in ManagementPack:[Name=System.Library, KeyToken=31bf3856ad364e35, Version=7.5.8501.0], ID=Mapping] in the MemberModules list.
: Incorrect XPATH reference: ClassId.
(Path = WF.Fax.RegistryProbe.Discovery.DS/Mapping)
Done building project “WF.Fax.mpproj” — FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========
There were a few key pieces of info here:
Failed to verify module reference [Type=ManagementPackElement=System.Discovery.ClassSnapshotDataMapper
– This tells me there is something wrong with how I’m using this module.
Incorrect XPATH reference: ClassId
– This tells me there something wrong with this parameter
(Path = WF.Fax.RegistryProbe.Discovery.DS/Mapping)
– This tells me where the problem is located: in the ‘Mapping’ section of the ‘WF.Fax.RegistryProbe.Discovery.DS’ module.
I once again visited the MSDN site where I found documentation for the reference module (https://msdn.microsoft.com/en-us/library/ee692953.aspx) and I copied the section of code from the Example into my Visual Studio 2017 SCOM 2016 MP project and BAM! I was able to build it successfully. The code from the example appeared to be absolutely identical to what I had first written.
Here’s what I first used (broken):
<ConditionDetection ID=”Mapping” TypeID=”System!System.Discovery.ClassSnapshotDataMapper”>
<!–https://msdn.microsoft.com/en-us/library/ee692953.aspx–>
<ClassId>$Config/ClassId$</ClassId>
<InstanceSettings>$Config/InstanceSettings$</InstanceSettings>
</ConditionDetection>
Here’s the working code (builds successfully):
<ConditionDetection ID=”Mapping” TypeID=”System!System.Discovery.ClassSnapshotDataMapper”>
<!–https://msdn.microsoft.com/en-us/library/ee692953.aspx–>
<ClassId>$Config/ClassID$</ClassId>
<InstanceSettings>$Config/InstanceSettings$</InstanceSettings>
</ConditionDetection>
Notice anything different about those two snippets? Well I didn’t see a darn thing different but one would build and the other would not. Why? Whyyyyy?!?! I was getting really frustrated because I needed to know. I decided to go toe to toe with the universe on this one and bust out some PowerShell skills to solve my problem. I decided to do an individual character comparison of the two strings.
I’m not sharing the MP at this time because it’s for a customer and it’s actually not finished yet (at the time of this writing) but here’s the resulting script available for download. My initial version was much uglier but I decided to polish it up and add it to the Gallery so maybe it might help others some day.
“This is an easy way to compare two strings. The script will compare individual characters and output the ASCII values, hash values, and comparison results for each. This is useful when two strings appear to be the same but may have different characters (encodings or ASCII values). The script contains a function of the same name so that this can be included easily into a profile or module.” (Example: ‘dot source’ the script in your PowerShell profile.)
Here’s an example of how the script works:
In order to solve the mystery of why the universe was smiting me I created two “here” strings, one for each snippet of code and then I compared them with the script:
The Result:
Notice in my datasource Configuration: ClassID
Here’s the problem:
“ID” should be capitalized in “ClassID”.
Mystery solved, I’m an idiot. I overlooked one single character.
This error should have tipped me off: Incorrect XPATH reference: ClassId
I went to a bit of trouble to track down the answer here and in the end it was a tiny typo. This is not the first time that a tiny typo like this or hidden encoded character has caused me major headache. Now I have another script to add to my toolset so hopefully next time I can breeze through the problem in little time.