Using Wildcards with the Windows Service Template

The Windows Service template in the Operations Console lets you discover and monitor a Windows service by doing little more than typing in the service name.  I was just talking with someone who had a situation where the name of the service includes the local computer name meaning that it's different on every computer.  It's the same service and should be monitored as such - just a slightly different name on each agent.  Unfortunately, the template won't allow us to provide a wildcard in the service name. 

For those who are skilled with management pack authoring, you're probably not relying on the template anyway, and this wouldn't be too difficult of a task.  As such, I'm going to write this post from the point of view of someone who primarily lives within the Operations Console.  We do have to get exposed to a bit of XML in order to pull this off, but it really should be minimal.

First, let's understand what the Windows Service template does.  It performs two functions: 1) creates a new class (aka target) for your service and 2) creates a discovery to find instances of that new class.  The new class that the template created should be fine as is.  We can provide the template with any name we want, and it doesn't have to have anything to do with the name of the service itself.  The discovery is what we need to think about.

The discovery that the template uses is a special one specifically designed for finding a service, and it doesn't allow wildcards.  We can replace that discovery with a WMI discovery module since we can pretty easily write a WMI query to find all services that match a certain criteria, and that criteria can include a wildcard.  There is a module called WmiProviderWithClassSnapshotDataMapper in the Windows Library management pack that will work perfectly.

Let's go through this step by step.  I have a virtual machine running under the beta of Hyper-V in Windows Server 2008.  That includes a few services that start with the three letters "vmi".  I know this is a bit of a difference scenario than I described above, but it will still illustrate the point of discovering services using a wildcard. 

1.  Walk through the Windows Template wizard as normal providing your wildcard string.  Note that we are going to pass this off to WMI which uses % as a wildcard character, not *.

image image

2.  Export the management pack you just used for the template.

image

 

3.  Open the XML file you just exported.  Use an XML editor if you have one.  Otherwise, you could use Notepad.

image

 

4.  You have to locate the discovery you just created which can be a little tricky since the names generated by the Operations Console are pretty long and ugly.  Probably the easiest method would be to search on the wildcard string you typed in. 

image

5.  The Discovery will look something like mine which I pasted below.  The long ID strings will be different in yours, but the rest should be pretty similar.  There's a lot going on here, but we're not going to have to worry about most of it.  I highlighted in blue the parts that we're going to need to change, and that shouldn't be too intimidating.

 

<Discovery ID="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f.DiscoveryRule" Enabled="true" Target="Windows!Microsoft.Windows.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f" />
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.Win32ServiceInformationProviderWithClassSnapshotDataMapper">
<ComputerName>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
<ServiceName>vmi%</ServiceName>
<Frequency>60</Frequency>
<ClassId>$MPElement[Name="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f"]$</ClassId>
<InstanceSettings>
<Settings>
<Setting>
<Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceName$</Name>
<Value>$Data/Property[@Name='Name']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceProcessName$</Name>
<Value>$Data/Property[@Name='BinaryPathName']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/DisplayName$</Name>
<Value>$Data/Property[@Name='DisplayName']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/Description$</Name>
<Value>$Data/Property[@Name='Description']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>Hyper-V Services</Value>
</Setting>
</Settings>
</InstanceSettings>
</DataSource>
</Discovery>

 

6.  Modify the discovery to use the WMI discovery module.  I highlighted in red the modifications you want to make.  You could just copy and paste right from this pots into your management pack.  Obviously, in that query, you're going to use your wildcard string as opposed to the vmi% that I used.  All we're doing is changing out the module we're using as the data source for the discovery.  Then we're replacing the parameters that we were passing to the old module to the parameters expected by the new one. 

<Discovery ID="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f.DiscoveryRule" Enabled="true" Target="Windows!Microsoft.Windows.Computer" ConfirmDelivery="false" Remotable="true" Priority="Normal">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f" />
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper">
<NameSpace>root\cimv2</NameSpace>
<Query>select * from win32_service where name like 'vmi%'</Query>
<Frequency>60</Frequency>
<ClassId>$MPElement[Name="ServiceStateProbePage_eaa08473602945a592b2a117b62c634f"]$</ClassId>
<InstanceSettings>
<Settings>
<Setting>
<Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name>
<Value>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceName$</Name>
<Value>$Data/Property[@Name='Name']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/ServiceProcessName$</Name>
<Value>$Data/Property[@Name='PathName']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/DisplayName$</Name>
<Value>$Data/Property[@Name='DisplayName']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="MicrosoftSystemCenterNTServiceLibrary!Microsoft.SystemCenter.NTService"]/Description$</Name>
<Value>$Data/Property[@Name='Description']$</Value>
</Setting>
<Setting>
<Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
<Value>Hyper-V Services</Value>
</Setting>
</Settings>
</InstanceSettings>
</DataSource>
</Discovery>

7.  Import the modified management pack.  If you get an error on import, then you made a mistake in the modification.  Go back and export the management pack and try again.

8.  Go to Discovered Inventory and change the target type to your class.  Within a minute or two, you should start to see instances showing up.

image