Switching to Microsoft Teams

Lowering barrier to entry by automating the transition to a new service thru REST APIs and PowerShell

Microsoft Teams

About a month ago Microsoft released their Teams service to the public, a service that goes head on with the likes of Slack. And for anyone with an Office 365 subscription it was really competitively priced as it was included.

In this post I’m not covering how it compares to the other products like Gitter, Hip-Chat, IRC or Slack. Instead I’ll go thru how you can automate the transition of configuring your existing services to talk to Teams.
I will not go thru how PowerShell as a language works in details, but hopefully even if you’re new to PowerShell and despite me going into details get the gist of it.

Doing it by hand

Microsoft Teams add connector to channel

Configuring Teams integrations is fairly easy, you just right click on the channel you want to add an integration to and choose connectors.

Microsoft Connector selector

Then search / scroll to the integration you want to add, click the big “Add” button and fill in the required options for the chosen connector.

Microsoft Team

In the case of Bitbucket you choose the account to use, the pick which repository you want to use and which events that should trigger and notification to Teams.
So it’s very easy to get going and if you only got a few repositories it’s no hassle at all.
But the fact that you only can add one repository at a time can make it quite tedious easy to miss one if you have several repositories.
Especially if you used the service for a couple of years then the paging could look something like below (25 repos/page…)

A couple of Bitbucket repositories…

Automation to the rescue

So this is when you ask yourself there’s got to be an better way, right?Wouldn’t it be great if Bitbucket offered some kind of API where you could iterate thru each repository and see which notifications were configured and if your Teams web hook is missing add it?
It turns out Atlassian offers APIs for all these scenarios! Before we star calling the API we need two things a web hook URI and a recommend you setup an “App password” too.

Unfortunately the Bitbucket incoming web hook isn’t displayed under Microsoft Teams connector config, fortunately it’s added as “web” under configured repositories, so if you just add connect one Bitbucket repository you will be able to take the URL from that one and reuse

Bitbucket settings web hook configuration

App passwords are setup under your Bitbucket settings

Bitbucket Settings App passwords

Click on the “Create app password” button, then enter a name and which permissions needed. For this exercise we only need to be able to read repositories, issues and pull requests, but both read and write web hooks (it’s which web hook events you subscribe to that controls which permissions needed)

When you hit create you’ll get the new password displayed, be sure to store it somewhere safe as this is the only chance you get to do so

If you find yourself in need of more permissions, you’ll have to revoke old and add an new app password with the new set of permissions.

Now that we have both the URI to talk with the Teams channel and the password to use we just need to find an API for fetching available repositories. Atlassian Bitbucket rest API is well documented here, and for listing repositories for specified user “/2.0/repositories/{username}” seems a perfect match:

GET /2.0/repositories/{username}
Returns all repositories owned by the specified account.

Next I needed an API to fetch hooks already configured on the repository, because I didn’t want to add the Teams hook if it already was configured. Here “ /2.0/repositories/{username}/{repo_slug}/hooks” seemed spot on:

GET /2.0/repositories/{username}/{repo_slug}/hooks
Returns a paginated list of webhooks installed on this repository.

Finally we need to be able to add a new web hook and that’s done by posting to the same endpoint as above

POST /2.0/repositories/{username}/{repo_slug}/hooks
Creates a new webhook on the specified repository.

Atlassian offers several ways to authenticate to the API where the easiest is basic auth which if chosen for this post, but they also i.e. offer more secure oauth.

So lets start scripting, to enable reuse I split this into four scripts

  • Get-BitbucketRepositories.ps1 
    Fetches all repositories for given user / organization
  • Test-BitbucketRepositoryHook.ps1
    Tests if a web hook is configured for a given repository
  • New-BitbucketRepositoryHook.ps1
    Adds a new web hook for given repository
  • EnsureMicorsoftTeamsOnAllRepos.ps1
    Composes the above scripts to ensure all repositories have Microsoft Teams notifications for given user / organization

So lets walk thru these scripts, starting with the usage of EnsureMicorsoftTeamsOnAllRepos.ps1 , this script takes four arguments, a Bitbucket user name, password and org/user (containing the target repositories), along with the Microsoft Teams web hook url to configure.

Usage of EnsureMicorsoftTeamsOnAllRepos.ps1

The first time the script executes you’ll see it output each repository missing the given web hook and then that it added it.

wcom/wcom-public [Missing]
wcom/wcom-public [Added]

The second time it should find that the given web hook exists.

wcom/wcom-public [Exists]

So what does EnsureMicorsoftTeamsOnAllRepos.ps1 look like


What does it do? Basically fetches all available repositories given user, password and user/org name using Get-BitbucketRepositories.ps1, then iterates over these and tests if given web hook exists using Test-BitbucketRepositoryHook.ps1, if it doesn’t exists it’ll try to add it and report “Added” or “Failed” depending on result from New-BitbucketRepositoryHook.ps1.

Cracking Get-BitbucketRepositories.ps1 open we’ll see


What the above script basically does is create an basic authorization header, fetch and merge all pages of repositories for a given user/org name returning each repositories full name in alphabetical order. Repository full name is the combination of owner and repository slug.

Digging into Test-BitbucketRepositoryHook.ps1 we’ll find


What the above script basically does is create an basic authorization header, fetch and merge all pages of a repository web hooks for a given user/org and repo slug. Then see and return if it finds the given web hook.

Investigating New-BitbucketRepositoryHook.ps1


This script creates an basic authorization header and the JSON payload given the supplied description, url and events and the reports it’s success using Test-BitbucketRepositoryHook.ps1 to see the web hook was added successfully.


Not only does scripts like these make it easier to migrate to the new service (in this case almost 500 repositories in 80 seconds), but also running it regularly picks up any new repositories created. A big win is also consistency — every repository is added in the same way, with same description, for same events and with same url.

If you have any questions or feedback please feel free to let me know!

Like what you read? Give Mattias Karlsson a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.