URL Monitoring Part IV–Getting More Advanced

 

This entry is a continuation of the following series:

URL Monitoring Part I – The Design
URL Monitoring Part II – The Classes and Discoveries
URL Monitoring Part III – The Monitors
URL Monitoring Part IV – Getting More Advanced
URL Monitoring Part V – Monitoring URLs from a Resource Pool

After my initial posts on URL monitoring I received various feedback but there are two questions that I continually receive, so I decided to address those.

  1. Is there a way to only alert if the website has been down for a specified amount of time?
  2. I don’t want to have to administer all of the settings in the registry of the watchers, can I just use a spreadsheet or database instead?

I addressed both of these questions in a new example management pack.  The new MP is designed to discover websites, along with the configuration settings you specify, based on a CSV file.  The configuration settings that are possible in the CSV are as follows:

  • The URL you want to monitor (one row per instance)
  • The Watcher Node you want to monitor this URL
  • A string you want to look for on the website
  • The maximum response time that you find acceptable
  • How often you want to check this website (in seconds)
  • The number of times you want to check this website before turning the monitor critical
  • The time window in which you want to look for consecutive failures
    • Example: You check a website every 30 seconds.  You want to alert if it is deemed “Slow”, ”Down”, or ”Missing Content” after 2 minutes.  You would specify 30 seconds for your check interval, 4 for the number of times you want to check the site, and 120 seconds for your time window.

To Test this Management Pack in your lab:

  1. Copy the attached CSV file to a share that all the watcher’s computer accounts can access or change the website discovery to use a runas account that has access to that share.  Three of the URLs in the CSV are meant to turn critical so keep this in mind when you import if you use what I’ve provided for testing.  For your reference, here is the format of the CSV file: URL,WatcherFQDN,ContentMatchString,MaxResponseTime,MonitoringIntervalInSeconds,AttemptsBeforeTurningRed,TimeWindowInSeconds
  2. Open the attached management pack in the authoring console or your favorite XML editor and change the “Discover Websites Discovery” UNCPathToCSVFile property to the correct path of the CSV file.
  3. Add the HKLM\Software\WebsiteWatcher registry KEY (not value) to the registry of the machines that you want to be watcher nodes.
  4. Modify the CSV to use the FQDN of the watchers you want to test with (they should be the same ones you modified the registry on).
  5. Import the Management Pack into your lab.

I will cover each part of the MP design below:

Classes

There are two classes in this management pack.  One is just for the watcher nodes and the other is for the websites.  There is also a relationship to make the watchers host the websites.

Discoveries

The watcher discovery targets all Windows Servers and looks for a registry key (HKLM\Software\WebsiteWatcher).  If that key exists then an instance of the website watcher class is created.  The website discovery is targeted at the website watcher class.  This discovery is script based and reads a CSV and based on what it finds it creates instances of the Website class hosted by the applicable watcher.

Data Sources

There are 4 data sources: One for the website discovery and 3 for each type of website monitoring you want to do (up/down, content, and response time).  I will admit that I could likely use a single data source and make these 3 requests cook down but I was limited on time so I created 3 separate data sources.  If the watcher needs to scale to a large amount of websites then I would suggest attempting the single data source route and investigating cook down.  One note, if a website is down then the content and response monitors will stay healthy so only one alert will be generated.

Monitor Types

There are 3 monitor types, one for each data source.  The monitor types contain the consolidator module which is used to provide the “don’t turn red until x number of failures have occurred in x amount of time” functionality.

Monitors

There are 3 monitors, one for each monitor type.  All of the configuration for these is provided from discovered data.

**If you find any issues with the MP or have any feedback please let me know so I can update this example.

The XML of the MP:

<ManagementPack ContentReadable="true" xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>Custom.Example.WebsiteWatcher</ID>
      <Version>1.0.0.0</Version>
    </Identity>
    <Name>Custom.Example.WebsiteWatcher</Name>
    <References>
      <Reference Alias="SC">
        <ID>Microsoft.SystemCenter.Library</ID>
        <Version>6.1.7221.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Web">
        <ID>Microsoft.SystemCenter.WebApplication.Library</ID>
        <Version>6.0.6278.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Windows">
        <ID>Microsoft.Windows.Library</ID>
        <Version>6.1.7221.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Health">
        <ID>System.Health.Library</ID>
        <Version>6.1.7221.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>6.1.7221.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Custom.Example.WebsiteWatcher.Class.Website" Accessibility="Public" Abstract="false" Base="System!System.Perspective" Hosted="true" Singleton="false">
          <Property ID="URL" Type="string" Key="true" CaseSensitive="false" Length="512" MinLength="0" />
          <Property ID="ContentMatchString" Type="string" Key="false" CaseSensitive="false" Length="255" MinLength="0" />
          <Property ID="MaxResponseTime" Type="decimal" Key="false" CaseSensitive="false" Length="38" MinLength="0" />
          <Property ID="MonitoringIntervalInSeconds" Type="int" Key="false" CaseSensitive="false" Length="256" MinLength="0" />
          <Property ID="TimeWindowInSeconds" Type="int" Key="false" CaseSensitive="false" Length="256" MinLength="0" />
          <Property ID="AttemptsBeforeTurningRed" Type="int" Key="false" CaseSensitive="false" Length="256" MinLength="0" />
        </ClassType>
        <ClassType ID="Custom.Example.WebsiteWatcher.Class.WebsiteWatcher" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.LocalApplication" Hosted="true" Singleton="false" />
      </ClassTypes>
      <RelationshipTypes>
        <RelationshipType ID="Custom.Example.WebsiteWatcher.Relationship.WebsiteWatcherHostsWebsite" Accessibility="Public" Abstract="false" Base="System!System.Hosting">
          <Source>Custom.Example.WebsiteWatcher.Class.WebsiteWatcher</Source>
          <Target>Custom.Example.WebsiteWatcher.Class.Website</Target>
        </RelationshipType>
      </RelationshipTypes>
    </EntityTypes>
    <ModuleTypes>
      <DataSourceModuleType ID="Custom.Example.WebsiteWatcher.DataSource.DiscoverWebsites" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="UNCPathToCSVFile" type="xsd:string" />
        </Configuration>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="DS" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalInSeconds$</Interval>
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Probe" TypeID="Windows!Microsoft.Windows.ScriptDiscoveryProbe">
                <ScriptName>DiscoverWebsites.vbs</ScriptName>
                <Arguments>$Config/UNCPathToCSVFile$</Arguments>
                <ScriptBody><![CDATA[
'Arg1 = UNC Path to CSV file
'CSV Format:
'URL,WatcherFQDN,ContentMatchString,MaxResponseTime,MonitoringIntervalInSeconds,AttemptsBeforeTurningRed,TimeWindowInSeconds

Set oArgs = Wscript.Arguments
sCSV = UCase(oArgs(0))

WScript.Echo "Creating Discovery Data"
Set oAPI = CreateObject("MOM.ScriptAPI")
Set oDiscoveryData = oAPI.CreateDiscoveryData(0,"$MPElement$", "$Target/Id$")

WScript.Echo "Opening CSV"
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oCSV = oFSO.OpenTextFile(sCSV)

WScript.Echo "Reading CSV"
Do While Not oCSV.AtEndOfStream
  aRow = split(oCSV.ReadLine, ",")
 
  'Read the watcher column to see if it matches
  If ucase(aRow(1)) = ucase("$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$") Then
    WScript.Echo "We have a match, creating discovery data"
Set oWebsite = oDiscoveryData.CreateClassInstance("$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']$")
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/URL$", aRow(0)
oWebsite.AddProperty "$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", "$Target/Host/Property[Type='Windows!Microsoft.Windows.Computer']/PrincipalName$"
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/ContentMatchString$", aRow(2)
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/MaxResponseTime$", aRow(3)
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/MonitoringIntervalInSeconds$", aRow(4)
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/TimeWindowInSeconds$", aRow(6)
oWebsite.AddProperty "$MPElement[Name='Custom.Example.WebsiteWatcher.Class.Website']/AttemptsBeforeTurningRed$", aRow(5)
oWebsite.AddProperty "$MPElement[Name='System!System.Entity']/DisplayName$", aRow(0)
    oDiscoveryData.AddInstance(oWebsite)
  End If
Loop

Call oAPI.Return(oDiscoveryData)
    ]]></ScriptBody>
                <TimeoutSeconds>300</TimeoutSeconds>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="DS" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.Discovery.Data</OutputType>
      </DataSourceModuleType>
      <DataSourceModuleType ID="Custom.Example.WebsiteWatcher.DataSource.WebsiteAvailability" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
        </Configuration>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="DS" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalInSeconds$</Interval>
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Probe" TypeID="Web!Microsoft.SystemCenter.WebApplication.UrlProbe">
                <Proxy />
                <ProxyUserName />
                <ProxyPassword />
                <ProxyAuthenticationScheme>None</ProxyAuthenticationScheme>
                <CredentialUserName />
                <CredentialPassword />
                <AuthenticationScheme>None</AuthenticationScheme>
                <FollowRedirects>true</FollowRedirects>
                <RetryCount>0</RetryCount>
                <RequestTimeout>60</RequestTimeout>
                <Requests>
                  <Request>
                    <RequestID>1</RequestID>
                    <URL>$Config/URL$</URL>
                    <Verb>GET</Verb>
                    <Version>HTTP/1.1</Version>
                    <HttpHeaders>
                      <HttpHeader>
                        <Name>User-Agent</Name>
                        <Value>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)</Value>
                      </HttpHeader>
                    </HttpHeaders>
                    <Body />
                    <CheckContentChange>false</CheckContentChange>
                    <ContentHash>00000000-0000-0000-0000-000000000000</ContentHash>
                    <Depth>0</Depth>
                    <ThinkTime>0</ThinkTime>
                    <CheckInternalLinks>false</CheckInternalLinks>
                    <CheckExternalLinks>false</CheckExternalLinks>
                    <CheckResources>true</CheckResources>
                    <RequestEvaluationCriteria>
                      <StopProcessingIfWarningCriteriaIsMet>false</StopProcessingIfWarningCriteriaIsMet>
                      <StopProcessingIfErrorCriteriaIsMet>false</StopProcessingIfErrorCriteriaIsMet>
                      <BasePageEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria>
                          <NumericCriteriaExpressions>
                            <NumericCriteriaExpression>
                              <NumericRequestMetric>BasePageData/StatusCode</NumericRequestMetric>
                              <Operator>GreaterEqual</Operator>
                              <Value>400</Value>
                            </NumericCriteriaExpression>
                          </NumericCriteriaExpressions>
                        </ErrorCriteria>
                      </BasePageEvaluationCriteria>
                      <LinksEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </LinksEvaluationCriteria>
                      <ResourcesEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </ResourcesEvaluationCriteria>
                      <WebPageTotalEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </WebPageTotalEvaluationCriteria>
                      <DepthEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </DepthEvaluationCriteria>
                    </RequestEvaluationCriteria>
                    <FormsAuthCredentials />
                  </Request>
                </Requests>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="DS" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>Web!Microsoft.SystemCenter.WebApplication.WebApplicationData</OutputType>
      </DataSourceModuleType>
      <DataSourceModuleType ID="Custom.Example.WebsiteWatcher.DataSource.WebsiteContent" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
          <xsd:element minOccurs="1" name="ContentMatchString" type="xsd:string" />
        </Configuration>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="DS" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalInSeconds$</Interval>
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Probe" TypeID="Web!Microsoft.SystemCenter.WebApplication.UrlProbe">
                <Proxy />
                <ProxyUserName />
                <ProxyPassword />
                <ProxyAuthenticationScheme>None</ProxyAuthenticationScheme>
                <CredentialUserName />
                <CredentialPassword />
                <AuthenticationScheme>None</AuthenticationScheme>
                <FollowRedirects>true</FollowRedirects>
                <RetryCount>0</RetryCount>
                <RequestTimeout>60</RequestTimeout>
                <Requests>
                  <Request>
                    <RequestID>1</RequestID>
                    <URL>$Config/URL$</URL>
                    <Verb>GET</Verb>
                    <Version>HTTP/1.1</Version>
                    <HttpHeaders>
                      <HttpHeader>
                        <Name>User-Agent</Name>
                        <Value>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)</Value>
                      </HttpHeader>
                    </HttpHeaders>
                    <Body />
                    <CheckContentChange>false</CheckContentChange>
                    <ContentHash>00000000-0000-0000-0000-000000000000</ContentHash>
                    <Depth>0</Depth>
                    <ThinkTime>0</ThinkTime>
                    <CheckInternalLinks>false</CheckInternalLinks>
                    <CheckExternalLinks>false</CheckExternalLinks>
                    <CheckResources>false</CheckResources>
                    <RequestEvaluationCriteria>
                      <StopProcessingIfWarningCriteriaIsMet>false</StopProcessingIfWarningCriteriaIsMet>
                      <StopProcessingIfErrorCriteriaIsMet>false</StopProcessingIfErrorCriteriaIsMet>
                      <BasePageEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria>
                          <ContentMatchCriteria>
                            <RegExOperator>DoesNotContainSubstring</RegExOperator>
                            <Value>$Config/ContentMatchString$</Value>
                          </ContentMatchCriteria>
                        </ErrorCriteria>
                      </BasePageEvaluationCriteria>
                      <LinksEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </LinksEvaluationCriteria>
                      <ResourcesEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </ResourcesEvaluationCriteria>
                      <WebPageTotalEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </WebPageTotalEvaluationCriteria>
                      <DepthEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </DepthEvaluationCriteria>
                    </RequestEvaluationCriteria>
                    <FormsAuthCredentials />
                  </Request>
                </Requests>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="DS" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>Web!Microsoft.SystemCenter.WebApplication.WebApplicationData</OutputType>
      </DataSourceModuleType>
      <DataSourceModuleType ID="Custom.Example.WebsiteWatcher.DataSource.WebsitePerformance" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
          <xsd:element minOccurs="1" name="MaximumResponseTime" type="xsd:decimal" />
        </Configuration>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <DataSource ID="DS" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalInSeconds$</Interval>
                  </SimpleReccuringSchedule>
                  <ExcludeDates />
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Probe" TypeID="Web!Microsoft.SystemCenter.WebApplication.UrlProbe">
                <Proxy />
                <ProxyUserName />
                <ProxyPassword />
                <ProxyAuthenticationScheme>None</ProxyAuthenticationScheme>
                <CredentialUserName />
                <CredentialPassword />
                <AuthenticationScheme>None</AuthenticationScheme>
                <FollowRedirects>true</FollowRedirects>
                <RetryCount>0</RetryCount>
                <RequestTimeout>60</RequestTimeout>
                <Requests>
                  <Request>
                    <RequestID>1</RequestID>
                    <URL>$Config/URL$</URL>
                    <Verb>GET</Verb>
                    <Version>HTTP/1.1</Version>
                    <HttpHeaders>
                      <HttpHeader>
                        <Name>User-Agent</Name>
                        <Value>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)</Value>
                      </HttpHeader>
                    </HttpHeaders>
                    <Body />
                    <CheckContentChange>false</CheckContentChange>
                    <ContentHash>00000000-0000-0000-0000-000000000000</ContentHash>
                    <Depth>0</Depth>
                    <ThinkTime>0</ThinkTime>
                    <CheckInternalLinks>false</CheckInternalLinks>
                    <CheckExternalLinks>false</CheckExternalLinks>
                    <CheckResources>false</CheckResources>
                    <RequestEvaluationCriteria>
                      <StopProcessingIfWarningCriteriaIsMet>false</StopProcessingIfWarningCriteriaIsMet>
                      <StopProcessingIfErrorCriteriaIsMet>false</StopProcessingIfErrorCriteriaIsMet>
                      <BasePageEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria>
                          <NumericCriteriaExpressions>
                            <NumericCriteriaExpression>
                              <NumericRequestMetric>BasePageData/TotalResponseTime</NumericRequestMetric>
                              <Operator>Greater</Operator>
                              <Value>$Config/MaximumResponseTime$</Value>
                            </NumericCriteriaExpression>
                          </NumericCriteriaExpressions>
                        </ErrorCriteria>
                      </BasePageEvaluationCriteria>
                      <LinksEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </LinksEvaluationCriteria>
                      <ResourcesEvaluationCriteria>
                        <WarningCriteria>
                          <StatusCodeCriteria>
                            <ListNumericRequestMetric>StatusCode</ListNumericRequestMetric>
                            <Operator>GreaterEqual</Operator>
                            <Value>400</Value>
                          </StatusCodeCriteria>
                        </WarningCriteria>
                        <ErrorCriteria />
                      </ResourcesEvaluationCriteria>
                      <WebPageTotalEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </WebPageTotalEvaluationCriteria>
                      <DepthEvaluationCriteria>
                        <WarningCriteria />
                        <ErrorCriteria />
                      </DepthEvaluationCriteria>
                    </RequestEvaluationCriteria>
                    <FormsAuthCredentials />
                  </Request>
                </Requests>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="DS" />
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>Web!Microsoft.SystemCenter.WebApplication.WebApplicationData</OutputType>
      </DataSourceModuleType>
    </ModuleTypes>
    <MonitorTypes>
      <UnitMonitorType ID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteAvailability" Accessibility="Public">
        <MonitorTypeStates>
          <MonitorTypeState ID="WebsiteUp" NoDetection="false" />
          <MonitorTypeState ID="WebsiteDown" NoDetection="false" />
        </MonitorTypeStates>
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
          <xsd:element minOccurs="1" name="AttemptsBeforeTurningRed" type="xsd:integer" />
          <xsd:element minOccurs="1" name="TimeWindowInSeconds" type="xsd:integer" />
        </Configuration>
        <MonitorImplementation>
          <MemberModules>
            <DataSource ID="DS" TypeID="Custom.Example.WebsiteWatcher.DataSource.WebsiteAvailability">
              <IntervalInSeconds>$Config/IntervalInSeconds$</IntervalInSeconds>
              <URL>$Config/URL$</URL>
            </DataSource>
            <ConditionDetection ID="CDUp" TypeID="System!System.ExpressionFilter">
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery Type="UnsignedInteger">RequestResults/RequestResult[@Id=1]/BasePageData/ErrorCode</XPathQuery>
                  </ValueExpression>
                  <Operator>Equal</Operator>
                  <ValueExpression>
                    <Value Type="UnsignedInteger">0</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="CDDown" TypeID="System!System.ExpressionFilter">
              <Expression>
                <SimpleExpression>
                  <ValueExpression>
                    <XPathQuery Type="UnsignedInteger">RequestResults/RequestResult[@Id=1]/BasePageData/ErrorCode</XPathQuery>
                  </ValueExpression>
                  <Operator>NotEqual</Operator>
                  <ValueExpression>
                    <Value Type="UnsignedInteger">0</Value>
                  </ValueExpression>
                </SimpleExpression>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="CDConsolidate" TypeID="System!System.ConsolidatorCondition">
              <Consolidator>
                <ConsolidationProperties />
                <TimeControl>
                  <WithinTimeSchedule>
                    <Interval>$Config/TimeWindowInSeconds$</Interval>
                  </WithinTimeSchedule>
                </TimeControl>
                <CountingCondition>
                  <Count>$Config/AttemptsBeforeTurningRed$</Count>
                  <CountMode>OnNewItemTestOutputRestart_OnTimerSlideByOne</CountMode>
                </CountingCondition>
              </Consolidator>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="WebsiteUp">
              <Node ID="CDUp">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="WebsiteDown">
              <Node ID="CDConsolidate">
                <Node ID="CDDown">
                  <Node ID="DS" />
                </Node>
              </Node>
            </RegularDetection>
          </RegularDetections>
        </MonitorImplementation>
      </UnitMonitorType>
      <UnitMonitorType ID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteContent" Accessibility="Public">
        <MonitorTypeStates>
          <MonitorTypeState ID="ContentFound" NoDetection="false" />
          <MonitorTypeState ID="ContentNotFound" NoDetection="false" />
        </MonitorTypeStates>
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="ContentMatchString" type="xsd:string" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
          <xsd:element minOccurs="1" name="AttemptsBeforeTurningRed" type="xsd:integer" />
          <xsd:element minOccurs="1" name="TimeWindowInSeconds" type="xsd:integer" />
        </Configuration>
        <MonitorImplementation>
          <MemberModules>
            <DataSource ID="DS" TypeID="Custom.Example.WebsiteWatcher.DataSource.WebsiteContent">
              <IntervalInSeconds>$Config/IntervalInSeconds$</IntervalInSeconds>
              <URL>$Config/URL$</URL>
              <ContentMatchString>$Config/ContentMatchString$</ContentMatchString>
            </DataSource>
            <ConditionDetection ID="CDFound" TypeID="Web!Microsoft.SystemCenter.WebApplication.OKCriteriaMatch">
              <DataItemEvaluationQuery>RequestResults/RequestResult[@Id=1]/BasePageData/ResponseBodyEvalResult</DataItemEvaluationQuery>
            </ConditionDetection>
            <ConditionDetection ID="CDNotFound" TypeID="Web!Microsoft.SystemCenter.WebApplication.ErrorCriteriaMatch">
              <DataItemEvaluationQuery>RequestResults/RequestResult[@Id=1]/BasePageData/ResponseBodyEvalResult</DataItemEvaluationQuery>
            </ConditionDetection>
            <ConditionDetection ID="CDConsolidate" TypeID="System!System.ConsolidatorCondition">
              <Consolidator>
                <ConsolidationProperties />
                <TimeControl>
                  <WithinTimeSchedule>
                    <Interval>$Config/TimeWindowInSeconds$</Interval>
                  </WithinTimeSchedule>
                </TimeControl>
                <CountingCondition>
                  <Count>$Config/AttemptsBeforeTurningRed$</Count>
                  <CountMode>OnNewItemTestOutputRestart_OnTimerSlideByOne</CountMode>
                </CountingCondition>
              </Consolidator>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="ContentFound">
              <Node ID="CDFound">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="ContentNotFound">
              <Node ID="CDConsolidate">
                <Node ID="CDNotFound">
                  <Node ID="DS" />
                </Node>
              </Node>
            </RegularDetection>
          </RegularDetections>
        </MonitorImplementation>
      </UnitMonitorType>
      <UnitMonitorType ID="Custom.Example.WebsiteWatcher.MonitorType.WebsitePerformance" Accessibility="Public">
        <MonitorTypeStates>
          <MonitorTypeState ID="WebsiteFast" NoDetection="false" />
          <MonitorTypeState ID="WebsiteSlow" NoDetection="false" />
        </MonitorTypeStates>
        <Configuration>
          <xsd:element minOccurs="1" name="IntervalInSeconds" type="xsd:integer" />
          <xsd:element minOccurs="1" name="URL" type="xsd:string" />
          <xsd:element minOccurs="1" name="MaximumResponseTime" type="xsd:decimal" />
          <xsd:element minOccurs="1" name="AttemptsBeforeTurningRed" type="xsd:integer" />
          <xsd:element minOccurs="1" name="TimeWindowInSeconds" type="xsd:integer" />
        </Configuration>
        <MonitorImplementation>
          <MemberModules>
            <DataSource ID="DS" TypeID="Custom.Example.WebsiteWatcher.DataSource.WebsitePerformance">
              <IntervalInSeconds>$Config/IntervalInSeconds$</IntervalInSeconds>
              <URL>$Config/URL$</URL>
              <MaximumResponseTime>$Config/MaximumResponseTime$</MaximumResponseTime>
            </DataSource>
            <ConditionDetection ID="CDFast" TypeID="Web!Microsoft.SystemCenter.WebApplication.OKCriteriaMatch">
              <DataItemEvaluationQuery>RequestResults/RequestResult[@Id=1]/BasePageData/TotalResponseTimeEvalResult</DataItemEvaluationQuery>
            </ConditionDetection>
            <ConditionDetection ID="CDSlow" TypeID="Web!Microsoft.SystemCenter.WebApplication.ErrorCriteriaMatch">
              <DataItemEvaluationQuery>RequestResults/RequestResult[@Id=1]/BasePageData/TotalResponseTimeEvalResult</DataItemEvaluationQuery>
            </ConditionDetection>
            <ConditionDetection ID="CDConsolidate" TypeID="System!System.ConsolidatorCondition">
              <Consolidator>
                <ConsolidationProperties />
                <TimeControl>
                  <WithinTimeSchedule>
                    <Interval>$Config/TimeWindowInSeconds$</Interval>
                  </WithinTimeSchedule>
                </TimeControl>
                <CountingCondition>
                  <Count>$Config/AttemptsBeforeTurningRed$</Count>
                  <CountMode>OnNewItemTestOutputRestart_OnTimerSlideByOne</CountMode>
                </CountingCondition>
              </Consolidator>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="WebsiteFast">
              <Node ID="CDFast">
                <Node ID="DS" />
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="WebsiteSlow">
              <Node ID="CDConsolidate">
                <Node ID="CDSlow">
                  <Node ID="DS" />
                </Node>
              </Node>
            </RegularDetection>
          </RegularDetections>
        </MonitorImplementation>
      </UnitMonitorType>
    </MonitorTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="Custom.Example.WebsiteWatcher.Discovery.DiscoverWebsites" Enabled="true" Target="Custom.Example.WebsiteWatcher.Class.WebsiteWatcher" ConfirmDelivery="true" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="Custom.Example.WebsiteWatcher.Class.Website" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Custom.Example.WebsiteWatcher.DataSource.DiscoverWebsites">
          <IntervalInSeconds>86400</IntervalInSeconds>
          <UNCPathToCSVFile>\\myfileserver\myopenfileshare\URLMonitoringList.CSV</UNCPathToCSVFile>
        </DataSource>
      </Discovery>
      <Discovery ID="Custom.Example.WebsiteWatcher.Discovery.DiscoverWebsiteWatchers" Enabled="true" Target="Windows!Microsoft.Windows.Server.OperatingSystem" ConfirmDelivery="true" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="Custom.Example.WebsiteWatcher.Class.WebsiteWatcher" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider">
          <ComputerName>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
          <RegistryAttributeDefinitions>
            <RegistryAttributeDefinition>
              <AttributeName>isWatcher</AttributeName>
              <Path>Software\WebsiteWatcher</Path>
              <PathType>0</PathType>
              <AttributeType>0</AttributeType>
            </RegistryAttributeDefinition>
          </RegistryAttributeDefinitions>
          <Frequency>86400</Frequency>
          <ClassId>$MPElement[Name="Custom.Example.WebsiteWatcher.Class.WebsiteWatcher"]$</ClassId>
          <InstanceSettings>
            <Settings>
              <Setting>
                <Name>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Name>
                <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
              </Setting>
              <Setting>
                <Name>$MPElement[Name="System!System.Entity"]/DisplayName$</Name>
                <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
              </Setting>
            </Settings>
          </InstanceSettings>
          <Expression>
            <SimpleExpression>
              <ValueExpression>
                <XPathQuery Type="String">Values/isWatcher</XPathQuery>
              </ValueExpression>
              <Operator>Equal</Operator>
              <ValueExpression>
                <Value Type="String">true</Value>
              </ValueExpression>
            </SimpleExpression>
          </Expression>
        </DataSource>
      </Discovery>
    </Discoveries>
    <Monitors>
      <UnitMonitor ID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability" Accessibility="Public" Enabled="true" Target="Custom.Example.WebsiteWatcher.Class.Website" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteAvailability" ConfirmDelivery="true">
        <Category>Alert</Category>
        <AlertSettings AlertMessage="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability_AlertMessageResourceID">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</AlertParameter1>
            <AlertParameter2>$Data/Context/Context/DataItem/RequestResults/RequestResult["1"]/BasePageData/ErrorCode$</AlertParameter2>
            <AlertParameter3>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</AlertParameter3>
            <AlertParameter4>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</AlertParameter4>
            <AlertParameter5>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AlertParameter5>
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="WebsiteUp" MonitorTypeStateID="WebsiteUp" HealthState="Success" />
          <OperationalState ID="WebsiteDown" MonitorTypeStateID="WebsiteDown" HealthState="Error" />
        </OperationalStates>
        <Configuration>
          <IntervalInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</IntervalInSeconds>
          <URL>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</URL>
          <AttemptsBeforeTurningRed>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AttemptsBeforeTurningRed>
          <TimeWindowInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</TimeWindowInSeconds>
        </Configuration>
      </UnitMonitor>
      <UnitMonitor ID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent" Accessibility="Public" Enabled="true" Target="Custom.Example.WebsiteWatcher.Class.Website" ParentMonitorID="Health!System.Health.ConfigurationState" Remotable="true" Priority="Normal" TypeID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteContent" ConfirmDelivery="true">
        <Category>Alert</Category>
        <AlertSettings AlertMessage="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent_AlertMessageResourceID">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</AlertParameter1>
            <AlertParameter2>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/ContentMatchString$</AlertParameter2>
            <AlertParameter3>$Data/Context/Context/DataItem/RequestResults/RequestResult["1"]/BasePageData/ResponseBodyEvalResult$</AlertParameter3>
            <AlertParameter4>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</AlertParameter4>
            <AlertParameter5>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</AlertParameter5>
            <AlertParameter6>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AlertParameter6>
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="ContentFound" MonitorTypeStateID="ContentFound" HealthState="Success" />
          <OperationalState ID="ContentNotFound" MonitorTypeStateID="ContentNotFound" HealthState="Error" />
        </OperationalStates>
        <Configuration>
          <IntervalInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</IntervalInSeconds>
          <ContentMatchString>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/ContentMatchString$</ContentMatchString>
          <URL>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</URL>
          <AttemptsBeforeTurningRed>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AttemptsBeforeTurningRed>
          <TimeWindowInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</TimeWindowInSeconds>
        </Configuration>
      </UnitMonitor>
      <UnitMonitor ID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance" Accessibility="Public" Enabled="true" Target="Custom.Example.WebsiteWatcher.Class.Website" ParentMonitorID="Health!System.Health.PerformanceState" Remotable="true" Priority="Normal" TypeID="Custom.Example.WebsiteWatcher.MonitorType.WebsitePerformance" ConfirmDelivery="true">
        <Category>Alert</Category>
        <AlertSettings AlertMessage="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance_AlertMessageResourceID">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</AlertParameter1>
            <AlertParameter2>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MaxResponseTime$</AlertParameter2>
            <AlertParameter3>$Data/Context/Context/DataItem/TransactionResponseTime$</AlertParameter3>
            <AlertParameter4>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</AlertParameter4>
            <AlertParameter5>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</AlertParameter5>
            <AlertParameter6>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AlertParameter6>
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="WebsiteFast" MonitorTypeStateID="WebsiteFast" HealthState="Success" />
          <OperationalState ID="WebsiteSlow" MonitorTypeStateID="WebsiteSlow" HealthState="Error" />
        </OperationalStates>
        <Configuration>
          <IntervalInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MonitoringIntervalInSeconds$</IntervalInSeconds>
          <URL>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/URL$</URL>
          <MaximumResponseTime>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/MaxResponseTime$</MaximumResponseTime>
          <AttemptsBeforeTurningRed>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/AttemptsBeforeTurningRed$</AttemptsBeforeTurningRed>
          <TimeWindowInSeconds>$Target/Property[Type="Custom.Example.WebsiteWatcher.Class.Website"]/TimeWindowInSeconds$</TimeWindowInSeconds>
        </Configuration>
      </UnitMonitor>
    </Monitors>
  </Monitoring>
  <Presentation>
    <StringResources>
      <StringResource ID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability_AlertMessageResourceID" />
      <StringResource ID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent_AlertMessageResourceID" />
      <StringResource ID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance_AlertMessageResourceID" />
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher">
          <Name>Website Watcher Example</Name>
          <Description>Example MP that discovers URLs from a spreadsheet and monitors them.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website">
          <Name>Website</Name>
          <Description>Websites monitored by OpsMgr</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website" SubElementID="AttemptsBeforeTurningRed">
          <Name>Attempts Before Turning Red</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website" SubElementID="ContentMatchString">
          <Name>Content Match String</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website" SubElementID="MaxResponseTime">
          <Name>Max Response Time</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website" SubElementID="MonitoringIntervalInSeconds">
          <Name>Monitoring Interval In Seconds</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.Website" SubElementID="TimeWindowInSeconds">
          <Name>Time Windows In Seconds</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Class.WebsiteWatcher">
          <Name>Website Watcher</Name>
          <Description>Agents used to monitor certain websites for availability and performance.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.DataSource.DiscoverWebsites">
          <Name>Discover Websites Data Source</Name>
          <Description>Contains the code required to read a CSV file and discover websites.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.DataSource.WebsiteAvailability">
          <Name>Website Availability Data Source</Name>
          <Description>Monitors the website to see if it is up or down.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.DataSource.WebsiteContent">
          <Name>Website Content Data Source</Name>
          <Description>Checks for a phrase on a website.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.DataSource.WebsitePerformance">
          <Name>Website Performance Data Source</Name>
          <Description>Monitors the response time of a website.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Discovery.DiscoverWebsites">
          <Name>Discover Websites Discovery</Name>
          <Description>Discovers websites from CSV file.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Discovery.DiscoverWebsiteWatchers">
          <Name>Discover Website Watchers Discovery</Name>
          <Description>Discovers which agents will be Website Watchers.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability">
          <Name>Website Availability Monitor</Name>
          <Description>Monitors whether a website is up or down.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability" SubElementID="WebsiteUp">
          <Name>WebsiteUp</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability" SubElementID="WebsiteDown">
          <Name>WebsiteDown</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteAvailability_AlertMessageResourceID">
          <Name>Website Unavailable</Name>
          <Description>URL: {0}

Error Code: {1}

Monitoring Interval In Seconds: {2}

Time Window In Seconds: {3}

Attempts Before Turning Red: {4}</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent">
          <Name>Website Content Monitor</Name>
          <Description>Checks for a string in the response from an http request.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent" SubElementID="ContentNotFound">
          <Name>ContentNotFound</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent" SubElementID="ContentFound">
          <Name>ContentFound</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsiteContent_AlertMessageResourceID">
          <Name>Website Content Not Found</Name>
          <Description>URL: {0}

Content String: {1}

Status Code: : {2}

Monitoring Interval: {3}

Time Window: {4}

Attempts Before Turning Red: {5}</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance">
          <Name>Website Performance Monitor</Name>
          <Description>Monitors the Performance of a Website.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance" SubElementID="WebsiteFast">
          <Name>WebsiteFast</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance" SubElementID="WebsiteSlow">
          <Name>WebsiteSlow</Name>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Monitor.WebsitePerformance_AlertMessageResourceID">
          <Name>Website Performance Slow</Name>
          <Description>URL: {0}

MaxResponseTime: {1}

Last Response Time: {2}

Monitoring Interval In Seconds: {3}

Time Window In Seconds: {4}

Attempts Before Alerting: {5}</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteAvailability">
          <Name>Website Availability Monitor Type</Name>
          <Description>Monitors the availability of a website.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.MonitorType.WebsiteContent">
          <Name>Website Content Monitor Type</Name>
          <Description>Checks a website for specific content.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.MonitorType.WebsitePerformance">
          <Name>Website Performance Monitor Type</Name>
          <Description>Monitors the response time of a website.</Description>
        </DisplayString>
        <DisplayString ElementID="Custom.Example.WebsiteWatcher.Relationship.WebsiteWatcherHostsWebsite">
          <Name>WebsiteWatcher Hosts Website Relationship</Name>
          <Description>Ties the discovered website to the watcher.</Description>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>

Custom.Example.WebsiteWatcher.zip