How to Deploy a Custom Website Tab in Teams using Microsoft Graph API and PowerShell

Microsoft Teams is quickly rising in popularity as a unified communication and collaboration platform. And since Microsoft is recommending (or pushing) organizations to adopt Teams, the number of the user base can only rise from this point.

Organizations often need to post information for employees like corporate news or policies. The usual way that these are posted is in a SharePoint Communication site.

Oftentimes, users are sent emails showing the link to the said site to visit. And whether you admit it or not, these emails are mostly ignored or tucked away to the bottom of the to-do list.

With the help of the Microsoft Graph API combined with PowerShell scripting, you can deploy a website tab in Microsoft Teams to display a relevant custom web page. And in this article, you will learn to do just that.

Getting Prepared

This article will be a walkthrough. If you intend to follow along, make sure you have the following prereqs set up ahead of time.

  • An Office 365 Tenant. Request for a trial if you do not have it yet.

  • A script editor, like Notepad++ or an Integrated Scripting Environment (ISE) like  Windows PowerShell ISE and  Visual Studio Code.

  • Windows PowerShell 5.1 or PowerShell Core 6+.

  • A registered app in Azure AD with proper permissions. Please refer to Register a New Application Using the Azure Portal if you don’t know how to do that.

  • The registered app must have the following settings.

    –            API to use - Microsoft Graph API

    –            API permission type to select - Application Permission

    –            API permissions to add - Group.ReadWrite.All

  • The registered app must be granted admin consent.
  • The Application ID, Directory ID and the Client Secret of the registered app.
  • A web page whose content will be in the new tab to be created in Teams. In this article, a fictitious Daily News page will be used.

Knowing the MS Graph API Basics for Microsoft Teams

To request information from the Microsoft Teams using the Microsoft Graph API, you must take note of the key information that makes up a request.

  • There are two Graph API versions as of this writing, namely 1.0 and beta. In this article, version 1.0 will be used.

  • The standard API URL to use is<API-version>

  • An access token is required. You will learn how to acquire access tokens in the Acquiring MS Graph API Access Token section in this article.

  • A request body in JSON format. You will learn how to create the request body using a custom object and convert it to a JSON string in the Defining the New Website Tab Details section in this article.

  • The different paths to append to the end of the API URL. This represents which information is being requested. These paths are:

    –            /Groups - used for requests targeting Groups

    –            /Teams - used for requests targeting Teams

    –            /Channel- used for requests targeting channels inside a team

    –            /Tabs - used for requests targeting tabs inside a channel

    Example: To get the list of all Groups/Teams, the request URL would be:

    Example: To get all channels inside a team, the URL would be:<TEAM-ID>/channels

    Example: To get all tabs inside a channel, the URL would be:<TEAM-ID>/channels/<CHANNEL-ID>/tabs

Acquiring MS Graph API Access Token

Once you’ve satisfied all the requirements, the next step is to acquire the access token that will be used to authorize the requests.

Copy and paste the code below into your script editor. Then, change the value of the $TenantID, $ClientID and $ClientSecret variables with the ones from your registered app. If you don’t have this information, refer to this link to find out how and where to get them.

Once you’ve updated the variables, paste the code into your PowerShell session to run it. The code requests an access token and stores the returned value to the $token variable.

$TenantID = 'TENANT-ID'
$ClientID = 'CLIENT-ID'
$ClientSecret = 'CLIENT-SECRET'

$body = @{grant_type="client_credentials";scope="";client_id=$ClientID;client_secret=$ClientSecret}
$oauth = Invoke-RestMethod -Method Post -Uri$TenantID/oauth2/v2.0/token -Body $body
$token = @{'Authorization'="$($oauth.token_type) $($oauth.access_token)"}

To give you an idea of what the authorization token looks like, see the screenshot below.

MS Graph API Access Token

Please note that requested access tokens are only valid for 60 minutes. Once it expires, a new access token must be requested.

Creating a PowerShell Script to Deploy a Website Tab in Teams

In this section, you’ll go through the process of creating a PowerShell script to create a website tab inside the General channel of each Team. So fire up your script editor and let’s get started.

Why choose the General channel for deploying the website tab? Because it is the default channel included in each provisioned Team, and it cannot be deleted.

Defining the New Website Tab Details

First, define the details for the new tab to be created. These details include the tab name, content URL and the tab type properties.

Using the code below, the first line stores the name of the tab to the $tabName variable. The second line stores the URL of the web page to be displayed inside the tab. The URL value is saved in the $contentURL variable.

$tabName = 'Daily News'
$contentURL = '!.aspx'

The next code block below creates the property collection object of the new tab and save the result in the $newTabConfig variable. The displayName property takes the value previously defined in the $tabName variable.

Then, the contentURL and websiteURL properties take the value of the $contentURL variable that contains the URL of the custom web page. The "[email protected]" property defines the type of tab. In this case, the tab to be added is a built-in type with ID of

The TeamsAppID value is a built-in tab type in Microsoft Teams. To learn more about the different built-in tab types, please visit Configuring the Built-in Tab Types in Microsoft Teams.

The object is then converted to the JSON format by piping it to the ConvertTo-Json cmdlet.

Do not make any changes to the below code. You only need to copy and paste it into your script.

$newTabConfig = [ordered]@{
    displayName   = $tabName
    "[email protected]" = ""
    configuration = @{
        contentUrl = $contentURL
        websiteUrl = $contentURL
} | ConvertTo-Json

To give you an idea of what the JSON body looks like, below if the converted value of the code above.

JSON-formatted string

Getting All Teams in Microsoft Teams

The goal of the script is to add a new tab to the General channel inside all Teams in Microsoft Teams. This means the list of all available Teams must be retrieved first. Use the code below to get a list of all available Teams.

The first line creates the $uri variable to store the entire URL for requesting the Office 365 groups and return the id, displayName and resourceProvisioningOptions properties only.

The second line filters the result to include only the groups with whose resourceProvisioningOptions contains the value Team. Copy this code below into your script.

$uri = ('$select=id,displayname,resourceProvisioningOptions')
$teams = (Invoke-RestMethod -Method Get -Uri $uri -Headers $token).Value | Where-Object {$_.resourceProvisioningOptions -contains 'Team'}

Teams are essentially Office 365 groups whose property resourceProvisioningOptions contains the value Team. Reference - List All Teams in Microsoft Teams for an Organization.

Looping Through All the Teams and Add the New Website Tab

This next code block will perform the following actions:

  • Loop through all the Teams retrieved and stored in the $teams variable.
  • Get the properties of the General channel inside each Team.
  • Check if the website tab already exists in each Team’s General channel.

    –            If the website tab does not exist, add the new website tab in the current Team and display a message.

    –            If the website tab already exists, skip the current Team and display a message. This is to avoid creating                        duplicate tabs.

    You can learn more about what each line of code does by referring to the comments above each line. Copy the code below and add it to the end of your script and save it as DeployWebsiteTab.ps1.

    # Loop through all teams
    foreach ($team in $teams) {
        # Get the General Channel properties
        $channel = (Invoke-RestMethod -Method Get -Uri ("$($team.ID)/channels" + '?$filter=DisplayName eq ' + "'General'") -Headers $token).Value

        # Check if the tab with the same value as the $tabName aleady exists
        $tab = (Invoke-RestMethod -Method Get -Uri ("$($team.ID)/channels/$($channel.ID)/tabs" + '?$filter=DisplayName eq ' + "'" + $tabName + "'") -Headers $token).value

        # Add the tab if the TAB does not exist in the General channel
        if (!$tab) {
            Write-Output "ADD: '$tabName' in [$($team.displayName)\General]"
            Invoke-RestMethod -Method POST -Uri "$($team.ID)/channels/$($channel.ID)/tabs" -Headers $token -Body $newTabConfig -ContentType application/json
        # Skip the tab if the TAB already exist in the General channel to avoid duplication
        else {
            Write-Output "SKIP: '$tabName' in [$($team.displayName)\General]"

Putting the Script in Action

Now that you have the script ready, it is time to put it to the test. But first, you must establish a control to determine whether the script works as expected. It is strongly recommended to test this script on a development or test environment before running it on production.

In this example, there are three Teams namely DevOps, ITOps and TechSupport. The goal is to deploy the website tab to each Team’s General channel.

First, confirm that the Team’s do not have the website tab to be added yet. In this example, it is the Daily News website tab.

The website tab does is not present in the General channel

Now that you’ve confirmed that the website tab is not present in the General channel, this means that when your script, the website tab will be added to each Team.

Open PowerShell and run the DeployWebsiteTab.ps1 script. The screenshot below shows that the script added the Daily News tab to all three Teams.

The website tab is added by running the PowerShell script

To confirm the presence of the website tab, go back to the Microsoft Teams desktop client or the Microsoft Teams web app and manually check the General channel. The screenshot below shows that the website tab has been added to the Team.

The website tab has been created

Moreover, the script also has the logic to skip adding the website tab to a Team if the tab already exists. To test that logic, manually remove the website tab from one channel and run the script again. In this example, the tab is removed from the DevOps team as shown below.

Removing the website tab

This time, when you run the script again, the expected results are shown below. The result shows that the script skipped the ITOps and TechSupport teams and added the website tab to the DevOps team only.

ITOps and TechSupport teams are skipped. The tab is only added to the DevOps team.


In this article, you have learned the basic components that make up the MS Graph API requests to MS Teams. You’ve also learned what application permission is required and how to generate an authentication token to access MS Teams.

You also created a PowerShell script to automate the deployment of a website tab to display custom web page contents to each team.

The script featured in this article only provides the basic functionality to deploy a website tab. It can be improved to include error handling, logging, or reporting functionality. It is up to you to use your PowerShell skills to make these improvements.

Depending on your implementation strategy, the script should be able to run using the Windows Task Scheduler, Jenkins, or even in Azure Automation.


Get Started with WhatsUp Gold

Subscribe to our mailing list

Get our latest blog posts delivered in a monthly email.

Loading animation


Comments are disabled in preview mode.