Help me understand why cookdown doesen't work

Hi. I’m creating a monitor where I want multi instance cookdown to work. I’m checking against azure monitor for alerts and matches the alert rule id I have in SCOM with what i get from alerts in AM. Now the only parameter apart from credentials I use in the ps script is subscription ID. I would assume that SCOM fired one script for each subscription, but it does it for all objects (azure monitor rules). I have attached the monitor, data source and PS. Powershell scripts grab all Azure Monitor rules in the particular subscription and checks/matches against the alerts.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <ModuleTypes>
      <DataSourceModuleType ID="ehrnst.AzureMonitor.AlertState.monitor.Datasource" Accessibility="Public">
        <Configuration>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:integer"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string"/>
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
          <OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
          <OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string"/>
        </OverrideableParameters>
        <ModuleImplementation>
          <Composite>
            <MemberModules>
              <DataSource ID="Scheduler" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalSeconds$</Interval>
                    <SyncTime>$Config/SyncTime$</SyncTime>
                  </SimpleReccuringSchedule>
                  <ExcludeDates/>
                </Scheduler>
              </DataSource>
              <ProbeAction ID="PS" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe">
                <ScriptName>Get-AzureMonitorAlerts.ps1</ScriptName>
                <ScriptBody>$IncludeFileContent/Rules and monitors/Scripts/Get-AzureMonitorAlerts.ps1$</ScriptBody>
                <SnapIns/>
                <Parameters>
                  <Parameter>
                    <Name>SourceID</Name>
                    <Value>$MPElement$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>ManagedEntityID</Name>
                    <Value>$Target/Id$</Value>
                  </Parameter>
                  <!--The secret and ID to partner center multi tenant app-->
                  <Parameter>
                    <Name>MultiTenantAppId</Name>
                    <Value>$RunAs[Name="ICSP!ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/UserName$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>MultiTenantAppSecret</Name>
                    <Value>$RunAs[Name="ICSP!ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/Password$</Value>
                  </Parameter>
                  <!--The customer tenant-->
                  <Parameter>
                    <Name>CustomerTenantId</Name>
                    <Value>$Target/Host/Host/Host/Property[Type="ICSP!ehrnst.Azure.CSPTenant.Class"]/TenantID$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>CustomerSubscriptionId</Name>
                    <Value>$Target/Host/Host/Property[Type="ICSP!ehrnst.Azure.CSPSubscription.Class"]/SubscriptionID$</Value>
                  </Parameter>
                  <!--RUNAS ACCOUNT PARAMETERS-->
                  <Parameter>
                    <Name>CSPUsername</Name>
                    <Value>$RunAs[Name="ICSP!ehrnst.Azure.CSP.Account.RunAsProfile"]/UserName$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>CSPPassword</Name>
                    <Value>$RunAs[Name="ICSP!ehrnst.Azure.CSP.Account.RunAsProfile"]/Password$</Value>
                  </Parameter>
                </Parameters>
                <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
                <StrictErrorHandling>true</StrictErrorHandling>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="PS">
                <Node ID="Scheduler"/>
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.PropertyBagData</OutputType>
      </DataSourceModuleType>
    </ModuleTypes>
    <MonitorTypes>
      <UnitMonitorType ID="ehrnst.AzureMonitor.AlertState" Accessibility="Internal">
        <MonitorTypeStates>
          <MonitorTypeState ID="Good"/>
          <MonitorTypeState ID="Bad"/>
        </MonitorTypeStates>
        <Configuration>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:int"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:int"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="MultitenantAppId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="MultitenantAppSecret" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CustomerTenantId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CustomerSubscriptionId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CSPUsername" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CSPPassword" type="xsd:string"/>
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" ParameterType="int" Selector="$Config/IntervalSeconds$"/>
          <OverrideableParameter ID="SyncTime" ParameterType="string" Selector="$Config/SyncTime$"/>
          <OverrideableParameter ID="TimeoutSeconds" ParameterType="int" Selector="$Config/TimeoutSeconds$"/>
        </OverrideableParameters>
        <MonitorImplementation>
          <MemberModules>
            <DataSource TypeID="ehrnst.AzureMonitor.AlertState.monitor.Datasource" ID="DS">
              <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
              <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
              <SyncTime>$Config/SyncTime$</SyncTime>
            </DataSource>
            <ConditionDetection ID="FilterGood" TypeID="System!System.ExpressionFilter">
              <Expression>
                <And>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="Integer">1</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="String">Property[@Name='Object']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="String">$Target/Property[Type="ehrnst.AzureMonitor.Rule.Class"]/RuleId$</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                </And>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="FilterBad" TypeID="System!System.ExpressionFilter">
              <Expression>
                <And>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="Integer">2</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="String">Property[@Name='Object']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="String">$Target/Property[Type="ehrnst.AzureMonitor.Rule.Class"]/RuleId$</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                </And>
              </Expression>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="Good">
              <Node ID="FilterGood">
                <Node ID="DS"/>
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="Bad">
              <Node ID="FilterBad">
                <Node ID="DS"/>
              </Node>
            </RegularDetection>
          </RegularDetections>
          <OnDemandDetections>
            <OnDemandDetection MonitorTypeStateID="Good">
              <Node ID="FilterGood">
                <Node ID="DS" />
              </Node>
            </OnDemandDetection>
            <OnDemandDetection MonitorTypeStateID="Bad">
              <Node ID="FilterBad">
                <Node ID="DS" />
              </Node>
            </OnDemandDetection>
          </OnDemandDetections>
        </MonitorImplementation>
      </UnitMonitorType>
    </MonitorTypes>
  </TypeDefinitions>
  <Monitoring>
    <Monitors>
      <UnitMonitor ID="ehrnst.AzureMonitor.AlertState.Monitor" Enabled="true" Target="ehrnst.AzureMonitor.Rule.Class" TypeID="ehrnst.AzureMonitor.AlertState" Accessibility="Public" ParentMonitorID="Health!System.Health.AvailabilityState">
        <Category>AvailabilityHealth</Category>
        <AlertSettings AlertMessage="ehrnst.AzureMonitor.AlertState.Monitor.Alert.Message">
          <AlertOnState>Warning</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>MatchMonitorHealth</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="ehrnst.AzureMonitor.Rule.Class"]/ResourceShortName$</AlertParameter1>
            <AlertParameter2>$Data/Context/Property[@Name='SignalType']$</AlertParameter2>
            <AlertParameter3>$Target/Property[Type="ehrnst.AzureMonitor.Rule.Class"]/AlertDescription$</AlertParameter3>
            <AlertParameter4>$Target/Property[Type="ehrnst.AzureMonitor.Rule.Class"]/ResourceId$</AlertParameter4>
            <AlertParameter5>$Data/Context/Property[@Name='Severity']$</AlertParameter5>
          </AlertParameters>
        </AlertSettings>

        <OperationalStates>
          <OperationalState ID="GoodCondition"  HealthState="Success"  MonitorTypeStateID="Good"/>
          <OperationalState ID="BadCondition" HealthState="Warning"  MonitorTypeStateID="Bad"/>
        </OperationalStates>

        <Configuration>
          <IntervalSeconds>302</IntervalSeconds>
          <SyncTime></SyncTime>
          <TimeoutSeconds>100</TimeoutSeconds>
          <MultitenantAppId>$RunAs[Name="ICSP!ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/UserName$</MultitenantAppId>
          <MultitenantAppSecret>$RunAs[Name="ICSP!ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/Password$</MultitenantAppSecret>
          <CustomerTenantId>$Target/Host/Host/Host/Property[Type="ICSP!ehrnst.Azure.CSPTenant.Class"]/TenantID$</CustomerTenantId>
          <CustomerSubscriptionId>$Target/Host/Host/Property[Type="ICSP!ehrnst.Azure.CSPSubscription.Class"]/SubscriptionID$</CustomerSubscriptionId>
          <CSPUsername>$RunAs[Name="ICSP!ehrnst.Azure.CSP.Account.RunAsProfile"]/UserName$</CSPUsername>
          <CSPPassword>$RunAs[Name="ICSP!ehrnst.Azure.CSP.Account.RunAsProfile"]/Password$</CSPPassword>

        </Configuration>

      </UnitMonitor>
    </Monitors>
  </Monitoring>
  <Presentation>
    <StringResources>
      <StringResource ID="ehrnst.AzureMonitor.AlertState.Monitor.Alert.Message" />
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="ehrnst.AzureMonitor.AlertState.Monitor">
          <Name>Azure Monitor Alert rule status monitor</Name>
          <Description>Checks azure monitor for current alerts and match with alert rules discovered. Uses endponint: https://docs.microsoft.com/en-us/rest/api/monitor/alertsmanagement/alerts/getall </Description>
        </DisplayString>
        <DisplayString ElementID="ehrnst.AzureMonitor.AlertState.Monitor" SubElementID="BadCondition">
          <Name>Bad Condition</Name>
        </DisplayString>
        <DisplayString ElementID="ehrnst.AzureMonitor.AlertState.Monitor" SubElementID="GoodCondition">
          <Name>Good Condition</Name>
        </DisplayString>
        <DisplayString ElementID="ehrnst.AzureMonitor.AlertState.Monitor.Alert.Message">
          <Name>Azure monitor alert triggered against {0}</Name>
          <Description>
            An alert in Azure Monitor targeting {3} fired.
            Please see alert description for more details:     
            {2}
          </Description>
        </DisplayString>
      </DisplayStrings>
      <KnowledgeArticles>
        <KnowledgeArticle ElementID="ehrnst.AzureMonitor.AlertState.Monitor" Visible="true">
          <MamlContent>
            <maml:section xmlns:maml="http://schemas.microsoft.com/maml/2004/10">
              <maml:title>Summary</maml:title>
              <maml:para>
                GEts all alerts within azure monitor and matches with the alert rules.
                Check the alert description for what may cause the error and use the Azure portal for further investigation.
              </maml:para>
            </maml:section>
            <maml:section xmlns:maml="http://schemas.microsoft.com/maml/2004/10">
              <maml:title>External</maml:title>
              <maml:para>
                ...
              </maml:para>
            </maml:section>
          </MamlContent>
        </KnowledgeArticle>
      </KnowledgeArticles>
    </LanguagePack>
  </LanguagePacks>

</ManagementPackFragment>

 

#=================================================================================
#  Checks the health of all resources
#=================================================================================
param ($SourceId, $ManagedEntityId, $CustomerTenantId, $MultiTenantAppId, $MultiTenantAppSecret, $CSPPassword, $CSPusername, $CustomerSubscriptionId )

#=================================================================================
# Constants section - modify stuff here:
# Gather script start time
$StartTime = Get-Date
$CustomerSubscriptionId = $CustomerSubscriptionId.ToLower()

# Assign script name variable for use in event logging
$ScriptName = "Get-AzureMonitorAlerts.ps1"
#=================================================================================

# Gather who the script is running as
$whoami = whoami

#Load the MOMScript API and discovery propertybag
$momapi = New-Object -comObject "Mom.ScriptAPI"  


#Log script event that we are starting task
$momapi.LogScriptEvent($ScriptName, 5322, 0, "Checking Azure monitor alerts.  Running as ($whoami) For customer, $CustomerTenantId using: $MultiTenantAppId, $CustomerSubscriptionId")

# Begin Main Script
#=================================================================================

function Get-AADAppUserToken {
    [CmdletBinding()]
    param (
        # Parameter help description
        [Parameter()]
        [string]
        $ClientId,

        # Parameter help description
        [Parameter()]
        [string]
        $ClientSecret,

        # Parameter help description
        [Parameter()]
        [string]
        $tenantId,

        # Parameter help description
        [Parameter()]
        [string]
        $username,

        # Parameter help description
        [Parameter(Mandatory)]
        [String]
        $password
    )

    $loginurl = "https://login.windows.net/$tenantId/oauth2/token"
    $Body = @{
        resource      = "https://management.core.windows.net/";
        grant_type    = "password";
        client_id     = $ClientId;
        username      = $username;
        password      = $Password;
        client_secret = $ClientSecret;
    }
    Return Invoke-RestMethod -Uri $loginurl -Method POST -Body $body
}

$ApiVersion = "2018-05-05"

$result = Get-AADAppUserToken -tenantId $CustomerTenantId -ClientID $MultitenantAppId -ClientSecret $MultiTenantAppSecret -username $CSPUsername -password $CSPPassword -Verbose

if ($result -eq $null) {
    $momapi.LogScriptEvent($ScriptName, 5322, 1, "Error. Failed to authenticate - terminating script" )
    break
}


$AuthKey = "Bearer " + ($result.access_token)
$authHeader = @{
    'Content-Type'  = 'application/json;charset=utf-8'
    'Accept'        = 'application/json;charset=utf-8'
    'Authorization' = $AuthKey
}

# get all alert rules and add them to a hash.

$rules = @{}
try {
    $metricUri = 'https://management.azure.com/subscriptions/' + $CustomerSubscriptionId + '/providers/Microsoft.insights/metricAlerts?api-version=2018-03-01'
    $metrics = (Invoke-RestMethod -method GET -Uri $metricUri -Headers $authHeader).value
    $classicUri = 'https://management.azure.com/subscriptions/' + $CustomerSubscriptionId + '/providers/Microsoft.insights/Alertrules?api-version=2016-03-01'
    $classics = (Invoke-RestMethod -method GET -Uri $classicUri -Headers $authHeader).value

    foreach ($metric in $metrics) {
        $rules.Add("$($metric.id)", "$($metric.properties.scopes)")
    }

    foreach ($classic in $classics) {
        $rules.Add("$($classic.id)", "$($classic.properties.condition.dataSource.resourceUri)")
    }
}

catch {
    write-error $_
}

#Get all alerts within subscription
$alertUri = 'https://management.azure.com/subscriptions/' + $CustomerSubscriptionId + '/providers/Microsoft.AlertsManagement/alerts?api-version=' + $ApiVersion
$Alerts = Invoke-RestMethod -method GET -Uri $alertUri -Headers $authHeader -Verbose
$count = $($alerts.value).Count
$momapi.LogScriptEvent($ScriptName, 5323, 0, "found $count alerts in sub: $CustomerSubscriptionId URI: $alertUri")

# iterate all rules and alerts to allow for cook down. I hate nested foreach
foreach ($key in $rules.keys) {
    $pbag = $momapi.CreatePropertyBag()
	
    foreach ($alert in $alerts.value) {
	
        $alertRuleId = $alert.properties.essentials.alertRule
        $monitorCondition = $alert.properties.essentials.monitorCondition
        $severity = $alert.properties.essentials.severity
        $signalType = $alert.properties.essentials.signalType
        $alertState = $alert.properties.essentials.alertState
        $targetResource = $alert.properties.essentials.targetResource
        $startDateTime = $alert.properties.essentials.startDateTime
		
	
        # Set the state
        if ($monitorCondition -eq "Fired" -and $alertState -eq "New" -and $key -eq $alertRuleId) {
            $state = "2" # set error
        }

        else {
            $state = "1"
        }
    }

    $pbag.AddValue("State", $state)
    $pbag.AddValue("Instance", $key)
    $pbag.AddValue("AvailabilityState", $monitorCondition)
    $pbag.AddValue("Object", $key)
    $pbag.AddValue("Severity", $severity)
    $pbag.AddValue("SignalType", $signalType)
	
    $pbag
}
#=================================================================================


#Log an event for script ending and total execution time.
$EndTime = Get-Date
$ScriptTime = ($EndTime - $StartTime).TotalSeconds
$momapi.LogScriptEvent($ScriptName, 5322, 0, "Finished azure monitor alerts check.  Script runtime was ($ScriptTime) seconds.")

From first glance it looks like one big datasource.

Normally for cook down you’d have the probe collecting the data in one datasource, called from another datasource this alllows cookdown to create the additional workflows for each property bag, within the master workflow.

The way I normally do it is;

ProbeActionModule – Simply Runs The PowershellScript returning all property bags

DataSourceModule1 – Runs ProbeActionModule, using a Scheduler

DataSourceModule2 – Runs DataSourceModule1, filtering results (this way the unique object isn’t passed to DataSourceModule1)

Monitors & Performance rules run DataSourceModule2

Best description I’ve seen is this Brian Wren Video (apologies if you’ve already seen this)

https://channel9.msdn.com/Series/System-Center-2012-R2-Operations-Manager-Management-Packs/Mod23

You can also download the sample management pack from his TechNet Blog, that goes with this video series.

1 Like

What Andi says is exactly right - I had the very same issue with some Citrix NetScaler monitoring i’m building and the solution in the end was to move the script portion into it’s own ProbeActionModule. That script now runs and returns a huge property bag which I can then filter using ConditionDetection modules which are embedded in a number of DataSourceModuleTypes.

Basically lines 27 to 70 need to be in a seperate module.

If you get really stuck then let me know and I can sanitise the code i’m working on to give some examples.

1 Like

apparently I have a hard time trying to get this right. Looking at one other MP we have, where cookdown does work, I moved the probe in to a separate module, but that doesent seem to make any difference.

<ManagementPackFragment SchemaVersion="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <TypeDefinitions>
    <ModuleTypes>
      <DataSourceModuleType ID="Ehrnst.AzureMonitor.AlertState.monitor.Datasource.Cookdown" Accessibility="Public">
        <Configuration>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:integer"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string"/>
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
          <OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
          <OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string"/>
        </OverrideableParameters>
        <ModuleImplementation>
          <Composite>
            <MemberModules>
              <DataSource ID="Scheduler" TypeID="System!System.Scheduler">
                <Scheduler>
                  <SimpleReccuringSchedule>
                    <Interval>$Config/IntervalSeconds$</Interval>
                    <SyncTime>$Config/SyncTime$</SyncTime>
                  </SimpleReccuringSchedule>
                  <ExcludeDates/>
                </Scheduler>
              </DataSource>
              <ProbeAction ID="Probe" TypeID="Ehrnst.AzureMonitor.AlertState.PAModuleType.Cookdown">
                <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="Probe">
                <Node ID="Scheduler"/>
              </Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.PropertyBagData</OutputType>
      </DataSourceModuleType>
      <ProbeActionModuleType ID="Ehrnst.AzureMonitor.AlertState.PAModuleType.Cookdown" Accessibility="Internal" Batching="false" PassThrough="false">
        <Configuration>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:integer"/>
        </Configuration>
        <OverrideableParameters>
        </OverrideableParameters>
        <ModuleImplementation Isolation="Any">
          <Composite>
            <MemberModules>
              <ProbeAction ID="PS" TypeID="Windows!Microsoft.Windows.PowerShellPropertyBagTriggerOnlyProbe">
                <ScriptName>Get-AzureMonitorAlerts.ps1</ScriptName>
                <ScriptBody>$IncludeFileContent/Rules and monitors/Scripts/Get-AzureMonitorAlerts.ps1$</ScriptBody>
                <SnapIns/>
                <Parameters>
                  <Parameter>
                    <Name>SourceID</Name>
                    <Value>$MPElement$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>ManagedEntityID</Name>
                    <Value>$Target/Id$</Value>
                  </Parameter>
                  <!--The secret and ID to partner center multi tenant app-->
                  <Parameter>
                    <Name>MultiTenantAppId</Name>
                    <Value>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/UserName$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>MultiTenantAppSecret</Name>
                    <Value>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/Password$</Value>
                  </Parameter>
                  <!--The customer tenant-->
                  <Parameter>
                    <Name>CustomerTenantId</Name>
                    <Value>$Target/Host/Host/Host/Property[Type="ICSP!Ehrnst.Azure.CSPTenant.Class"]/TenantID$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>CustomerSubscriptionId</Name>
                    <Value>$Target/Host/Host/Property[Type="ICSP!Ehrnst.Azure.CSPSubscription.Class"]/SubscriptionID$</Value>
                  </Parameter>
                  <!--RUNAS ACCOUNT PARAMETERS-->
                  <Parameter>
                    <Name>CSPUsername</Name>
                    <Value>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.Account.RunAsProfile"]/UserName$</Value>
                  </Parameter>
                  <Parameter>
                    <Name>CSPPassword</Name>
                    <Value>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.Account.RunAsProfile"]/Password$</Value>
                  </Parameter>
                </Parameters>
                <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
              </ProbeAction>
            </MemberModules>
            <Composition>
              <Node ID="PS"></Node>
            </Composition>
          </Composite>
        </ModuleImplementation>
        <OutputType>System!System.PropertyBagData</OutputType>
        <TriggerOnly>true</TriggerOnly>
      </ProbeActionModuleType>
    </ModuleTypes>
    <MonitorTypes>
      <UnitMonitorType ID="Ehrnst.AzureMonitor.AlertState.Cookdown" Accessibility="Internal">
        <MonitorTypeStates>
          <MonitorTypeState ID="Good"/>
          <MonitorTypeState ID="Bad"/>
        </MonitorTypeStates>
        <Configuration>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:int"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:int"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="MultitenantAppId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="MultitenantAppSecret" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CustomerTenantId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CustomerSubscriptionId" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CSPUsername" type="xsd:string"/>
          <xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="CSPPassword" type="xsd:string"/>
        </Configuration>
        <OverrideableParameters>
          <OverrideableParameter ID="IntervalSeconds" ParameterType="int" Selector="$Config/IntervalSeconds$"/>
          <OverrideableParameter ID="SyncTime" ParameterType="string" Selector="$Config/SyncTime$"/>
          <OverrideableParameter ID="TimeoutSeconds" ParameterType="int" Selector="$Config/TimeoutSeconds$"/>
        </OverrideableParameters>
        <MonitorImplementation>
          <MemberModules>
            <DataSource TypeID="Ehrnst.AzureMonitor.AlertState.monitor.Datasource.Cookdown" ID="DS">
              <IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
              <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
              <SyncTime>$Config/SyncTime$</SyncTime>
            </DataSource>
            <ProbeAction ID="PS" TypeID="Ehrnst.AzureMonitor.AlertState.PAModuleType.Cookdown">
              <TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
            </ProbeAction>
            <ConditionDetection ID="FilterGood" TypeID="System!System.ExpressionFilter">
              <Expression>
                <And>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="Integer">1</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="String">Property[@Name='RuleId']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="String">$Target/Property[Type="Ehrnst.AzureMonitor.Rule.Class"]/RuleId$</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                </And>
              </Expression>
            </ConditionDetection>
            <ConditionDetection ID="FilterBad" TypeID="System!System.ExpressionFilter">
              <Expression>
                <And>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="Integer">Property[@Name='State']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="Integer">2</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                  <Expression>
                    <SimpleExpression>
                      <ValueExpression>
                        <XPathQuery Type="String">Property[@Name='RuleId']</XPathQuery>
                      </ValueExpression>
                      <Operator>Equal</Operator>
                      <ValueExpression>
                        <Value Type="String">$Target/Property[Type="Ehrnst.AzureMonitor.Rule.Class"]/RuleId$</Value>
                      </ValueExpression>
                    </SimpleExpression>
                  </Expression>
                </And>
              </Expression>
            </ConditionDetection>
          </MemberModules>
          <RegularDetections>
            <RegularDetection MonitorTypeStateID="Good">
              <Node ID="FilterGood">
                <Node ID="DS"/>
              </Node>
            </RegularDetection>
            <RegularDetection MonitorTypeStateID="Bad">
              <Node ID="FilterBad">
                <Node ID="DS"/>
              </Node>
            </RegularDetection>
          </RegularDetections>
          <OnDemandDetections>
            <OnDemandDetection MonitorTypeStateID="Good">
              <Node ID="FilterGood">
                <Node ID="DS" />
              </Node>
            </OnDemandDetection>
            <OnDemandDetection MonitorTypeStateID="Bad">
              <Node ID="FilterBad">
                <Node ID="DS" />
              </Node>
            </OnDemandDetection>
          </OnDemandDetections>
        </MonitorImplementation>
      </UnitMonitorType>
    </MonitorTypes>
  </TypeDefinitions>
  <Monitoring>
    <Monitors>
      <UnitMonitor ID="Ehrnst.AzureMonitor.AlertState.Monitor.Cookdown" Enabled="true" Target="Ehrnst.AzureMonitor.Rule.Class" TypeID="Ehrnst.AzureMonitor.AlertState.Cookdown" Accessibility="Public" ParentMonitorID="Health!System.Health.AvailabilityState">
        <Category>AvailabilityHealth</Category>
        <AlertSettings AlertMessage="Ehrnst.AzureMonitor.AlertState.Cookdown.Monitor.Alert.Message">
          <AlertOnState>Warning</AlertOnState>
          <AutoResolve>true</AutoResolve>
          <AlertPriority>Normal</AlertPriority>
          <AlertSeverity>MatchMonitorHealth</AlertSeverity>
          <AlertParameters>
            <AlertParameter1>$Target/Property[Type="Ehrnst.AzureMonitor.Rule.Class"]/ResourceShortName$</AlertParameter1>
            <AlertParameter2>$Data/Context/Property[@Name='SignalType']$</AlertParameter2>
            <AlertParameter3>$Target/Property[Type="Ehrnst.AzureMonitor.Rule.Class"]/AlertDescription$</AlertParameter3>
            <AlertParameter4>$Target/Property[Type="Ehrnst.AzureMonitor.Rule.Class"]/ResourceId$</AlertParameter4>
            <AlertParameter5>$Data/Context/Property[@Name='Severity']$</AlertParameter5>
          </AlertParameters>
        </AlertSettings>

        <OperationalStates>
          <OperationalState ID="GoodCondition"  HealthState="Success"  MonitorTypeStateID="Good"/>
          <OperationalState ID="BadCondition" HealthState="Warning"  MonitorTypeStateID="Bad"/>
        </OperationalStates>

        <Configuration>
          <IntervalSeconds>302</IntervalSeconds>
          <SyncTime></SyncTime>
          <TimeoutSeconds>100</TimeoutSeconds>
          <MultitenantAppId>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/UserName$</MultitenantAppId>
          <MultitenantAppSecret>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.MultiTenantApp.RunAsProfile"]/Password$</MultitenantAppSecret>
          <CustomerTenantId>$Target/Host/Host/Host/Property[Type="ICSP!Ehrnst.Azure.CSPTenant.Class"]/TenantID$</CustomerTenantId>
          <CustomerSubscriptionId>$Target/Host/Host/Property[Type="ICSP!Ehrnst.Azure.CSPSubscription.Class"]/SubscriptionID$</CustomerSubscriptionId>
          <CSPUsername>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.Account.RunAsProfile"]/UserName$</CSPUsername>
          <CSPPassword>$RunAs[Name="ICSP!Ehrnst.Azure.CSP.Account.RunAsProfile"]/Password$</CSPPassword>
        </Configuration>

      </UnitMonitor>
    </Monitors>
  </Monitoring>
  <Presentation>
    <StringResources>
      <StringResource ID="Ehrnst.AzureMonitor.AlertState.Cookdown.Monitor.Alert.Message" />
    </StringResources>
  </Presentation>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="Ehrnst.AzureMonitor.AlertState.Monitor.Cookdown">
          <Name>Azure Monitor Alert rule status monitor</Name>
          <Description>Checks azure monitor for current alerts and match with alert rules discovered. Uses endponint: https://docs.microsoft.com/en-us/rest/api/monitor/alertsmanagement/alerts/getall </Description>
        </DisplayString>
        <DisplayString ElementID="Ehrnst.AzureMonitor.AlertState.Monitor.Cookdown" SubElementID="BadCondition">
          <Name>Bad Condition</Name>
        </DisplayString>
        <DisplayString ElementID="Ehrnst.AzureMonitor.AlertState.Monitor.Cookdown" SubElementID="GoodCondition">
          <Name>Good Condition</Name>
        </DisplayString>
        <DisplayString ElementID="Ehrnst.AzureMonitor.AlertState.Cookdown.Monitor.Alert.Message">
          <Name>Azure monitor alert triggered against {0}</Name>
          <Description>
            An alert in Azure Monitor targeting {3} fired.
            Please see alert description for more details:
            {2}
          </Description>
        </DisplayString>
      </DisplayStrings>
      <KnowledgeArticles>
        <KnowledgeArticle ElementID="Ehrnst.AzureMonitor.AlertState.Monitor.Cookdown" Visible="true">
          <MamlContent>
            <maml:section xmlns:maml="http://schemas.microsoft.com/maml/2004/10">
              <maml:title>Summary</maml:title>
              <maml:para>
                GEts all alerts within azure monitor and matches with the alert rules.
                Check the alert description for what may cause the error and use the Azure portal for further investigation.
              </maml:para>
            </maml:section>
            <maml:section xmlns:maml="http://schemas.microsoft.com/maml/2004/10">
              <maml:title>External</maml:title>
              <maml:para>
                ...
              </maml:para>
            </maml:section>
          </MamlContent>
        </KnowledgeArticle>
      </KnowledgeArticles>
    </LanguagePack>
  </LanguagePacks>

</ManagementPackFragment>

I noted that you are passing $SourceId and $ManagedEntityId to your script (and not even using them in the script), this will break cookdown!

You can’t pass anything from the Target to the script you should only be passing the $Target/Host…… objects.

If you think about it in terms of VMWare, if you have one virtual center hosting 100 virtual machines and you pass the virtual machine name to the script it has no choice but to create 100 scripts, one for each virtual machine!

If however you pass the virtual center name to the script and the script creates 100 property bags, one per virtual machine, then only 1 script is created, this is how cookdown works!

The video I posted above explains it all much better than I can!

I’ll have a look at re-writing what you’ve posted int a cookdown compliant fragment, I’m on a course so I’ll be bored in the hotel tonight anyway!

Thank you. I’ll have a look again. Probably been a few years since I saw that video

Thanks Peter. Some code examples, a modified version of mine or what ever you have laying around is much appreciated. /M

Hi Ehnrst. Any chance you could share your full MP project with me please? I’d be more than happy then to tweak it as needed and then report back with an explanation on the changes and what they do.

From my side it’s easier to work with the full project as I can compile it to verify that the changes i’m making are satisfying cookdown whilst not breaking anything else.

Hi Peter. Not really planned for open source (yet), but if you can email me, i could send you a copy of what I have atm. me AT intility . no

Thanks a bunch.

WAP-Community.zip (1.92 KB)

Hey Andi. Sorry for my late update. And indeed. I believe it was the $sourceId and $ManagedEntity that broke cookdown, thats the only thing i have done, except from putting the probe in to a module. Had a look at Brian Wren’s video today. It’s a great video, but a lot has changed to the modules since then.

That’s great, glad it’s working for you!