Post notifications to Microsoft Teams using PowerShell

Microsoft Teams, announced earlier today, is a new platform for chat based communication. I was very happy to see the Connectors available including many popular CI/CD related tools. The Connector configurations allow for an easily pluggable extension for Microsoft Teams to integrate notifications in to discussions. This creates an opportunity to integrate datacenter and cloud operations practices with real time discussions.

Among the available connectors in the list, you will find Incoming Webhook. This provides an easy solution to post notifications from any scripting language through JSON formatted web service call.

To add the Connector:

  1. Open the Channel and click the More Options button (which appears as three dots at the top right of the window).
  2. Select Connectors.
  3. Scroll down to Incoming Webhook and click the Add button.
  4. Give the connector a name and image of your choosing and finally click Create.
  5. A new unique URI is automatically generated. Copy this URI string to your clipboard.

If you ever need to retrieve it in the future you can do so from this same configuration area of Teams. Select the Connector and then click the Manage button to reveal the URI string.

Call the Webhook from PowerShell

Let's start with a simple test to verify functionality. Replace the value for the URI string in the following script and test it by running it in PowerShell ISE. You should see a "1" returned in the PowerShell window and new post in the Teams channel. If an error occurs, it will appear as an error in PowerShell communicating a malformed web service call.

 $uri = <paste your URI here>

$body = ConvertTo-JSON @{
    text = 'Hello Channel'
}

Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'

simple

Adding more details

Now referencing the O365 Connector Cards API, we can add significantly more detail to the notification. This script will probably not be run interactively by a human, it will be called from some automated process. You can include this in an Azure Automation runbook to notify a channel every time the runbook has executed and the result. For example, the message text "Successfully shut down all running Hyper-V lab virtual machines using Hybrid Runbook Worker" can be posted to your team channel at the end of every work day to make everyone aware that a change occurred in your test environment.

As another example, you can use PowerShell to deliver notifications about changes to your Infrastructure As Code environment, managed by a CI/CD pipeline. In this case, you can leverage PowerShell Core to launch PowerShell if your build service is running on a Linux Server, and send the notification.

In the example below, the body includes an activity and multiple facts. This script is compatible across Windows, Linux, or MacOS when running in PowerShell Core.

 $uri = <paste your URI here>

# these values would be retrieved from or set by an application
$status = 'success'
$fact1 = 'All tests passed'
$fact2 = '1 test failed'

$body = ConvertTo-Json -Depth 4 @{
    title = 'New Build Notification'
    text = "A build completed with status $status"
    sections = @(
        @{
            activityTitle = 'Build'
            activitySubtitle = 'automated test platform'
            activityText = 'A change was evaluated and new results are available.'
            activityImage = 'https://URL' # this value would be a path to a nice image you would like to display in notifications
        },
        @{
            title = 'Details'
            facts = @(
                @{
                name = 'Unit Tests'
                value = $fact1
                },
                @{
                name = 'Integration Tests'
                value = $fact2
                }
            )
        }
    )
}


Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'

details
Finally, add links to the fact values and a button at the end of the notification to link to a web location. Add links by formatting the values with markdown style link references. Then add the button using the "ViewAction" type.

There is a catch to adding the button.

In order for PowerShell to correctly convert the JSON, use the -Depth parameter. The target item within the 'potentialAction' object must be created as an array with a single item when it is converted to JSON, else you will have a malformed request. A Depth of "4" correctly creates the array in this example, as the value is 4 sub-sections in to the JSON document.

 
$uri = <paste your URI here>

# these values would be retrieved from or set by an application
$status = 'success'
$fact1 = '[All tests passed](https://URLtoReport)'
$fact2 = '[1 test failed](https://URLtoReport)'

$body = ConvertTo-Json -Depth 4 @{
    title = 'New Build Notification'
    text = "A build completed with status $status"
    sections = @(
        @{
            activityTitle = 'Build'
            activitySubtitle = 'automated test platform'
            activityText = 'A change was evaluated and new results are available.'
            activityImage = 'https://URL' # this value would be a path to a nice image you would like to display in notifications
        },
        @{
            title = 'Details'
            facts = @(
                @{
                name = 'Unit Tests'
                value = $fact1
                },
                @{
                name = 'Integration Tests'
                value = $fact2
                }
            )
        }
    )
    potentialAction = @(@{
            '@context' = 'https://schema.org'
            '@type' = 'ViewAction'
            name = 'Click here to visit PowerShell.org'
            target = @('https://powershell.org')
        })
}


Invoke-RestMethod -uri $uri -Method Post -body $body -ContentType 'application/json'

button

Troubleshooting

In testing this, all of the errors I encountered were a result of not correctly formatting the JSON document. Reference the examples given in the API and compare your results as returned by the ConvertTo-Json cmdlet. To see this text, highlight just the section of the script that generates $body and run it in PowerShell ISE using the "Run Selection" button or by pressing F8. Then type $body in the terminal window and review the output. Remember that when you see square brackets in the JSON document, that indicates an array, and arrays might contain only a single value.

Thank you!
Michael Greene
Principal Program Manager
Enterprise Cloud Group CAT Team