Category Archives: Buggy

OleDbProbe – RegLocation Configuration – Design Flaw

I’ve been messing around with the OleDbProbe module this week, and have hit a couple issues that have been a bit frustrating and cost quite a bit of time. The first issue I ran into is described here, and now I’ll tell you about another problem.

Taking a snippet from the module definition below, we can inspect the registry to set the DatabaseName and ServerName configuration values for the SQL connection string.

<ProbeActionModuleType ID="System.OleDbProbe" Accessibility="Public" PassThrough="false" Batching="false">
<Configuration>
<xsd:element name="ConnectionString" type="xsd:string"/>
<xsd:element name="Query" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<xsd:element name="GetValue" type="xsd:boolean" minOccurs="0" maxOccurs="1"/>
<xsd:element name="IncludeOriginalItem" type="xsd:boolean" minOccurs="0" maxOccurs="1"/>
<xsd:element name="OneRowPerItem" type="xsd:boolean" minOccurs="0" maxOccurs="1"/>
<xsd:element name="DatabaseNameRegLocation" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<xsd:element name="DatabaseServerNameRegLocation" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<xsd:element name="QueryTimeout" type="xsd:integer" minOccurs="0" maxOccurs="1"/>
<xsd:element name="GetFetchTime" type="xsd:boolean" minOccurs="0" maxOccurs="1"/>
</Configuration>
<ModuleImplementation Isolation="Any">
<Native>
<ClassID>B5A35748-86F5-46A3-9BC2-F9A494E36B25</ClassID>
</Native>
</ModuleImplementation>
<OutputType>System.OleDbData</OutputType>
<InputType>System.BaseData</InputType>
</ProbeActionModuleType>

The example registry key path and string name provided on the MSDN page is SOFTWARE\Company\Product\1.0\DatabaseName and SOFTWARE\Company\Product\1.0\ServerName.

Ok – no problem. Good example. The problem is, it’s not an example – the string name must be exactly DatabaseName and ServerName.

It’s not exactly a useful configuration, unless your registry string names happen to conform to the name specified in the native code for the OleDbProbe module (which, of course, is hidden from us). For example, if you want to use this module to query the Operations Manager databases, forget about using this registry configuration option because the string names for either the Operational database or Data Warehouse database do not exactly match what the OleDbModule expects. I can say, without a doubt, this is a design flaw.

If you really want to use a registry location of your choice, you’ll need to add another module before the OleDbProbe to read the registry string name, and then pass that into the connection string element of the OleDbProbe module. (see below for an example)

Here are the events you might see on the target server that attempts to execute the workflow without having the expected registry string names.

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
<Provider Name="HealthService" />
<EventID Qualifiers="49152">4511</EventID>
<Level>2</Level>
<Task>1</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2016-06-07T02:19:20.000000000Z" />
<EventRecordID>7520157</EventRecordID>
<Channel>Operations Manager</Channel>
<Computer>ms01.scomskills.com</Computer>
<Security />
</System>
- <EventData>
<Data>2012-SP1</Data>
<Data>Your.Workflow</Data>
<Data>ms01.scomskills.com</Data>
<Data>{2C420F32-475D-019B-F7D2-E6F92B60E0C0}</Data>
<Data>OleDbProbe</Data>
<Data>{B5A35748-86F5-46A3-9BC2-F9A494E36B25}</Data>
<Data>The system cannot find the file specified.</Data>
</EventData>
</Event>

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
<Provider Name="Health Service Modules" />
<EventID Qualifiers="49152">11851</EventID>
<Level>2</Level>
<Task>0</Task>
<Keywords>0x80000000000000</Keywords>
<TimeCreated SystemTime="2016-06-07T02:19:20.000000000Z" />
<EventRecordID>7520156</EventRecordID>
<Channel>Operations Manager</Channel>
<Computer>ms01.scomskills.com</Computer>
<Security />
</System>
- <EventData>
<Data>2012-SP1</Data>
<Data>Your.Workflow</Data>
<Data>ms01.scomskills.com</Data>
<Data>{2C420F32-475D-019B-F7D2-E6F92B60E0C0}</Data>
<Data><Configuration><ConnectionString>Provider=SQLOLEDB;Integrated Security=SSPI</ConnectionString><Query>Your Query</Query><GetValue>true</GetValue><OneRowPerItem>true</OneRowPerItem><DatabaseNameRegLocation>SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\DataWarehouseDBName</DatabaseNameRegLocation><DatabaseServerNameRegLocation>SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Setup\DataWarehoueDBServerName</DatabaseServerNameRegLocation><QueryTimeout>60</QueryTimeout><GetFetchTime>false</GetFetchTime></Configuration></Data>
<Data>0x80070002</Data>
<Data>The system cannot find the file specified.</Data>
</EventData>
</Event>
 
Here’s an example to solve the problem. String these together in a module if you want to grab a registry string name/value of your choice.
 
<ProbeAction ID="RegistryProbe" TypeID="Windows!Microsoft.Windows.RegistryProbe">
<ComputerName>$Config/ComputerName$</ComputerName>
<RegistryAttributeDefinitions>
<RegistryAttributeDefinition>
<AttributeName>ServerName</AttributeName>
<Path>SOFTWARE\WhateverYouWant</Path>
<PathType>1</PathType>
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
<RegistryAttributeDefinition>
<AttributeName>DatabaseName</AttributeName>
<Path>SOFTWARE\WhateverYouWant</Path>
<PathType>1</PathType>
<AttributeType>1</AttributeType>
</RegistryAttributeDefinition>
</RegistryAttributeDefinitions>
</ProbeAction>
<ProbeAction ID="Query" TypeID="System!System.OleDbProbe">
<ConnectionString>Provider=SQLOLEDB;Server=$Data/Values/ServerName$;Database=$Data/Values/DatabaseName$;Integrated Security=SSPI</ConnectionString>
<Query>$Config/Sql$</Query>
<GetValue>$Config/GetValue$</GetValue>
<OneRowPerItem>true</OneRowPerItem>
<QueryTimeout>$Config/QueryTimeoutSeconds$</QueryTimeout>
<GetFetchTime>false</GetFetchTime>
</ProbeAction>

OleDbProbe – VariantType=”0” – Empty

Today I found an issue with the OleDbProbe module in which I found no solution in my searches, so it was one of those cases where I needed to step through various debugging tools and scour through code to solve the problem. It’s can be rewarding, because it gives me something to write about, but it sure can be time consuming. I’ve used this module many times in the past, but this is the first time I’ve seen odd behavior in the results.

The Problem

I had plugged my query into the module and simulated the workflow, and the results of each column was <Column VariantType=”0” />, as shown below.

- <DataItems>
- <DataItem type="System.OleDbData" time="2016-06-04T14:15:45.9305344-05:00" sourceHealthServiceId="D4E9691B-9F54-0F31-786C-BAF110FB769F">
<HRResult>0</HRResult>
<ResultLength>8</ResultLength>
<Result>Success</Result>
<InitializationTime>909</InitializationTime>
<OpenTime>0</OpenTime>
<ExecutionTime>20</ExecutionTime>
<FetchTime>0</FetchTime>
<RowLength>5</RowLength>
- <Columns>
<Column VariantType="0" />
</Columns>
- <Columns>
<Column VariantType="0" />
</Columns>
- <Columns>
<Column VariantType="0" />
</Columns>
- <Columns>
<Column VariantType="0" />
</Columns>
- <Columns>
<Column VariantType="0" />
</Columns>
<OriginalDataLength>0</OriginalDataLength>
<ErrorDescriptionLength>0</ErrorDescriptionLength>
<ResultCode>0</ResultCode>
</DataItem>
</DataItems>

As we can see from the results, the query succeeded. One would assume with a successful query comes valid and filled columns. Wondering why the results were all empty, I expanded the query selection to include all columns, and what I found was quite interesting. Below is just the columns section. As we can see here, about half the columns filled with data and with their corresponding types. And about half did not fill, with VariantType=”0”, which means it’s empty.

<Columns>
<Column VariantType="3">147</Column>
<Column VariantType="3">1</Column>
<Column VariantType="8">{A6B2A91A-BA8E-6D80-06BD-3F12BF28652D}</Column>
<Column VariantType="3">64</Column>
<Column VariantType="3">147</Column>
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="3">64</Column>
<Column VariantType="8">{EA99500D-8D52-FC52-B5A5-10DCD1E9D2BD}</Column>
<Column VariantType="3">8</Column>
<Column VariantType="8">Microsoft.Windows.Computer</Column>
<Column VariantType="8">Windows Computer</Column>
<Column VariantType="0" />
<Column VariantType="3">273</Column>
<Column VariantType="3">147</Column>
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="0" />
<Column VariantType="1" />
<Column VariantType="0" />
<Column VariantType="0" />
</Columns>

I thought there might be some sort of pattern to this, but I haven’t discovered it. I looked at the column properties in the database, and did not find anything resembling a consistent pattern that would indicate any reason why some columns are filled during execution and some are not. I gave up on trying to answer the question of “why” some columns refuse to fill, and found the solution by casting in the sql SELECT statement.

The Solution

The problem was solved by casting the columns that did not fill in the SELECT statement.

Here is the first query that returned empty columns.

SELECT me.Name
FROM vManagedEntity AS me
inner join vManagedEntityType AS met ON met.ManagedEntityTypeRowId = me.ManagedEntityTypeRowId
inner join vManagedEntityProperty AS mep ON mep.ManagedEntityRowId = me.ManagedEntityRowId
WHERE met.ManagedEntityTypeSystemName = 'Microsoft.Windows.Computer' AND
mep.ToDateTime IS NULL

And here is the modified query with CAST in the SELECT statement.

SELECT CAST (me.Name as NVARCHAR)
FROM vManagedEntity AS me
inner join vManagedEntityType AS met ON met.ManagedEntityTypeRowId = me.ManagedEntityTypeRowId
inner join vManagedEntityProperty AS mep ON mep.ManagedEntityRowId = me.ManagedEntityRowId
WHERE met.ManagedEntityTypeSystemName = 'Microsoft.Windows.Computer' AND
mep.ToDateTime IS NULL

That’s it folks. Hope this helps if you find yourself in the same bind as me.

Passing Boolean values to Powershell modules

Often times we need to pass a Boolean value to a Powershell provider, and a perfect example is for the purpose of a “debug” flag.

In my experience, Powershell probe and write action modules always type cast the script input parameter as String, whether the configuration element is of type Boolean or String. This means the default value in your workflow could be true, false, 1, or 0, and it will always equal true if you are handling this input parameter as Boolean in the script.

Obviously, this will cause some unexpected behaviors, and most likely will be viewed as a bug in the management pack.

The way I work around this issue (at least until this is fixed in the product) is NOT typing the script parameter, and then converting the variable to Boolean just after the param block like this:

param($debugFlag)
$debugFlag = [System.Convert]::ToBoolean($debugFlag)

By handling a Boolean input parameter like this in the script, we can effectively use the Boolean type in module configuration; the default value in the monitoring workflow can be true or false, the value will be handled appropriately by the script, the operator will see the default value as it should appear in console, and the operator will be presented with a meaningful (True|False) selector in the override interface.

UPDATE (09/02/2015) – This problem applies to Boolean, Integer, and Double values!

After writing this post, I wanted to get down to the bottom of the problem, so I poked around the Windows Library and what I found made it clear.

Taking a look at the implementation of any Powershell probe module, you will notice the Parameters element type is NamedParametersType, and this is defined in the Microsoft.Windows.PowerShellSchema. Notice the name-value pair are of type ID and string, respectively. This is the reason any type of value will be cast as String in a Powershell module.

<SchemaType ID="Microsoft.Windows.PowerShellSchema" Accessibility="Public"> 
<xsd:complexType name="NamedParametersType">
<xsd:sequence>
<xsd:element name="Parameter" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:ID" />
<xsd:element name="Value" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SnapInsType">
<xsd:sequence>
<xsd:element name="SnapIn" minOccurs="0" maxOccurs="unbounded" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="NonNullString">
<xsd:restriction base="xsd:string">
<xsd:minLength value="1" />
</xsd:restriction>
</xsd:simpleType>
</SchemaType>

It seems to me, the way to resolve this is to update the library with a choice for value type. This would allow the developer the option to type cast, and would remove the assumption that type casting is occurring when it is not. Since this schema exists in the Microsoft Windows Library, it would make the most sense for Microsoft to fix this.

WFAnalyzer.exe has stopped working

Just a quick post here, for those management pack developers that have run into the problem of simulating a workflow using the Visual Studio Authoring Extensions.

I have been missing the Workflow Analyzer companion to the MP Simulator for QUITE SOME TIME. I’ve tried troubleshooting the problem on several occasions, probably spending more than 10-12 hours burning midnight oil over the past months researching, debugging, sifting through logs and many Stack Overflow pages regarding .NET exceptions.

I’ve uninstalled and installed again the VSAE, and probably Visual Studio as well at some point, to no avail – the catastrophic behavior of Workflow Analyzer was clearly the bane of my development work. “The system cannot find the file specified?” What a benign message that is, especially when there is no file specified in the exception!

Just fixed it, though – out of what seems to be sheer luck.

I uninstalled Microsoft Monitoring Agent from my development workstation and installed the System Center 2012 SP1 agent – low and behold, the Workflow Analyzer sprung to life!

So happy now that I can actually see runtime data!

 

Here are a couple other references that didn’t provide a solution for me, but this issue seems very eluding and they might work in your case.

http://blogs.msdn.com/b/tysonpaul/archive/2014/07/01/workflow-analyzer-unhandled-exception-quot-the-system-cannot-find-the-file-specified-quot.aspx

http://blogs.inframon.com/post/2012/04/04/Management-Pack-Simulation-The-good-the-bad-and-the-%E2%80%A6-workaround.aspx

http://stackoverflow.com/questions/27596215/c-sharp-code-wont-launch-programs-win32exception-was-unhandled

Is ComputerName really an option?

I was creating a custom event data source module today, using the Microsoft.Windows.BaseEventProvider, and ran into a problem.

After importing the pack into the management group, I saw these events on all targeted agents.

Log Name:      Operations Manager
Source:        HealthService
Date:          5/15/2014 4:38:34 PM
Event ID:      4511
Task Category: Health Service
Level:         Error
Keywords:      Classic
User:          N/A
Computer:      sql01.scomskills.com
Description:
Initialization of a module of type "CrimsonDataSource" (CLSID "{B98BD20C-3CC8-4AFE-9F68-5702C74D73DB}") failed with error code The parameter is incorrect. causing the rule "Scomskills.CustomModules.Rule.FileSizeScriptException" running for instance "SQL01.scomskills.com" with id:"{6898E94D-1E65-E33B-F8DF-7BF9A124CF6F}" in management group "2012-SP1".

It ended up being that the Microsoft.Windows.BaseEventProvider required ComputerName as configuration, even though ComputerName is marked as optional configuration.

Digging in a little further, event details above call out CrimsonDataSource CLSID {B98BD20C-3CC8-4AFE-9F68-5702C74D73DB}.

Taking a look at the module implementation, we can see this is exactly the class id referenced:

<DataSourceModuleType ID="Microsoft.Windows.BaseEventProvider" Accessibility="Public">
  <Configuration>
    <IncludeSchemaTypes>
      <SchemaType>Microsoft.Windows.ComputerNameSchema</SchemaType>
    </IncludeSchemaTypes>
    <xsd:element name="ComputerName" type="ComputerNameType" minOccurs="0" maxOccurs="1" />
    <xsd:element name="LogName" type="xsd:string" />
    <xsd:element name="AllowProxying" type="xsd:boolean" minOccurs="0" maxOccurs="1" />
  </Configuration>
  <ModuleImplementation>
    <Native>
      <ClassID>B98BD20C-3CC8-4AFE-9F68-5702C74D73DB</ClassID>
    </Native>
  </ModuleImplementation>
  <OutputType>Microsoft.Windows.EventData</OutputType>
</DataSourceModuleType>

 

Another interesting part is that Microsoft.Windows.ComputerNameSchema is referenced as an included schema. The interesting part here is, when a schema type is included in a data source module, this automatically precludes that xsd element from being optional – in this case, ComputerName.

<SchemaType ID="Microsoft.Windows.ComputerNameSchema" Accessibility="Public">
  <xsd:simpleType name="ComputerNameType">
    <xsd:restriction base="xsd:string">
      <xsd:minLength value="0" />
      <xsd:maxLength value="260" />
    </xsd:restriction>
  </xsd:simpleType>
</SchemaType>

 

If the included schema type had a minOccurs flag, ComputerName would in fact be optional in the data source. But this is not the case in this example.

I suppose the point to this entire post is:

Beware of "optional" configuration, because it may actually be required and result in a broken data source if it’s missing.

In these cases, it is minimally required to pass in empty configuration, as demonstrated below.

<DataSource ID="DS1" TypeID="Windows!Microsoft.Windows.BaseEventProvider">
  <ComputerName />
  <LogName>Operations Manager</LogName>
</DataSource>

 

 

🙁