<ManagementPack ContentReadable="true" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>MPAuthor.DiagnosticAndRecovery</ID>
      <Version>1.0.0.1</Version>
    </Identity>
    <Name>MPAuthor.DiagnosticAndRecovery</Name>
    <References>
      <Reference Alias="DW">
        <ID>Microsoft.SystemCenter.DataWarehouse.Library</ID>
        <Version>6.1.7221.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="SC">
        <ID>Microsoft.SystemCenter.Library</ID>
        <Version>6.1.7221.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="MPAuthor.DiagnosticAndRecovery.Target" Accessibility="Internal" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false" />
      </ClassTypes>
    </EntityTypes>
  </TypeDefinitions>
  <Monitoring>
    <Discoveries>
      <Discovery ID="MPAuthor.DiagnosticAndRecovery.Discovery.TargetClass" Enabled="true" Target="Windows!Microsoft.Windows.OperatingSystem" ConfirmDelivery="false" Remotable="true" Priority="Normal">
        <Category>Discovery</Category>
        <DiscoveryTypes>
          <DiscoveryClass TypeID="MPAuthor.DiagnosticAndRecovery.Target" />
        </DiscoveryTypes>
        <DataSource ID="DS" TypeID="Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider">
          <ComputerName>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/NetworkName$</ComputerName>
          <RegistryAttributeDefinitions>
            <RegistryAttributeDefinition>
              <AttributeName>AppExists</AttributeName>
              <Path>SOFTWARE\MPAuthor\DiagnosticAndRecovery</Path>
              <PathType>0</PathType>
              <AttributeType>0</AttributeType>
            </RegistryAttributeDefinition>
          </RegistryAttributeDefinitions>
          <Frequency>120</Frequency>
          <ClassId>$MPElement[Name="MPAuthor.DiagnosticAndRecovery.Target"]$</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/AppExists</XPathQuery>
              </ValueExpression>
              <Operator>Equal</Operator>
              <ValueExpression>
                <Value Type="String">True</Value>
              </ValueExpression>
            </SimpleExpression>
          </Expression>
        </DataSource>
      </Discovery>
    </Discoveries>
    <Monitors>
      <UnitMonitor ID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" Accessibility="Internal" Enabled="true" Target="MPAuthor.DiagnosticAndRecovery.Target" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="Windows!Microsoft.Windows.CheckNTServiceStateMonitorType" ConfirmDelivery="false">
        <Category>AvailabilityHealth</Category>
        <AlertSettings AlertMessage="MPAuthor.DiagnosticAndRecovery.ServiceMonitor_AlertMessageResourceID">
          <AlertOnState>Error</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>Error</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Data/Context/Property[@Name='Name']$</AlertParameter1>
          </AlertParameters>
        </AlertSettings>
        <OperationalStates>
          <OperationalState ID="Running" MonitorTypeStateID="Running" HealthState="Success" />
          <OperationalState ID="NotRunning" MonitorTypeStateID="NotRunning" HealthState="Error" />
        </OperationalStates>
        <Configuration>
          <ComputerName />
          <ServiceName>wmiApSrv</ServiceName>
          <CheckStartupType />
        </Configuration>
      </UnitMonitor>
    </Monitors>
    <Diagnostics>
      <Diagnostic ID="MPAuthor.DiagnosticAndRecovery.Diagnostic.PowerShell" Accessibility="Internal" Enabled="false" Target="MPAuthor.DiagnosticAndRecovery.Target" Monitor="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" ExecuteOnState="Error" Remotable="true" Timeout="300">
        <Category>Custom</Category>
        <ProbeAction ID="PSScript" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagProbe">
          <ScriptName>GetErrorCode.ps1</ScriptName>
          <ScriptBody><![CDATA[
param($computerName,$serviceName)

$errorCode = (get-itemProperty -path hklm:\SOFTWARE\MPAuthor\DiagnosticAndRecovery).ErrorCode

$api = new-object -comObject 'MOM.ScriptAPI'
$api.LogScriptEvent('GetErrorCode.vbs',515,4,'Running diagnostic.' + 'Computer: ' + $computerName + "`r`nService: " + $serviceName)

$errorCode = (get-itemProperty -path hklm:\SOFTWARE\MPAuthor\DiagnosticAndRecovery).ErrorCode

$bag = $api.CreatePropertyBag()
$bag.AddValue('ComputerName',$computerName)
$bag.AddValue('ServiceName',$serviceName)
$bag.AddValue('ErrorCode',$errorCode)

$bag
  ]]></ScriptBody>
          <Parameters>
            <Parameter>
              <Name>computerName</Name>
              <Value>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Value>
            </Parameter>
            <Parameter>
              <Name>serviceName</Name>
              <Value>$Data/StateChange/DataItem/Context/DataItem/Property[@Name='Name']$</Value>
            </Parameter>
          </Parameters>
          <TimeoutSeconds>60</TimeoutSeconds>
        </ProbeAction>
      </Diagnostic>
      <Diagnostic ID="MPAuthor.DiagnosticAndRecovery.Diagnostic.VBScript" Accessibility="Internal" Enabled="true" Target="MPAuthor.DiagnosticAndRecovery.Target" Monitor="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" ExecuteOnState="Error" Remotable="true" Timeout="300">
        <Category>Custom</Category>
        <ProbeAction ID="VBScript" TypeID="Windows!Microsoft.Windows.ScriptPropertyBagProbe">
          <ScriptName>GetErrorCode.vbs</ScriptName>
          <Arguments>$Target/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$ $Data/StateChange/DataItem/Context/DataItem/Property[@Name='Name']$</Arguments>
          <ScriptBody><![CDATA[
const HKEY_LOCAL_MACHINE = &H80000002

Set oAPI = CreateObject("MOM.ScriptAPI")

sComputerName = WScript.Arguments(0)
sServiceName = WScript.Arguments(1)

Set oAPI = CreateObject("MOM.ScriptAPI")
oAPI.LogScriptEvent "GetErrorCode.vbs",515,4,"Running diagnostic." & vbCrLf & "Computer: " & sComputerName & vbCrLf & "Service: " & sServiceName 

Set oReg=GetObject("winmgmts:\\" & sComputerName & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\MPAuthor\DiagnosticAndRecovery"
strValueName = "ErrorCode"
oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,sValue

Set oBag = oAPI.CreatePropertyBag
oBag.AddValue "ComputerName",sComputerName
oBag.AddValue "ServiceName",sServiceName
oBag.AddValue "ErrorCode",sValue
oAPI.Return(oBag)
  ]]></ScriptBody>
          <TimeoutSeconds>60</TimeoutSeconds>
        </ProbeAction>
      </Diagnostic>
    </Diagnostics>
    <Recoveries>
      <Recovery ID="MPAuthor.DiagnosticAndRecovery.Recovery.PowerShell" Accessibility="Internal" Enabled="true" Target="MPAuthor.DiagnosticAndRecovery.Target" Monitor="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" ResetMonitor="true" ExecuteOnDiagnostic="MPAuthor.DiagnosticAndRecovery.Diagnostic.PowerShell" Remotable="true" Timeout="300">
        <Category>Custom</Category>
        <ConditionDetection ID="FilterOnErrorCode" TypeID="System!System.ExpressionFilter">
          <Expression>
            <SimpleExpression>
              <ValueExpression>
                <XPathQuery Type="String">Diagnostic/DataItem/Property[@Name='ErrorCode']</XPathQuery>
              </ValueExpression>
              <Operator>Equal</Operator>
              <ValueExpression>
                <Value Type="String">3</Value>
              </ValueExpression>
            </SimpleExpression>
          </Expression>
        </ConditionDetection>
        <WriteAction ID="PSScript" TypeID="Windows!Microsoft.Windows.PowerShellWriteAction">
          <ScriptName>StartService.ps1</ScriptName>
          <ScriptBody>
param($computerName,$serviceName)

$service = get-service -name $serviceName 
$service.start()
$service.WaitForStatus('Running',(new-timespan -seconds 10))

if ($service.Status -eq 'Running') 
	{write-host "Service $serviceName started successfully."}
else
	{write-host "Service $serviceName could not be started."}
	</ScriptBody>
          <Parameters>
            <Parameter>
              <Name>serviceName</Name>
              <Value>$Data/Diagnostic/DataItem/Property[@Name='ServiceName']$</Value>
            </Parameter>
          </Parameters>
          <TimeoutSeconds>300</TimeoutSeconds>
        </WriteAction>
      </Recovery>
      <Recovery ID="MPAuthor.DiagnosticAndRecovery.Recovery.VBScript" Accessibility="Internal" Enabled="true" Target="MPAuthor.DiagnosticAndRecovery.Target" Monitor="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" ResetMonitor="true" ExecuteOnDiagnostic="MPAuthor.DiagnosticAndRecovery.Diagnostic.VBScript" Remotable="true" Timeout="300">
        <Category>Custom</Category>
        <ConditionDetection ID="FilterOnErrorCode" TypeID="System!System.ExpressionFilter">
          <Expression>
            <SimpleExpression>
              <ValueExpression>
                <XPathQuery Type="String">Diagnostic/DataItem/Property[@Name='ErrorCode']</XPathQuery>
              </ValueExpression>
              <Operator>Equal</Operator>
              <ValueExpression>
                <Value Type="String">3</Value>
              </ValueExpression>
            </SimpleExpression>
          </Expression>
        </ConditionDetection>
        <WriteAction ID="VBScript" TypeID="Windows!Microsoft.Windows.ScriptWriteAction">
          <ScriptName>StartService.vbs</ScriptName>
          <Arguments>$Data/Diagnostic/DataItem/Property[@Name='ComputerName']$ $Data/Diagnostic/DataItem/Property[@Name='ServiceName']$</Arguments>
          <ScriptBody><![CDATA[sComputerName = WScript.Arguments(0)
sServiceName = WScript.Arguments(1)

Set oAPI = CreateObject("MOM.ScriptAPI")
oAPI.LogScriptEvent "StartService.vbs",516,4,"Running recovery." & vbCrLf & "Computer: " & sComputerName & vbCrLf & "Service: " & sServiceName 

Set oWMI = GetObject("winmgmts:\\" & sComputerName & "\root\cimv2")
Set cServices = oWMI.ExecQuery("Select * from Win32_Service Where Name ='" & sServiceName & "' ")

For Each oService in cServices
	iReturn = oService.StartService()
Next

If iReturn = 0 Then
	WScript.Echo "Service " & sServiceName & " started successfully."
Else
	WScript.Echo "Service " & sServiceName & " could not be started. Error code: " & iReturn
End If]]></ScriptBody>
          <TimeoutSeconds>300</TimeoutSeconds>
        </WriteAction>
      </Recovery>
    </Recoveries>
  </Monitoring>
  <Presentation>
    <Views>
      <View ID="MPAuthor.DiagnosticAndRecovery.View.TargetClass" Accessibility="Internal" Enabled="true" Target="MPAuthor.DiagnosticAndRecovery.Target" TypeID="SC!Microsoft.SystemCenter.StateViewType" Visible="true">
        <Category>StateCollection</Category>
        <Criteria />
      </View>
    </Views>
    <Folders>
      <Folder ID="MPAuthor.DiagnosticAndRecovery.Folder" Accessibility="Internal" ParentFolder="SC!Microsoft.SystemCenter.Monitoring.ViewFolder.Root" />
    </Folders>
    <FolderItems>
      <FolderItem ElementID="MPAuthor.DiagnosticAndRecovery.View.TargetClass" Folder="MPAuthor.DiagnosticAndRecovery.Folder" />
    </FolderItems>
    <StringResources>
      <StringResource ID="AlertMessageID3c3f53bd716449f58e793397c3a79f5b" />
      <StringResource ID="MPAuthor.DiagnosticAndRecovery.Monitor.FileSize_AlertMessageResourceID" />
      <StringResource ID="MPAuthor.DiagnosticAndRecovery.Monitor.Script_AlertMessageResourceID" />
      <StringResource ID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor_AlertMessageResourceID" />
      <StringResource ID="MPAuthor.DiagnosticAndRecovery.SimpleEventAlert.AlertMessage" />
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery">
          <Name>MPAuthor Sample - Property Bag</Name>
          <Description>This management pack provides an example of a recovery running after a diagnostic.  The recovery only runs if specific criteria is received from the diagnostic output.  It also illustrates how to pass property bag data from the monitor to the diagnostic and the recovery.

In this example, the diagnostic runs in response to a service monitor.  If the specified service is stopped, then the diagnostic runs.  The service used is the WMI Performance Adapter (WmiApSrv), but this can be changed in the properties of the monitor.  The diagnostic runs a script that collects an error code value from the registry at HKLM\SOFTWARE\MPAuthor\DiagnosticAndRecovery\ErrorCode.  If the error code is 3, then the recovery will run.  If it is any other value, the recovery will not run.  The recovery is a script that restarts the service.

A sample diagnostic and recovery are provided for both VBScript and PowerShell.  The functionality of each are identical and only one of the diagnostics should be enabled at a time.  

The monitor is targeted at a class called MPAuthor.DiagnosticAndRecovery.Target.  This is discovered by creating a registry key at HKLM\SOFTWARE\MPAuthor\DiagnosticAndRecovery. This registry key must be on the same agent computer with the service being monitored.</Description>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Diagnostic.PowerShell">
          <Name>PowerShell Diagnostic</Name>
          <Description />
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Diagnostic.VBScript">
          <Name>VBScript Diagnostic</Name>
          <Description />
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Discovery.TargetClass">
          <Name>MPAuthor Discover PropertyBag Target Class</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Folder">
          <Name>MPAuthor Sample Diagnostic and Recovery</Name>
          <Description />
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Monitor.FileSize_AlertMessageResourceID">
          <Name>File size</Name>
          <Description>Please see the alert context for details.</Description>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Monitor.Script_AlertMessageResourceID">
          <Name>Script Monitor</Name>
          <Description>{0}</Description>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Recovery.PowerShell">
          <Name>PowerShell Recovery</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Recovery.VBScript">
          <Name>VBScript Recovery</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor">
          <Name>Service Monitor</Name>
          <Description />
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" SubElementID="NotRunning">
          <Name>NotRunning</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor" SubElementID="Running">
          <Name>Running</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.ServiceMonitor_AlertMessageResourceID">
          <Name>Service Monitor</Name>
          <Description>{0}</Description>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.Target">
          <Name>MPAuthor DiagnosticAndRecovery Target</Name>
        </DisplayString>
        <DisplayString ElementID="MPAuthor.DiagnosticAndRecovery.View.TargetClass">
          <Name>DiagnosticAndRecovery Target</Name>
          <Description />
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>
