Let SuperIT and your scheduled actions post alerts and summaries to a team channel through an incoming webhook

Send a message to a Microsoft Teams or Slack channel from a workflow action, so the SuperIT agent can tell your team about something on request, and your other actions can report their results where people will see them. For MSPs and IT teams that work in Teams or Slack.

This guide is about sending notifications to a channel. Chatting with SuperIT itself in Teams or Slack is a separate feature, in Beta.

Runs in Cloud sandbox (PowerShell)
Uses API key credential (webhook URL stored as a custom header)
Suggested approval None (engineers and admins run it without approval)
Category Integrations

Test it with SuperIT before you rely on it

This is an example, not a ready-made action, and it hasn't been tested end to end. The Teams payload assumes a Teams workflow webhook that accepts an Adaptive Card message; check Microsoft's current guidance for your webhook. Before you use it, work through it with SuperIT: ask SuperIT to review the script against your environment and requirements, and adjust it together. Then test it, as in Test it. Test in the action editor isn't a dry run: it runs the script for real.

Why use an action instead of asking SuperIT

SuperIT can't post to your team's channels. This action stores the incoming webhook URL as an encrypted credential and posts a message, on request ("tell #it-alerts the VPN is back"). More importantly, its code is the delivery step for scheduled checks: a scheduled run's output otherwise just sits in run history. Actions can't call each other, so a scheduled check must include the webhook call in its own script.

To draft the wording of an announcement, or to talk to SuperIT itself from Teams or Slack, just ask SuperIT in chat.

When to use it

  • "Tell the service desk channel that the VPN is down for the Leeds office."
  • "Post a summary of this outage to #it-alerts."
  • "Let the on-call channel know SRV-SQL01 is back up."

Its posting code is also the last step for scheduled checks, such as Check website and SSL certificate expiry or Check backup job status.

What the action does

  1. Reads the message and optional title inputs, and rejects an empty or very long message.
  2. Reads the webhook URL from the linked credential.
  3. Builds the right payload: Slack's text format for a hooks.slack.com URL, or an Adaptive Card for a Teams webhook. For Slack, it escapes &, < and >, so text such as <!channel> or <https://example.com|link> shows as typed instead of notifying the channel or hiding a link.
  4. Posts it once and prints whether the channel accepted it.

What it doesn't do:

  • It doesn't read replies or reactions. Webhooks only send.
  • It doesn't send direct messages to people or @mention them, and it escapes Slack's mention and link syntax in the message.
  • It doesn't post to a channel other than the one the webhook belongs to. Create one credential per channel.

Before you begin

  • A webhook for the channel.
    • Slack: create a Slack app with an incoming webhook for the channel. The URL starts with https://hooks.slack.com/.
    • Teams: in the channel, add a workflow that posts to the channel when a webhook request is received, and copy its URL.
  • A credential. Anyone with the webhook URL can post to the channel, so treat it as a secret. Under Workflows → Credentials, select New, name it IT Alerts Channel and choose Custom HTTP headers (under Advanced). Add one row: name webhook_url, value the URL. There's no credential type for a single secret value, so this stores the URL as a custom header value; the script reads it as CREDENTIAL_IT_ALERTS_CHANNEL_WEBHOOK_URL and never sends it as a header. SuperIT never shows the value again. See Credentials.
  • No authorization policy, so engineers and admins can post without approval. If you want end users to trigger posts, add a policy instead. See Approvals.
  • Your role. Creating an action in chat needs the Admin role. Engineers can build it by hand under Workflows → Actions.

Build it with SuperIT

Create an action called "Post to IT alerts channel".
Purpose: post a message to our IT alerts channel in Teams (or Slack) through its incoming webhook.
Runtime: PowerShell in the cloud sandbox, using Invoke-WebRequest.
Inputs: message (textarea, required, max 3000 characters), title (string, optional).
Credential: "IT Alerts Channel" (custom header webhook_url holds the webhook URL).
Use Slack's text payload for hooks.slack.com URLs, escaping &, < and >; otherwise a Teams Adaptive Card.
No authorization policy: engineers and admins only, no approval.

SuperIT drafts the script, validates it and creates the action as a draft. You review it, test it and publish it under Workflows → Actions.

Or build it yourself

Name Type Required Example
message textarea Yes VPN is down for the Leeds office. We're on it.
title string No Service notice

Set Runtime to PowerShell:

# Goal: post one message to the IT alerts channel through its Slack or Teams incoming webhook.
$webhookUrl = "$env:CREDENTIAL_IT_ALERTS_CHANNEL_WEBHOOK_URL"

function Invoke-ChannelPost {
    param([string]$Message, [string]$Title)

    $text = $Message.Trim()
    $heading = $Title.Trim()
    Assert-Inputs -Message $text
    if ($webhookUrl -like "*hooks.slack.com*") {
        $payload = New-SlackPayload -Message $text -Title $heading
    } else {
        $payload = New-TeamsPayload -Message $text -Title $heading
    }
    $status = Send-WebhookPost -Payload $payload
    Write-Output "=== MESSAGE POSTED ==="
    Write-Output "HTTP status : $status"
    # $script: so the runner can still read $result after this function returns.
    $script:result = @{ posted = $true; status = $status }
}

function Assert-Inputs {
    param([string]$Message)
    if (-not $Message) { throw "Input 'message' is required." }
    if ($Message.Length -gt 3000) { throw "Message is longer than 3000 characters. Shorten it." }
    if (-not $webhookUrl.StartsWith("https://")) {
        throw "The 'IT Alerts Channel' credential is missing or isn't an https URL."
    }
}

function New-SlackPayload {
    param([string]$Message, [string]$Title)
    $body = ConvertTo-SlackText -Text $Message
    $text = if ($Title) { "*$(ConvertTo-SlackText -Text $Title)*`n$body" } else { $body }
    return @{ text = $text }
}

function ConvertTo-SlackText {
    param([string]$Text)
    # Slack reads <!channel>, <!here> and <url|text> as commands; escaping shows them as typed.
    return $Text.Replace('&', '&amp;').Replace('<', '&lt;').Replace('>', '&gt;')
}

function New-TeamsPayload {
    param([string]$Message, [string]$Title)
    $body = [System.Collections.Generic.List[object]]::new()
    if ($Title) { $body.Add(@{ type = "TextBlock"; text = $Title; weight = "Bolder"; size = "Medium" }) }
    $body.Add(@{ type = "TextBlock"; text = $Message; wrap = $true })
    return @{
        type        = "message"
        attachments = @(@{
            contentType = "application/vnd.microsoft.card.adaptive"
            content     = @{
                type      = "AdaptiveCard"
                version   = "1.4"
                '$schema' = "http://adaptivecards.io/schemas/adaptive-card.json"
                body      = $body
            }
        })
    }
}

function Send-WebhookPost {
    param([hashtable]$Payload)
    $json = $Payload | ConvertTo-Json -Depth 10
    try {
        $response = Invoke-WebRequest -Method Post -Uri $webhookUrl -TimeoutSec 30 `
            -ContentType "application/json; charset=utf-8" -Body ([System.Text.Encoding]::UTF8.GetBytes($json))
    } catch {
        # Never include $webhookUrl in a message: anyone holding it can post to the channel.
        $status = $_.Exception.Response.StatusCode
        if ($status) { throw "Failed to post to the channel: webhook returned HTTP $([int]$status). Check the webhook still exists." }
        throw "Failed to reach the channel webhook: $($_.Exception.Message)"
    }
    return [int]$response.StatusCode
}

Invoke-ChannelPost -Message $ctx.inputs.message -Title $ctx.inputs.title

The script never prints the webhook URL, so it doesn't end up in run output or ticket notes.

Test it

  1. Save the draft and select Test.
  2. Test is not a dry run: it skips authorization and approvals and uses the real credential and network access, so the message really posts to the channel. Test runs aren't billed.
  3. Use a message like "Test from SuperIT, please ignore", or point a test credential at a private test channel first.
  4. Check the message appears with the title in bold.
  5. In Slack, post a test message containing <!here> and check it shows as text and notifies nobody.
  6. Select Publish.

Use it

  • In chat: "Post to the IT alerts channel: VPN is down for Leeds, ETA 30 minutes." SuperIT shows you the message before running the action if you ask it to.
  • From a ticket: after investigating a ticket that affects many users, SuperIT can recommend posting a notice.
  • With other actions: an action runs one script and can't call other actions (see Limits), so to report from a scheduled check, copy the posting code into that action and link this credential to it as well.
  • Managed teams: use Publish to teams if each customer has its own channel. Each managed team gets a read-only copy and a blank IT Alerts Channel credential for its admin to fill in with their webhook.

Variations

  • Severity colours: add an enum input with info, warning and critical and style the card accordingly.
  • Status page update: post to your own status page's incident API at the same time.
  • Email instead: send through Microsoft Graph sendMail with a Microsoft Graph credential. See Send a weekly summary report.