SENDING DATA TO TEAMS FROM SCCM
In this tutorial I show how to send data from SCCM (MEMCM) to Microsoft Teams using the built-in Teams webhook and some PowerShell.
Specifically, I will show how we can get the latest software update deployment information via PowerShell, wrap it in some JSON, and then fire it off to a Teams channel!
Management will be impressed and junior admins may consider you a god. Pretty cool right?
SETTING UP THE WEBHOOK
The first step is that you need to create a Teams channel! If you are unsure how to do this please go away and learn check this article. Once you are setup, hit the … to the right of the channel and click on Connectors
Now search for Incoming Webhook and click Add
Click Add again
You may need to go back in via the three dots but you should now see a Configure button for the connector
Give your webhook a name and choose an image (these will be visible in the channel when the webhook posts something) and then click Create
Copy the unique URL as we will need this for our script and then click on Save
If you now check your channel you should see something like the below which indicates we are good to go!
SCCM AND POWERSHELL – GETTING SET UP
SCCM has its own PowerShell module and this can be accessed from any machine that has the console installed. More information can be found about the module and the available cmdlets here
Set-Location 'C:\Program Files\Microsoft Configuration Manager\AdminConsole\bin'
Import-Module .\ConfigurationManager.psd1
With the module now exposed we need to set up a PSDrive to the site server. Replace ABC with your three letter site code and siteserver.contoso.com with the FQDN of your site server
New-PSDrive -Name "ABC" -PSProvider "CMSite" -Root "siteserver.contoso.com" -Description "Primary site"
To run our cmdlets we now need to change directory to the logical drive (replace ABC with your SCCM site code)
Set-Location ABC:
PULLING THE UPDATE INFORMATION WITH POWERSHELL
With the above prep done we can now pull pretty much anything we want out of SCCM. In this example I am grabbing –
- The Automatic Deployment Rule information (last run time and exit code)
- A specific software update group and the updates it contains
- Deployment details such as the collection the software update group targets
- The status of the update installations on the collection members (two devices in my lab environment).
IMPORTANT – Remember to add in your unique URL at the bottom of the script 😉
### Get some ADR info, last run time and exit code
$ADR = Get-CMSoftwareUpdateAutoDeploymentRule -Name "Windows 11"
$ADRLastRun = $ADR.LastRunTime
$ADRExitCode = $ADR.LastErrorCode
### Get the Software Update Group
$sugupdates = Get-CMSoftwareUpdateGroup -Name "Windows 11"
### Get the updates inside in the software update group and do a bit of formatting on the results
foreach ($update in $sugupdates.Updates)
{
$CurrentUpdates += @(Get-CMSoftwareUpdate -Id $update)
}
$CurrentUpdatesName = $CurrentUpdates.LocalizedDisplayName
$CurrentUpdateNameFormatted = [string]::Join('<br>',$CurrentUpdatesName)
### Get the deployment details
$sudeploy = Get-CMSoftwareUpdateDeployment -Name "Windows 11" -Summary
$CollectionName = $sudeploy.CollectionName
$NumberDevices = $sudeploy.NumberTargeted
$NumberInProgress = $sudeploy.NumberInProgress
$NumberErrors = $sudeploy.NumberErrors
$NumberSuccess = $sudeploy.NumberSuccess
### Prepare the payload
[String]$var = "Text which appears in the message content"
$JSONBody = [PSCustomObject][Ordered]@{
"@type" = "MessageCard"
"@context" = "<http://schema.org/extensions>"
"summary" = "Latest Update Deployment Information"
"themeColor" = '0078D7'
"title" = "Latest Update Deployment Information"
"text" = "
The ADR last ran <strong>$ADRLastRun</strong><br>
The ADR exit code was <strong>$ADRExitCode</strong><br>
<br>
The updates in the software update group are:<br><br>
<strong>$CurrentUpdateNameFormatted
</strong>
<br><br>
The collection name is <strong>$CollectionName</strong><br>
The number of devices is <strong>$NumberDevices</strong><br>
<br>
Successes: <strong>$NumberSuccess</strong><br>
In Progress: <strong>$NumberInProgress</strong><br>
Errors: <strong>$NumberErrors</strong><br>
"
}
### Convert to JSON
$TeamMessageBody = ConvertTo-Json $JSONBody
### POST to URL
$parameters = @{
"URI" = "INSERT YOUR UNIQUE URL"
"Method" = 'POST'
"Body" = $TeamMessageBody
"ContentType" = 'application/json'
}
Invoke-RestMethod @parameters
THE RESULTS
And here we go! A nicely formatted message (thanks to the HTML tags in the JSON) and this is something that can easily be called from a scheduled task on a repeatable basis.
Cool tutorial!
How would you automate the script execution? Daily task scheduler on the site server or something smarter?
Hey Mathias, yes I would just call the script from a scheduled task personally.
If you wanted to get a bit more “modern” you could investigate using a flow with Power Automate. Maybe even hook into an Azure Automation runbook? Scheduled task is probably the simplest option however I think….
Sadly not working for me.
Keeps getting error: Invoke-RestMethod : Invalid webhook request – Empty Payload
Hi Tim,
Do you want to post your code?
PS
Make sure you leave out your unique URL.
https://pastebin.com/cHfHYQNN
I did bypass the error by enforcing newer TLS protocols.
Also, i’ve removed the [Ordered] from the JSONBody, as i received error: “Unable to find type [Ordered].
At line:47 char:29
+ $JSONBody = [PSCustomObject][Ordered]”
Now i get the error: “Invoke-RestMethod : Summary or Text is required.”
NOTE: For the $ADR variable, i actually use “Windows 10 Updates” as well. I mistyped it in the pastebin.
OK I was able to replicate this but it should work now if you re-copy it. I think the issue was the white-space after the [Ordered] was causing problems. I’ve updated the script, copied it from this page, inserted my URL and it works now.
Well executes better now.
I still need to force newer TLS protocols inorder to trigger the invoke-restmethod with:
Otherwise i get the error: Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
After that the script rans through. Sadly the message is to long to be displayed in teams.
In the teams channel it says: “This message is too long to display here. Please visit the external source app to view the message.”
That’s good news Tim and glad its working better now. With regards to TLS 1.2, what OS are you using? You may find forcing 1.2 is not needed on newer OS’s possibly.
With regards to the message size limit, I am not sure on what this is exactly but in my demo my software update group only contains 4 updates. You may need to do a bit of extra filtering of the results in your variable if your SUG has lots of updates inside!
The site server is running Server 2016 build 1607 with the April patch.
And yes, my SUG is very large and needs to be trimmed. It contains over 100 updates. Will have a look at trimming that, and retry at some point 🙂
hey nice work here. Anyway to get this sent via email rather than teams?