Provisioning Teams with a SharePoint Site Template, Power Automate and Microsoft Graph

Provisioning Teams with a SharePoint Site Template, Power Automate and Microsoft Graph

Last updated on September 3, 2023

Microsoft recently added an option to create a team for an Office 365 group via its modern team site. There is a a button at the bottom of the left-hand side navigation that allows you to create a Team with a single click. This is a great change and makes it easier to create a team for a particular group — especially if you are already browsing its site.

But could things be made even easier? Why can’t we just have an option during team site creation to have the team created straight away, automatically? Actually, we can, and in this blog post, I’ll show you how we can make that happen.

To achieve this, we are taking advantage of SharePoint site templates, Microsoft Power Automate and Microsoft Graph. The target is that when a user creates a new modern team site via the SharePoint Online UI, a team will get created for it automatically. The site is created using a custom site template, which will trigger a Power Automate flow, where we’ll call Microsoft Graph to provision the team.

Table of Contents

The Power Automate flow

Let’s create the Power Automate flow first. We’ll start by adding a When HTTP request is received trigger and inserting the schema below into it. We use this trigger, because the site template triggerFlow action makes a HTTP request to our Power Automate flow. The schema matches the body of the request.

{
    "type": "object",
    "properties": {
        "webUrl": {
            "type": "string"
        },
        "parameters": {
            "type": "object",
            "properties": {
                "event": {
                    "type": "string"
                },
                "product": {
                    "type": "string"
                }
            }
        }
    }
}

After that, add a Compose action and use the expression below to extract the last bit of the site URL, so we can use it in other actions.

last(split(triggerBody()?['webUrl'], '/'))

Now save the flow and note down the URL that appeared in the trigger. We’ll need it later when we create our site script.

Calling Microsoft Graph from Power Automate

Before you can call Microsoft Graph from Power Automate, you need to set up an application registration in your Azure Active Directory. To do that, follow the instructions I’ve given in my other blog post: How to set up an Azure AD application registration for calling Microsoft Graph. We are going to use client credentials for authentication, so just follow the instructions under the application identity chapter. When setting the permissions, select Sites.Read.All and Group.ReadWrite.All permissions.

After your app registration is set up, note down the tenant ID, client ID and client secret as described in the Information required for authentication chapter. In Power Automate, add three Initialize variable actions and insert those values into them. We will need to use these values in three different places, so it will be a lot faster to configure those actions when you can just select them from dynamic content. Also, if you later want to copy this flow to a different tenant, you only need to update the values in these three variables to get your flow working against a new application registration.

Getting the group ID

Before we can create a Team for an Office 365 group, we need to know its group ID. When a user creates a new Office 365 group enabled team site using our site template, the group gets created automatically, but the only information we get in Power Automate about the created site is the site URL we extracted earlier. Quite often the site name in the URL matches the group mailNickname, but not always. Because of this, we can’t simply fetch the group information from Graph with query $filter=mailNickname eq ‘siteurl’. Instead, we need to take a little detour.

We first need to get the site object from Graph using the site URL we extracted earlier (Output in the image below), and parse the response, so we can use the response content in other actions.



Schema:

{
    "type": "object",
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "createdDateTime": {
            "type": "string"
        },
        "description": {
            "type": "string"
        },
        "id": {
            "type": "string"
        },
        "lastModifiedDateTime": {
            "type": "string"
        },
        "name": {
            "type": "string"
        },
        "webUrl": {
            "type": "string"
        },
        "displayName": {
            "type": "string"
        },
        "root": {
            "type": "object",
            "properties": {}
        },
        "siteCollection": {
            "type": "object",
            "properties": {
                "hostname": {
                    "type": "string"
                }
            }
        }
    }
}

 

The response includes the site ID, which we can use to get the Documents library of the site, also known as the drive. The drive is shared by both the site and the Office 365 group objects, and as you can see from the response schema, the information we receive includes information about the owner > group > id. Right there is the group ID we need.


{
    "type": "object",
    "properties": {
        "@@odata.context": {
            "type": "string"
        },
        "createdDateTime": {
            "type": "string"
        },
        "description": {
            "type": "string"
        },
        "id": {
            "type": "string"
        },
        "lastModifiedDateTime": {
            "type": "string"
        },
        "name": {
            "type": "string"
        },
        "webUrl": {
            "type": "string"
        },
        "driveType": {
            "type": "string"
        },
        "createdBy": {
            "type": "object",
            "properties": {
                "user": {
                    "type": "object",
                    "properties": {
                        "displayName": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "owner": {
            "type": "object",
            "properties": {
                "group": {
                    "type": "object",
                    "properties": {
                        "email": {
                            "type": "string"
                        },
                        "id": {
                            "type": "string"
                        },
                        "displayName": {
                            "type": "string"
                        }
                    }
                }
            }
        },
        "quota": {
            "type": "object",
            "properties": {
                "deleted": {
                    "type": "integer"
                },
                "remaining": {
                    "type": "integer"
                },
                "state": {
                    "type": "string"
                },
                "total": {
                    "type": "integer"
                },
                "used": {
                    "type": "integer"
                }
            }
        }
    }
}

Creating the team

During Ignite, Microsoft added support for application permissions for the Create team operation. Until then, you were required to authenticate to Graph using a set of user credentials with a Teams license to be able to utilize the operation. When a set of service credentials were used to take care of the automatic provisioning, it could become a problem in large organizations, because a single user is allowed to create only 250 teams. But luckily that is no longer the case and we are able to use application permissions for this operation as well.

Here is an example of the body, but you can of course alter the team settings to fit your purpose.

{
  "memberSettings": {
    "allowCreateUpdateChannels": true
  },
  "messagingSettings": {
    "allowUserEditMessages": true,
    "allowUserDeleteMessages": true
  },
  "funSettings": {
    "allowGiphy": true,
    "giphyContentRating": "strict"
  }
}

 

Now our Power Automate flow is ready and overall it should look like this. Make sure you’ve saved it, and let’s move on to create a site script for our site template.

 

Creating a SharePoint Site Template to trigger our Power Automate flow

Create a site script (JSON file) with the following content. Replace the URL with the one from your flow trigger.

{
    "$schema": "schema.json",
    "actions": [
        {
            "verb": "triggerFlow",
            "url": "https://prod-57.westeurope.logic.azure.com:443/workflows/9bb732 ...",
            "name": "Team site + Teams", 
            "parameters": 
            { 
               "event": "Microsoft Event", 
               "product": "SharePoint" 
            }
        }
    ], 
    "bindata": { }, 
    "version": 1
};

You might also want to include some other configurations in the site script while at it, such as activating a company branded theme for the site. If you are interested in doing that or want to know more about site templates and site scripts in general, check out my Ultimate Guide to SharePoint Site Templates and Site Scripts. It has been very popular among readers.

When your site script is finished, deploy it with this PowerShell script. You’ll also create the site template for it at the same time. If you have not yet installed the SharePoint Online Management Shell, check this other blog post for instructions.

$adminSiteUrl = "https://laurakokkarinen-admin.sharepoint.com"
$siteScriptFile = "C:\site-script.json" # path to site script file

$webTemplate = "64" # 64 = Office 365 group connected team site
$siteScriptTitle = "Team site + Teams"
$siteDesignTitle = "Team site + Teams"
$siteDesignDescription = "Custom team site template which provisions a Team via Power Automate."
$previewImageUrl = "" # if left empty, the default preview image will be used.

Connect-SPOService $adminSiteUrl

$siteScript = (Get-Content $siteScriptFile -Raw | Add-SPOSiteScript -Title $siteScriptTitle) | Select -First 1 Id

Add-SPOSiteDesign -SiteScripts $siteScript.Id -Title $siteDesignTitle -WebTemplate $webTemplate -Description $siteDesignDescription -PreviewImageUrl $previewImageUrl

 

Now you should be able to see your site template listed in the drop-down menu when creating a new modern team site in SharePoint Online. When you use it, you’ll get a team site and a Teams team for it automatically. You also retain the default Team Site template, which you can still use when you just want a team site but don’t want a team for it. Note that if your tenant has restrictions regarding who are allowed to create Office 365 groups, the custom site template is only visible to those users who can.

Afterword

Workspace provisioning is always interesting. The more we can automate and optimize, the better! I hope you enjoyed reading this article and found it useful. Or perhaps it sparked up your imagination? Let me know in the comments below if you have an interesting idea or if you’ve already built some useful provisioning solutions utilizing the site template -> Power Automate pipeline.

Also, feel free to take a look at my other articles, and follow me on Twitter if you’d like to get a tweet from me when I publish new content. Thank you for reading and until next time!

Laura



19 thoughts on “Provisioning Teams with a SharePoint Site Template, Power Automate and Microsoft Graph”

  • Hi Laura,
    Great article and thanks for sharing! I am having an issue with the last item in the Flow HTTP PUT to create the Team from the Group GUID. It comes with the following error: “groupId needs to be a valid GUID.”

    Any help would be appreciated! Thanks again! 🙂

    “error”: {
    “code”: “BadRequest”,
    “message”: “groupId needs to be a valid GUID.”,
    “innerError”: {
    “date”: “2020-10-01T10:33:16”,

  • Thank you so much for documenting! I had to do a bit of a variation and create a custom connector as I do not have access to premium connectors but I was able to get a team created from a Site creation!

  • Hi Laura
    This is really helpful, The flow runs successfully, Call it from Site Script, and the run was successful.
    But a small hitch, The notification in new Team site – .[Create a Team with a single click. This is a great change and makes it easier to create a team for a particular group — especially if you are already browsing its site.], want to hide that as well, Is it possible? From where it’s coming?
    Thank you
    ananda

    • Hi Ananda,

      The “Create a team” link will disappear automatically soon — but not immediately — from the team site after the team has been created.

      Laura

  • Hello Laura
    Thank you for another wonderful post, But I’m getting error at last step – Create Team.
    {
    “error”: {
    “code”: “Request_BadRequest”,
    “message”: “Specified HTTP method is not allowed for the request target.”,
    “innerError”: {
    “date”: “2020-07-19T16:01:07”,
    “request-id”: “66834978-50ea-44f1-9d79-9afffc69b1ff”
    }
    }
    }
    I’ve set up the API Permission like following. Still no luck.

    Directory.ReadWrite.All, – Delegated
    Directory.ReadWrite.All – Application
    Group.ReadWrite.All – Delegated
    Group.ReadWrite.All – Application
    Sites.Read.All – Application
    Team.Create – Delegated
    Team.Create – Application
    Team.ReadBasic.All -Delegated
    Team.ReadBasic.All – Application

    Could you please help,
    Thank you
    ananda

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.