Beyond Impact Blog

Post SCOM Alerts to Microsoft Teams

Dec 23, 2016 3:43:34 PM / by Cole McDonald

Connecting System Center to Microsoft Teams (straight to the code: https://github.com/cole-mcdonald/Blog_Code/blob/master/Send-SCOM2Teams.ps1)

Microsoft has released the team collaboration tool Teams.  It promises to allow tighter integration of more advanced team workflows by keeping the whole system better integrated.  The possibilities this opens up for us are nearly limitless.  Operations Manager can be used to schedule interval checks of server specifics for data analysis, the team informed of the results and responses from within the Teams interface can be pushed back to SCOM, VMM, Azure, or any other piece of the puzzle for reducing the action time.

At Beyond Impact, we're a multi-tenant hybrid ERP cloud hosting company.  We monitor our entire environment for health to be able to react as quickly as possible.  This is the goal of every company utilizing a monitoring system like Operations Manager.  Each environment has its own peculiarities which lead to specific operational procedures for reacting to common problems in that environment.  If we know a set of virtual machines from separate customers are hosted on the same physical hardware, we are able to infer that a problem which shows up on all of them may actually be an issue with the host rather than the individual virtual servers.

If it's a problem we've encounted in the past, we'll have documented a solution for that issue.  If the corrective action can be automated (most of them can), then we can use SCOM to push a connection card alert through a webhook to Teams.  This connection card can have an action button on the bottom that allows the admins on the channel to choose to react using the pre-defined remediation, or to assign it to someone to investigate first.

Since the notification will be a Powershell command channel, we can build logic into the alert as well.  Once we see an alert we have identified in the past, we can then look for that same error on the other virtuals.  If we find them, we can then announce to the Teams channel that the physical host seems to be having a pre-identified issue and pull up the remediation data to present along with the alert.  Let's build out the alert mechanism in this post.

I'm assuming you're in Teams and have at least one channel setup.

- Right-click on the channel title in the channel listing on the left side of the page.
- Select "Connectors" ... the page may take a little bit of time to load
- From the list, click the Add button to the right of "Incoming Webhook"
- Create a title for the Hook.  In this example, we'll be using "SCOM Alerts"
- If you want it to have its own icon, you can choose to upload a suitably small, square image here
- Click Create
- Copy the provided URL using the overlapping docs "copy to clipboard" button.

The Azure Webhook takes a JSON String as an argument via an HTTP POST

Let's start our script:

####### Simple Powershell alert to Teams #######

# Drop the nasty long "https://outlook.office365.com/webhook/..." URL into a string variable
$SCOM_Hook = "URL from clipboard"

# Add the messages we want to send into easy to manage variables
$title = "SCOM Test Alert
$message = "This is a simple message to my team`nYou know what to do with it."

# Build the JSON object for the POST - using a "stringwich" ( @"..."@ )to keep it readable.
$content_JSON = @"
{
    "title" : "$title",
    "text" : "$message"
}
"@

# Send message to Teams Channel using Invoke-WebRequest (note the line coninuations)
Invoke-WebRequest `
    -Uri $SCOM_HOOK `
    -Method POST `
    -Body $content_JSON `
    -ContentType application/json

####### End Simple Powershell alert to Teams #######

We should now have a message in your Teams Channel!  Nothing exciting yet, but functional.  The "O365 connector card" hasn't been fully implemented yet, but color bands for the sides and action blocks with URLs are in the works.  I was able to get an action block to attach to the bottom of a post the other day, then it threw an error the next day.  I would present more in terms of more complicated interaction in this post, but the two I'm addressing here are going to be pretty stable and can give a starting point that can be implemented immediately.  Speaking of implementing.  Let's grab a bunch of alert data from SCOM and throw it into a card.

I'll be using some of the code from Tyson Paul's version 2.3 of Tao Yang's Enhanced E-Mail Script (https://blogs.msdn.microsoft.com/tysonpaul/2014/08/04/scom-enhanced-email-notification-script-version-2-1/ ) to get the knowledge articles out of the management packs to display as well.  WIth this in place, a company knowledge MP can be the repository of the standard operating procedures you'd like your technicians to follow.  For testing, I've used 'get-scomalert' to grab a currently active alert to prepopulate the $alertID variable at the head of the script... here's the full command I used to choose one:

get-scomalert -computername scom-server-name-here `
    | where-object -property resolutionstate -eq 0 `
    | select-object name, id `
    | format-list

I digress, Once I've got that and the same thing for the subscription using get-scomnotificationsubscription, I plug them into the parameters block along with the Web Hook and the local resources.  Keeping them all in a block up tops makes it easier to reference and change bot internally for testing, and when accessing them from the SCOM interface:

####### Environmental Variable Declaraions #######
param (
    [string]$AlertID = "guid-for-alert-goes-here",
    [string]$SubscriptionID = "guid-for-subscription-goes-here",
    [string]$SCOM_HOOK = "incoming webhook connector URL from teams channel",
    [string]$SCOM_MS = "SCOM_Mgmt_Server",
    [string]$SCOM_URL = "https://scom.domain.com"
)
####### End Environmental Variable Declaraions #######

We then need to use the alerrt ID to grab the alert object from SCOM and the knowledge from the management pack:

####### Alert grab from SCOM #######
Import-Module OperationsManager

# Grab the alert and subscription delay
$alert = Get-SCOMAlert -ComputerName $SCOM_MS | Where-Object -Property ID -eq $AlertID
$thisSub = Get-SCOMNotificationSubscription -ComputerName $SCOM_MS | Where-Object { $_.Id -eq $SubscriptionID }
$delay = $thisSub.Configuration.IdleMinutes

## The knowledge parts and toHTML functions are pulled from Tyson Paul's 2.3 version of Tao Yang's Enhanced Email

# Company Knowledge
# Functions to parse the content
# Needed to remove quotes to get the JSON to pass correctly as well.

function trim-braces ($inString) {
    $instring = $inString.trimstart("{")
    $instring = $inString.trimend("}")
    return $inString
}

function fnMamlToHTML ($MAMLText) {
    $HTMLText = ""
    $HTMLText = $MAMLText -replace ('xmlns:maml="http://schemas.microsoft.com/maml/2004/10"')
    $HTMLText = $HTMLText -replace ("<maml:para>", "`n")
    $HTMLText = $HTMLText -replace ("maml:")
    $HTMLText = $HTMLText -replace ("</section>")
    $HTMLText = $HTMLText -replace ("<section>")
    $HTMLText = $HTMLText -replace ("<section >")
    $HTMLText = $HTMLText -replace ("<title>")
    $HTMLText = $HTMLText -replace ("</title>")
    $HTMLText = $HTMLText -replace ("<listitem>")
    $HTMLText = $HTMLText -replace ("</listitem>")
    $HTMLText = $HTMLText -replace ("`", " ")
    return $HTMLText
}

function fnTrimHTML ($HTMLText) {
    $TrimmedText = ""
    $TrimmedText = $HTMLText -replace ("&lt;", "<")
    $TrimmedText = $TrimmedText -replace ("&gt;", ">")
    $TrimmedText = $TrimmedText -replace ("<html>")
    $TrimmedText = $TrimmedText -replace ("<HTML>")
    $TrimmedText = $TrimmedText -replace ("</html>")
    $TrimmedText = $TrimmedText -replace ("</HTML>")
    $TrimmedText = $TrimmedText -replace ("<body>")
    $TrimmedText = $TrimmedText -replace ("<BODY>")
    $TrimmedText = $TrimmedText -replace ("</body>")
    $TrimmedText = $TrimmedText -replace ("</BODY>")
    $TrimmedText = $TrimmedText -replace ("<h1>", "<h3>")
    $TrimmedText = $TrimmedText -replace ("</h1>", "</h3>")
    $TrimmedText = $TrimmedText -replace ("<h2>", "<h3>")
    $TrimmedText = $TrimmedText -replace ("</h2>", "</h3>")
    $TrimmedText = $TrimmedText -replace ("<H1>", "<h3>")
    $TrimmedText = $TrimmedText -replace ("</H1>", "</h3>")
    $TrimmedText = $TrimmedText -replace ("<H2>", "<h3>")
    $TrimmedText = $TrimmedText -replace ("</H2>", "</h3>")
    $TrimmedText = $TrimmedText -replace ("`"", " ")
    return $TrimmedText
}

# Strip the curly braces off of the incoming values
$alertID = trim-braces -inString $alertID
$SubscriptionID = trim-braces -inString $SubscriptionID

# Load the SDK and connect to the Management Server
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager.Common") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.EnterpriseManagement.OperationsManager") | Out-Null
$MS_CONNECTION = New-Object Microsoft.EnterpriseManagement.ManagementGroupConnectionSettings($SCOM_MS)
$MGMT_GROUP = New-Object Microsoft.EnterpriseManagement.ManagementGroup($MS_CONNECTION)

$KnowledgeArticles = $null
$KnowledgeArticles = $MGMT_GROUP.GetMonitoringKnowledgeArticles([string]$alert.ruleid)

if ($KnowledgeArticles -eq $null) {
    $knowledgeText = "No resolutions were found for this alert.`n"
} else {
    #Convert Knowledge articles
    Foreach ($article in $KnowledgeArticles)
    {
     If ($article.Visible)
     {
      #Retrieve and format article content
      $MamlText = $null
      $HtmlText = $null
   
      if ($article.MamlContent -ne $null)
      {
       $MamlText = $article.MamlContent
       $knowledgeText = "$(fnMamlToHtml($MamlText))`n"
      }
   
      if ($article.HtmlContent -ne $null)
      {
       $HtmlText = $article.HtmlContent
       $knowledgeText = "$(fnTrimHTML($HtmlText))`n"
      }
     }
    }
}
####### End Alert grab from SCOM #######

Now, we'll build a message to send to the team.  I'm breaking it down into component parts for this example, but feel free to use quotewiches (@""@) or any other method you'd like:

####### Message Aggregation #######
# Empty message and title variable for posterity
$title = ""
$message = ""

# Title
$title = "SCOM Dispatch`n"
# Time and Path
$message += "$($alert.TimeRaised) - $($alert.MonitoringObjectPath)`n"
# Alert Name
$message += "$($alert.name)`n`n"
# Description
$message += "$($alert.Description)`n`n"
# Add the knowledge to the output
$message += $knowledgeText
# Alert ID
$message += "Alert: $($alert.id)`n"
# Monitor ID
$message += "Monitor: $($alert.ruleid)`n"
# Subscription Info
$message += "Subscription ID: $SubscriptionID - Delay: $delay`n"
# Add action Link
$message += "[ $SCOM_URL ]"
####### End Message Aggregation #######

Lastly, we need to package this into a JSON object for passing through to Teams' Webhook:

####### Create JSON String (using a quotewich) #######
$content_JSON = @"
{
    "title" : "$title",
    "text" : "$message"
}
"@
####### End Create JSON String #######

The only piece left is to send the the JSON off to the Azure Webhook.  The easy method for accomplishing this in Powershell is the invoke-webrequest command. We'll need to explicitly set the content-type to json and the connection method to POST.

####### Post the JSON to the Webhook #######
Invoke-WebRequest `
    -Uri $SCOM_HOOK `
    -Method POST `
    -Body $content_JSON `
    -ContentType application/json
####### End Post the JSON to the Webhook #######

At this point, we've successfully taken an alert from System Center Operations Manager and piped it into a Microsoft Teams channel.  The only thing left is to add a subscriber and channel for your Teams script.  This will allow you to set notification schedules and combine them with other things like auto-trouble ticket generation (which sounds like a good blog post).  I'll leave most of that up to you, but the command channel will look like this with the script saved to your SCOM Management server's "D:\Scripts" directory as "Send-SCOMToTeams.ps1":

path:
    C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe
Parameters:
    "D:\Scripts\Send-SCOMToTeams.ps1" -alertID "$Data/Context/DataItem/AlertId$" -Subscription "$MPElement$"
Startup Folder:
    D:\Scripts

Now any subscription can be fed to Teams using the subscriber/command channel combo you've added.

The full script is hosted on GitHub:

https://github.com/cole-mcdonald/Blog_Code/blob/master/Send-SCOM2Teams.ps1

------------------------------------------------------------------------

Did you find this article useful?  Let me know at cole.mcdonald@beyondimpactllc.com

If you want to be kept informed, follow our RSS feed: http://blog.beyondimpactllc.com/blog/rss.xml

Learn more about PowerShell in Azure

Beyond Impact is a Cloud Hosting and Managed Services provider based in Minneapolis, Minnesota. 
You can learn more about our Cloud Services at beyondimpactllc.com/azure-services/.

Tags: system center operations manager, powershell, webhook, SCOM, Microsoft Teams

Cole McDonald

Written by Cole McDonald

Internet Pioneer, Digital Futurist

Subscribe to Email Updates

Recent Posts