Notification Service

Back in August I created a blog post on using Pushover and powershell for OSD deployment notifications, in the comments section Shawn Esterman suggested that Microsoft Teams could be used too. This was a really good suggestion but due to work commitments I have not had much time to look at this until now.

Microsoft Teams

Is a platform that combines workplace chat, meetings, notes and attachments, this is integrated into Office 365 and as such needs a subscription. Teams runs on desktop, laptops and mobile devices, but what makes this product so good is the ever extending list of connectors. So far I have been very impressed with, it has been something that I have not used but was aware of. Its worth noting that Teams will eventually replace/intergrate Skype for Business.

Creating your Team and Channel

If you have never used Teams you will need to get your head around how Teams and Channels work, below is a picture and link that Microsoft provide which really helps. You can see that this has huge potential.

Microsoft Teams Documentation site 

Things worth remembering
  • You can have many Channels on each Team
  • Each Channel can have Connectors (or bots)
  • You can have multiple Connectors on each Channel

  1. Create your Team
  2. Give your Team a name, it’s worth thinking about your structure and not being to specific with the name. 
  3. You can add members or groups to your Team, they will have to have an Office 365 accounts i’m not 100% sure you can use members from a different tenancy.
  4. The Team has been created now look at the settings.
  5. Give your Team an icon.
  6. Now create a channel, the first one is for “OSD Completed Successfully” but I will have multiple channels for “Failed“, “Started” etc
  7. Time to add a connector, there are so many and you can have multiple connectors per channel.
  8. You can add an incoming Webhook which can be used to send data to a Teams channel.
  9. Give your connector a name.
  10. Copy the URL which you will add to the script later.

Powershell Script

   Created with: 	SAPIEN Technologies, Inc., PowerShell Studio 2017 v5.4.140
   Created on:   	05/10/2017 13:07
   Created by:   	Terence Beggs
   Organization: 	SCConfigMgr 
   Filename:     	MicrosoftTeams-OSD-Successful-v0.4.ps1

    This script uses Microsoft Teams to notify when a OSD task sequence has completed successfully.

   	Twitter : @terencebeggs
    Blog :	

$uri = 'INSERT URL'

# Date and Time
$DateTime = Get-Date -Format g #Time

# Time
$Time = get-date -format HH:mm

# Computer Make
$Make = (Get-WmiObject -Class Win32_BIOS).Manufacturer

# Computer Model
$Model = (Get-WmiObject -Class Win32_ComputerSystem).Model

# Computer Name
$Name = (Get-WmiObject -Class Win32_ComputerSystem).Name

# Computer Serial Number
[string]$SerialNumber = (Get-WmiObject win32_bios).SerialNumber

# IP Address of the Computer
$IPAddress = (Get-WmiObject win32_Networkadapterconfiguration | Where-Object{ $_.ipaddress -notlike $null }).IPaddress | Select-Object -First 1

# Uses TS Env doesnt give much on x64 arch
#$TSsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment -ErrorAction SilentlyContinue
#$TSlogPath = $tsenv.Value("_SMSTSLogPath")

# these values would be retrieved from or set by an application

$body = ConvertTo-Json -Depth 4 @{
  title    = "$Name Completed Successfully"
  text	 = " "
  sections = @(
      activityTitle    = 'Task Sequence'
      activitySubtitle = 'Windows 10 1703 x64 (Staff & Student)'
      #activityText	 = ' '
      activityImage    = '' # this value would be a path to a nice image you would like to display in notifications
      title = '<h2 style=color:blue;>Deployment Details'
      facts = @(
          name  = 'Name'
          value = $Name
          name  = 'Finished'
          value = "$DateTime"
          name  = 'IP Addresss'
          value = $IPAddress
          name  = 'Make'
          value = $Make
          name  = 'Model'
          value = $Model
          name  = 'Serial'
          value = $SerialNumber

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

Executing the script

When the script is run the message instantly arrives on the clients, below is an example of the message on the desktop and the iOS client. You can add this to the end of a Task Sequences and similarly create one for failed Task Sequences.

Desktop Client

iPhone Client



If you are not too familiar with powershell or are not too sure how this actually works it’s worth reading up. I have added some resources below and once you understand it you can alter to fit your own environment.


ConvertTo-JSON cmdlet converts any object to a string in JavaScript Object Notation (JSON) format. The properties are converted to field names, the field values are converted to property values, and the methods are removed.

Invoke-RestMethod cmdlet sends HTTP and HTTPS requests to Representational State Transfer (REST) web services that returns richly structured data.

Actionable message card reference

Cards are meant to provide easy to read, at-a-glance information that users can very quickly decipher and act upon when appropriate. As such, the guiding principle for designing great card is “content over chrome,” which means cards are straight to the point and minimize the use of anything that would be distracting such as icons or custom colors.

A great resource on this is

Card Playground is great site for testing your “Message Cards”.


An Irish man living in London, after completing a BSc in Computer Science in 2005 he started working in the IT Industry. Currently Senior Systems Officer at London Metropolitan University managing Azure and several thousand endpoints across several campuses in London.

Technology focuses include SCCM, MDT, Azure, Office 365, Active Directory, Group Policy, Application Packaging, PowerShell, Virtualization and Automation.

  • Scott
    Posted at 16:06 October 6, 2017

    This is sweet!

  • rbi
    Posted at 17:36 October 6, 2017


    very usefull tips, that’s appreciated ! I’m wondering how can i use this to be used with my ~30 task sequences ? Do i have to edit and create multiple different script ?


    • Terence Beggs
      Posted at 19:27 October 6, 2017
      Terence Beggs

      No you should be able to use the same one just change a few things to make it more dynamic like the task sequence name. Plus you should be able to change settings in a task sequence using powershell so shouldn’t take you long

  • Shawn Esterman
    Posted at 19:04 October 6, 2017
    Shawn Esterman

    I’m honored to be mentioned! Thanks for the idea credit

    • Terence Beggs
      Posted at 19:28 October 6, 2017
      Terence Beggs

      Not at all it was a very good idea

  • Michael Winger
    Posted at 19:17 October 6, 2017
    Michael Winger

    This script inspired me to learn how to do this in Slack instead of Microsoft Teams. While the Slack App still wants JSON, they have different requirements for the array that you convert to json. I’ve uploaded my code here:

  • Shawn Esterman
    Posted at 19:32 October 6, 2017
    Shawn Esterman

    For anyone looking to implement something like this I found the following things helpful:

    1. The card playground mentioned was super helpful
    2. I needed a helper function to escape strings so they were JSON safe:

    # Tried using [Regex]::Escape($String), but it also escaped spaces and that wasn’t going to work for me so I wrote this function
    function EscapeForJson {
    param (
    [Parameter(ValueFromPipeline = $true)]
    if ( $String -eq $null ) { return ‘ ‘ }
    $String = $String.ToString().Replace(‘”‘,’\”‘).Replace(‘\’,’\\’).Replace(“`n”,’\n’).Replace(“`r”,’\r’).Replace(“`t”,’\t’)
    return $String
    3a. We do 3 times of task sequence notification: Build Start, Build Finish, and Build Error
    3b. To send build errors, we use the concept behind this article and if an error occurs there is a task sequence step to send the last error code to a Teams webhook. You create 2 steps, one to store the last result in a custom task sequence variable and one to send the message passing in that custom variable

    Posted at 23:26 October 6, 2017

    This is great. thx for sharing

  • Bill
    Posted at 15:02 October 23, 2017

    Where do I put my URL in the script? I’m still very new to Powershell.

    • Terence Beggs
      Posted at 15:16 October 23, 2017
      Terence Beggs

      Hello Bill

      You will need to put the URL in $uri = ‘INSERT URI’ part of the script, replace INSERT URI with your URL. I will change this to URL to stop any confusion in the future.


      Specifies the Uniform Resource Identifier (URI) of the Internet resource to which the web request is sent. This parameter supports HTTP, HTTPS, FTP, and FILE values.+
      This parameter is required. The parameter name (-Uri) is optional.

      • Bill
        Posted at 15:53 October 23, 2017

        Hi Terence,

        Thank you very much for your response! I’m excited to test this out today!

  • Jeremy Kowalski
    Posted at 00:32 November 17, 2017
    Jeremy Kowalski

    Just a note – the problem with TSenv above is that it’s defined as TSsenv and then called as TSenv, which doesn’t match. Even in 64-bit WinPE, it works fine now.

    I suggest a few tweaks, namely:
    1) Set product, because both model and product are useful for Lenovo devices.
    if ($Make.tolower() -eq ‘lenovo’) { $Product = (Get-WmiObject -Class Win32_ComputerSystemProduct).Version } else { $Product = $Model }

    2) Detect the proper computer name, if we can.
    if ($TSenv.Value(“OSDComputerName”) -ne “”) { $Name = $TSenv.value(“OSDComputerName”) } else { $Name = (Get-WmiObject -Class Win32_ComputerSystem).Name }

    3) Detect the name of our task sequence dynamically, if possible.
    if ($TSenv.Value(“_SMSTSPackageName”) -ne “”) { $JobName = $TSenv.value(“_SMSTSPackageName”) } else { $JobName = “Unknown Task Sequence” }

    All of these have been tested and are working properly for us on WinPE 1703×64.

  • Gutavo
    Posted at 14:25 December 11, 2017

    Hello I have problems with Proxy of my company, it´s possible configurate Proxy Setting in the script?

  • Leave a Reply