Category Archives: Authoring

Automate management packs using powershell

I’ve been asked on a few occasions to automate management packs. Unfortunately, there isn’t much information about how to do to do this using Powershell in the MSDN development kit. I am providing a couple Powershell functions you can add to your automation process that will generate a new management pack.

Just update the output directory, pack name, pack display name, and version in the highlighted lines.

 

function CreateNewPack ($id, $name, $version) {
    $mpStore = New-Object Microsoft.EnterpriseManagement.Configuration.IO.ManagementPackFileStore
    $managementPack = New-Object Microsoft.EnterpriseManagement.Configuration.ManagementPack($id, $name, (New-Object Version(1,0,0,$version)), $mpStore)
    $managementPack.DefaultLanguageCode = 'ENU'
    $managementPack.DisplayName = $name
    $managementPack.Description = $name + ' management pack was auto-generated'
    $managementPack
}
function WriteManagementPack ($directory, $mp) {
    $mpWriter = new-object Microsoft.EnterpriseManagement.Configuration.IO.ManagementPackXmlWriter($directory)
    $mpWriter.WriteManagementPack($mp) | Out-Null
}
$directory = 'c:\My Pack'
$mp = CreateNewPack 'MyNewPack' 'My New Pack' 1
$mp.AcceptChanges()
WriteManagementPack $directory $mp

Contact SCOMskills if you are interested in learning more about management pack automation, at automation@scomskills.com.

 

🙂

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>

 

 

🙁

New MatchCount Configuration in SCOM 2012

I’ve been meaning to write about this for a while, because I was thrilled when I found this new configuration element in the expression filter module when SCOM 2012 hit the press.

For reference, here are the differences in the expression filters:

SCOM 2007: http://msdn.microsoft.com/en-us/library/ee692962.aspx

SCOM 2012: http://msdn.microsoft.com/en-us/library/jj129836.aspx

Previously, the System.ExpressionFilter did not include suppression – today it does!

What this means is, we can now count the number of passes through a condition detection, and it will only pass data to the next module when the MatchCount value exceeds the configuration provided.

It doesn’t sound like a big deal really – but it is. I’ve had cases where I needed to count condition passes, and the only way to do it before was to include a consolidation module. This was not fun and it turned out to be a lot more work than was necessary – and it was confusing to the customer when they looked at the code.

What I do not like so much is the fact that Microsoft doesn’t expose this new configuration in their base monitoring at this time. For example, it’s not possible to override the match count for a service monitor that you created using the service monitoring template – or even interval for that matter. To me, it doesn’t make sense to introduce a new configuration element without providing a way to override it – especially a valuable configuration such as this.

The default monitoring for Windows services (at this time) is to sample every 30 seconds and exceed a match count of 2. This equates to a state change within 60 seconds of service downtime.

What I am providing here is a Windows service monitoring VSAE fragment that will allow you to override both the interval as well as the match count. I’ve also included an additional state value to account for service not found conditions. I added this condition because sometimes a pack needs to take into account upgrade scenarios where a service name changes – you don’t want an alert on a service that had been renamed due to an upgrade!

By the way, MatchCount has nothing to do with service monitoring – it’s a part of the expression filter, and can be used anywhere. This is just a working example of how you can use it in a custom service monitor type.

Here you go!

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <MonitorTypes>
      <UnitMonitorType ID="Example.CustomeModuleLibrary.MonitorType.CheckServiceState" Accessibility="Public">
        <MonitorTypeStates>
          <MonitorTypeState ID="MTS_Running" />
          <MonitorTypeState ID="MTS_NotRunning" />
        </MonitorTypeStates>
        <Configuration>
          <xsd:element name="ComputerName" type="xsd:string" />
          <xsd:element name="ServiceName" type="xsd:string" />
          <xsd:element name="IntervalSeconds" type="xsd:integer" />
          <xsd:element name="MatchCount" type="xsd:integer" />
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int" />
          <OverrideableParameter ID="MatchCount" Selector="$Config/MatchCount$" ParameterType="int" />
        </OverrideableParameters>
        <MonitorImplementation>
          <MemberModules>
            <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.Win32ServiceInformationProvider">
              <ComputerName>$Config/ComputerName$</ComputerName>
              <ServiceName>$Config/ServiceName$</ServiceName>
              <Frequency>$Config/IntervalSeconds$</Frequency>
            </DataSource>
            <ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.Win32ServiceInformationProbe">
              <ComputerName>$Config/ComputerName$</ComputerName>
              <ServiceName>$Config/ServiceName$</ServiceName>
            </ProbeAction>
            <ConditionDetection ID="CD_ServiceRunning" TypeID="System!System.ExpressionFilter">
              <Expression>
                <RegExExpression>
                  <ValueExpression>
                    <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                  </ValueExpression>
                  <Operator>MatchesRegularExpression</Operator>
                  <Pattern>^(4|8)$</Pattern> 
                </RegExExpression>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="CD_ServiceNotRunning" TypeID="System!System.ExpressionFilter">
              <Expression>
                <RegExExpression>
                  <ValueExpression>
                    <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                  </ValueExpression>
                  <Operator>DoesNotMatchRegularExpression</Operator>
                  <Pattern>^(4|8)$</Pattern>
                </RegExExpression>
              </Expression>
              <SuppressionSettings>
                <MatchCount>$Config/MatchCount$</MatchCount>
              </SuppressionSettings>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="MTS_Running">
              <Node ID="CD_ServiceRunning">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="MTS_NotRunning">
              <Node ID="CD_ServiceNotRunning">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
          </RegularDetections>
          <OnDemandDetections>
            <OnDemandDetection MonitorTypeStateID="MTS_Running">
              <Node ID="CD_ServiceRunning">
                <Node ID="Probe" />
              </Node>
            </OnDemandDetection>
            <OnDemandDetection MonitorTypeStateID="MTS_NotRunning">
              <Node ID="CD_ServiceNotRunning">
                <Node ID="Probe" />
              </Node>
            </OnDemandDetection>
          </OnDemandDetections>
        </MonitorImplementation>
      </UnitMonitorType>
    </MonitorTypes>
  </TypeDefinitions>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Example.CustomeModuleLibrary.MonitorType.CheckServiceState" SubElementID="IntervalSeconds">
          <Name>Interval (seconds)</Name>
          <Description>Check service state interval.</Description>
        </DisplayString>
        <DisplayString ElementID="Example.CustomeModuleLibrary.MonitorType.CheckServiceState" SubElementID="MatchCount">
          <Name>Match Count</Name>
          <Description>Number of intervals service is not running before changing monitor state.</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

Now you can implement new unit monitors that use this monitor type, and extend to your operators the ability to override interval and match count. You might want to replace "Example" with your company name before implementing in your library.

 

🙂

Report Fragment–Visual Studio Authoring Extensions

Developing reports in SCOM is quite a bit different than developing any type of monitoring workflow. You really need to ramp up your skills on a couple different tools and languages to become a good report developer.

In this post, I will cover a typical VSAE fragment that provides for deploying the report and stored procedure files – of course, the report files are deployed to the report server and the stored procedure is installed on the data warehouse.

This post covers the fragment essentials – it does not get into report or stored procedure development. It is intended to be a quick reference for those developers out there to quickly plug in the necessary elements to push the rdl and sql resource files in their management pack.

At the end, I will provide some essential elements that need to be included in your sql file that will satisfy "install", "upgrade", and "uninstall" functionality, as well as set the right execution permissions that will allow the data reader account to run the report in a generic environment.

In this example, there is a main report and a detail report. The detail report may be launched by clicking on an element in the main report – consider this a linked report.

Here’s the entire fragment

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Reporting>
    <DataWarehouseScripts>
      <DataWarehouseScript ID="MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script" Accessibility="Public">
        <InstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install</InstallScript>
        <UninstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall</UninstallScript>
        <UpgradeScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade</UpgradeScript>
      </DataWarehouseScript>
      <DataWarehouseScript ID="MyReports.Deploy.MyReportAvailabilityDataGet.Script" Accessibility="Public">
        <InstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Install</InstallScript>
        <UninstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Uninstall</UninstallScript>
        <UpgradeScript>Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Upgrade</UpgradeScript>
      </DataWarehouseScript>
    </DataWarehouseScripts>
    <Reports>
      <Report ID="MyReports.Availability.Main" Accessibility="Public" Visible="true">
        <Dependencies>
          <DataWarehouseScript>MyReports.Deploy.MyReportAvailabilityDataGet.Script</DataWarehouseScript>
        </Dependencies>
        <ReportDefinition>Res.MyReports.Availability.Main</ReportDefinition>
      </Report>
      <Report ID="MyReports.Availability.Detail" Accessibility="Public" Visible="true">
        <Dependencies>
          <DataWarehouseScript>MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script</DataWarehouseScript>
          <Report>MyReports.Availability.Main</Report>
        </Dependencies>
        <ReportDefinition>Res.MyReports.Availability.Detail</ReportDefinition>
      </Report>
    </Reports>
  </Reporting>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="MyReports">
          <Name>MyReports</Name>
          <Description>This management pack contains all data warehouse and reporting elements for custom MyReports.</Description>
        </DisplayString>
        <DisplayString ElementID="MyReports.Availability.Main">
          <Name>Availability Main</Name>
          <Description>Availability MyReport Main</Description>
        </DisplayString>
        <DisplayString ElementID="MyReports.Availability.Detail">
          <Name>Availability Detail</Name>
          <Description>Availability MyReport Detail</Description>
        </DisplayString>
        <DisplayString ElementID="MyReports.Deploy.MyReportAvailabilityDataGet.Script">
          <Name>Deploy MyReport Availability Data Get Script</Name>
        </DisplayString>
        <DisplayString ElementID="MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script">
          <Name>Deploy MyReport Availability Data Detail Get Script</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
  <Resources>
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Install" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Install.sql" HasNullStream="false" />
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Uninstall" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Uninstall.sql" HasNullStream="false" />
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Upgrade" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Upgrade.sql" HasNullStream="false" />
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install.sql" HasNullStream="false" />
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall.sql" HasNullStream="false" />
    <Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade.sql" HasNullStream="false" />
    <ReportResource ID="Res.MyReports.Availability.Detail" Accessibility="Public" FileName="Res.MyReports.Availability.Detail.rdl" HasNullStream="false" MIMEType="application/octet-stream" />
    <ReportResource ID="Res.MyReports.Availability.Main" Accessibility="Public" FileName="Res.MyReports.Availability.Main.rdl" HasNullStream="false" MIMEType="application/octet-stream" />
  </Resources>
</ManagementPackFragment>

 

Let’s break it down.

 

Data Warehouse Scripts

<DataWarehouseScript ID="MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script" Accessibility="Public">
  <InstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install</InstallScript>
  <UninstallScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall</UninstallScript>
  <UpgradeScript>Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade</UpgradeScript>
</DataWarehouseScript>

This is where the resource file pointers are defined – your sql stored procedures. You will need each version of the stored procedure to install, upgrade, and uninstall the stored procedure. These pointers reference the actual sql file resource later.

Note: I have yet to see the uninstall work (I think this is a bug in the sdk, but I won’t go there now).

 

Reports

<Report ID="MyReports.Availability.Main" Accessibility="Public" Visible="true">
  <Dependencies>
    <DataWarehouseScript>MyReports.Deploy.MyReportAvailabilityDataGet.Script</DataWarehouseScript>
  </Dependencies>
  <ReportDefinition>Res.MyReports.Availability.Main</ReportDefinition>
</Report>

This section defines the report id, the report dependencies, and the report definition resource (this points to the actual rdl file later).

 

Resource Files (skipping language packs, as we know what that’s for)

<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Install" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Install.sql" HasNullStream="false" />
<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Uninstall" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Uninstall.sql" HasNullStream="false" />
<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Upgrade" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataGet.Script.Upgrade.sql" HasNullStream="false" />
<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Install.sql" HasNullStream="false" />
<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Uninstall.sql" HasNullStream="false" />
<Resource ID="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade" Accessibility="Public" FileName="Res.MyReports.Deploy.MyReportAvailabilityDataDetailGet.Script.Upgrade.sql" HasNullStream="false" />
<ReportResource ID="Res.MyReports.Availability.Detail" Accessibility="Public" FileName="Res.MyReports.Availability.Detail.rdl" HasNullStream="false" MIMEType="application/octet-stream" />
<ReportResource ID="Res.MyReports.Availability.Main" Accessibility="Public" FileName="Res.MyReports.Availability.Main.rdl" HasNullStream="false" MIMEType="application/octet-stream" />

This section ties the resource id’s from above to actual physical files you will include in your solution – these are the .rdl and .sql files.

 

Stored Procedure Necessities

I mentioned earlier that I would discuss a couple things you will need in your stored procedure. Namely, you will need to specify the action of the procedure (install, upgrade, uninstall) and you need to assign permissions to execute the procedure (otherwise it will not work and you’ll get errors).

MSDN has a mediocre description for deploying stored procedures, but it falls short with real world examples. So I’ll give an example of each here.

Install

Basically, you need to first create the procedure, and then alter the procedure as follows. Don’t worry about the parameter declarations – it’s just an example in case you have them.

IF NOT EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = 'MyReport_AvailabilityDataGet')
BEGIN
EXECUTE ('CREATE PROCEDURE dbo.MyReport_AvailabilityDataGet AS RETURN 1')
END
GO

ALTER PROCEDURE dbo.MyReport_AvailabilityDataGet
    @StartDate datetime,
    @EndDate datetime,
    @ObjectList xml,
    @MonitorName nvarchar(256),
    @DataAggregation tinyint = 0,
    @LanguageCode varchar(3) = 'ENU'
AS
BEGIN
SET NOCOUNT ON
{your procedure goes here}
 

Upgrade

The only thing that needs to be changed for the upgrade procedure is to remove the entire first section of the install procedure (the first 5 lines). Everything else stays the same – just start your procedure with the ALTER PROCUDURE section.

 

Uninstall

This is actually very simple – just perform a drop.

IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = 'MyReport_AvailabilityDataGet')
BEGIN
        DROP PROCEDURE dbo.[MyReport_AvailabilityDataGet]
END
GO
 

Assign Permissions to the DataReader account

This is required at the end of both the install and upgrade scripts. The OpsMgrReader account is a standard role that is created during setup, so unless you have some custom configuration in your environment, this will work for you.

GRANT EXECUTE ON MyReport_AvailabilityDataGet TO OpsMgrReader
GO

 

And that’s about it. Now go write some reports and deploy them with your management pack, like a pro!

Event Description Pattern Matching (with minimal impact)

One thing to think about when authoring rules and monitors is performance, and Windows event monitoring is no exception. If you need to search for a string in an event description, and if said event description is not parameterized, this post is for you.

You could add this logic while creating a rule in the Operations console.

 

image

 

The reason you should not do this is because it’s going to require more compute time than is necessary. If the monitored event log typically has a steady stream of events written, a single event detection rule like this could create a significant processing bottleneck on the monitored computer.

This is because all filtering is happening at the data source level, which means every element in your expression filter is checked against every event that is written to the specified log on that computer. Searching for a string in the event description takes time, and this is why it’s a bad practice to implement event description processing in the data source module.

To implement event monitoring with minimal performance impact, I suggest including only these parameters in the data source criteria:

  • Event Source
  • Event Id
  • Event Level
  • Event Category
  • Event Parameter [0-..]

 

Furthermore, I suggest including only these operators in the data source criteria:

  • Equal
  • NotEqual
  • Greater
  • GreaterEqual
  • Less
  • LessEqual

 

So, how is it possible to implement pattern matching while still providing minimal processing impact?

The answer is to process pattern matching criteria in a condition detection module.

 

Wow, what a concept! Let the data source filter the simple event criteria, then move to the next module to process more complex criteria. That’s the cool thing about using System.ExpressionFilter. The workflow will exit if the expression <> true.

 

To understand this logic a little better, here is the processing sequence…

Without Condition Detection:

1. DataSource\EventDetection\Provider – match event log and logging computer (if true, move next)

2. DataSource\EventDetection\Filter – process all criteria (if true, move next)

3. WriteAction\Alert – generate an alert

 

With Condition Detection:

1. DataSource\EventDetection\Provider – match event log and logging computer (if true, move next)

2. DataSource\BasicEventDetection\Filter – process simple criteria (if true, move next)

3. ConditionDetection\FilterDescription – process complex criteria (if true, move next)

4. WriteAction\Alert – generate an alert

 

Unfortunately, it is not possible to implement the condition detection module in the Operations console. You will need to author this using the R2 Authoring Console, Visual Studio Authoring Extension, or directly in XML. I am providing a rule fragment you can add to your project using VSAE.

Similarly, you could implement this logic in an event detection monitor.

 

The below fragment detects event 101, with source TEST and event level ERROR in the Application log. If simple criteria matches, move the next module to process complex criteria (match SomePattern in the event description). Generate an alert at the end.

This rule fragment needs to be updated with your criteria and alert details. If you build it, alerts will come – and your manager will thank you.

 

 

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Monitoring>
    <Rules>
      <Rule ID="MyMp.Rule.EventDescriptionMatches" ConfirmDelivery="true" DiscardLevel="100" Enabled="true" Priority="Normal" Remotable="false" Target="Windows!Microsoft.Windows.Computer">
        <Category>Alert</Category>
        <DataSources>
          <DataSource ID="BasicEventDetection" TypeID="Windows!Microsoft.Windows.EventProvider">
            <ComputerName>$Target/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
            <LogName>Application</LogName>
            <Expression>
              <And>
                <Expression>
                  <SimpleExpression>
                    <ValueExpression>
                      <XPathQuery>EventSourceName</XPathQuery>
                    </ValueExpression>
                    <Operator>Equal</Operator>
                    <ValueExpression>
                      <Value>TEST</Value>
                    </ValueExpression>
                  </SimpleExpression>
                </Expression>
                <Expression>
                  <SimpleExpression>
                    <ValueExpression>
                      <XPathQuery>EventDisplayNumber</XPathQuery>
                    </ValueExpression>
                    <Operator>Equal</Operator>
                    <ValueExpression>
                      <Value>101</Value>
                    </ValueExpression>
                  </SimpleExpression>
                </Expression>
                <Expression>
                  <SimpleExpression>
                    <ValueExpression>
                      <XPathQuery>EventLevel</XPathQuery>
                    </ValueExpression>
                    <Operator>Equal</Operator>
                    <ValueExpression>
                      <Value>1</Value>
                    </ValueExpression>
                  </SimpleExpression>
                </Expression>
              </And>
            </Expression>
          </DataSource>
        </DataSources>
        <ConditionDetection ID="FilterDescription" TypeID="System!System.ExpressionFilter">
          <Expression>
            <RegExExpression>
              <ValueExpression>
                <XPathQuery>EventDescription</XPathQuery>
              </ValueExpression>
              <Operator>MatchesRegularExpression</Operator>
              <Pattern>SomePattern</Pattern>
            </RegExExpression>
          </Expression>
        </ConditionDetection>
        <WriteActions>
          <WriteAction ID="Alert" TypeID="Health!System.Health.GenerateAlert">
            <Priority>1</Priority>
            <Severity>2</Severity>
            <AlertMessageId>$MPElement[Name="MyMp.Rule.EventDescriptionMatches.AlertMessage"]$</AlertMessageId>
            <AlertParameters />
            <Suppression />
          </WriteAction>
        </WriteActions>
      </Rule>
    </Rules>
  </Monitoring>
  <Presentation>
    <StringResources>
      <StringResource ID="MyMp.Rule.EventDescriptionMatches.AlertMessage"/>
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="MyMp.Rule.EventDescriptionMatches">
          <Name>Event Description Match Alert Rule</Name>
        </DisplayString>
        <DisplayString ElementID="MyMp.Rule.EventDescriptionMatches.AlertMessage">
          <Name>Event Description Match</Name>
          <Description>Event description match pattern specified in rule configuration.</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPackFragment>

 

 

 

 

__