There are various ways of creating Teams with Power Automate:
- The Create Team action in Flow. Currently, very limited options available.
- Create a Team from an Azure Group. This still requires the Graph API to create the group.
- Clone a current Team (Graph)– this is a really useful method, as it allows non IT people to create template Teams, which can then be cloned via a Flow/App. Downside, private channels cannot be cloned.
- PowerShell. This can be called via Flow into an Azure Runbook. Tabs cannot be easily added yet via PowerShell.
- Create a Team using the Graph API. This gives the most options. All the options. It can be used to create any amount of tabs / channels etc. This is where all the fun is.
- Creating Teams, channels and tabs in one go
1. Built in Create a Team Flow Action
Create a team with the Create Team Action. Simple, but no options except for the public / private visibility. There are also actions to add channels (no options) and to add a user (Owner or member) to a Team (but not channel). Over time, one expects these actions to bring in more options. Creating Teams and Channels this way seems quite fast.

2. Create a Team from an Office 365 Group.
This seems to be Microsoft’ s preferred method. The members of the group become members of the Team. Creating an Office Group cannot be handled in Flow yet, so again an HTTP call from Flow is required, which kind of defeats the point to me. Also the documentation states waiting up to 15 minutes after group creation before creating the Team is wise. This also requires Graph to create a Team this way.
3. Cloning a Team
I like this method. Create a private team template (or multiple templates) in Teams, with any channels and Tabs required. These can all be created inside of Teams and modified at any time by non techie people, and does not need the Flows being amended.
Here is a Team I created earlier, with an added channel and added tabs.

In Flow, I create a simple HTTP request to Graph. The parts of the Team to be cloned can be specified in the JSON body.
{
"displayName": "A Cloned Graph Team",
"mailNickname": "clonegraphteam",
"description": "Testing the cloning feature from Microsoft Graph API",
"partsToClone": "apps,tabs,settings,channels,members",
"visibility": "public"
}
The Flow runs under an app registration (see a previous post on this). The GUID of the Team to be cloned is required (easiest way to find is to go into Teams, click on the … and get link to Team. The generated URL contains the groupid={xxxx} where xxxx is the Team ID). Note, only Microsoft apps are cloned, not custom apps. Documentation.

4. Creating a Team using Graph
Two ways of doing this. The big bang approach or the incremental approach, i.e. create a Team, then add tabs, add channels etc.
All these Graph HTTP calls use the OAuth authentication as pictured above. Each Graph call requires certain permissions set for the app registration in Azure, which will be described by each sep.
The initial Team creation requires an owner. Adding multiple owners/members on initial creation I believe is not possible yet, but requires a second call to bulk add members.
First, each part in turn, and then the big bang approach!
4.1 Create a Team
First, a substitute for the option 1 above, create a simple Team. The JSON below sets the display name and description, and adds an owner which is mandatory. Replace the AZURE-GUID-OF-USER string with a real user in Azure !
{
"template@odata.bind":"https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
"displayName":"My Awesome Team",
"description":"They work so well",
"members":[
{
"@odata.type":"#microsoft.graph.aadUserConversationMember",
"roles":[
"owner"
],
"user@odata.bind":"https://graph.microsoft.com/v1.0/users('AZURE-GUID-OF-USER')"
}
]
}
The Graph permissions creating a Team for the application registration (Application) or Delegated.
Delegated | Team.Create |
Application | Team.Create |
Using the HTTP Connector makes the Flow checker throw an odd error “Fix Invalid expression(s) for the input parameter(s) of operation”, which prevents the Flow from being saved. This took a long while to solve, with people suggesting to use the HTTP Azure connector where this error does not appear, particularly as it does not use the application registration but the user owning the Flow connection, which makes the Graph permissioning more awkward.

So to solve this, all that is needed is adding a second @ symbol in the above JSON on the line:
“@odata.type”:”#microsoft.graph.aadUserConversationMember”,
to make it:
“@@odata.type”:”#microsoft.graph.aadUserConversationMember”,
and then the Flow can be saved and everything is wonderful. Note, the second @ vanishes when you re-edit the Flow, so remember to add it back if you edit the JSON again ! This issue seems to occur on the adding members lines only. All future examples will include a double @@illuminocity
Any other place where @odata.type exists has the same issue, so watch out for it!
The Flow Action:

The result which is within a couple of seconds:

4.2 Adding a channel to the Team
Note: A channel can not be created which is automatically shown this way. That is only possible on Team creation, not after a Team exists. If this is important, then the big bang approach is the only current way.
Note 2: There is no way to change the default channel order from alphabetically, so if order is important, prefix the channels with numbers.
The Graph permissions creating a Channel for the application registration (Application) or Delegated.
Delegated | Channel.Create |
Application | Channel.Create.Group |
The code, with an owner defined and a private channel:
{
"@@odata.type": "#Microsoft.Graph.channel",
"description": "This is a private channel",
"displayName": "Marmite is the best Channel",
"members": [
{
"@@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"user@odata.bind": "https://graph.microsoft.com/v1.0/users('AZURE-GUID-OF-USER')"
}
],
"membershipType": "private"
}
The Flow Action:

The result:

Other stuff
Adding a PowerBI tab:
dynamics tab / dataverse tab / whiteboard / removing wiki / canvas app? / web tab
5. Adding Tabs
To add a tab, the adder must be a member of the Team. Permissions:
Delegated | TeamsTab.Create |
Application | TeamsTab.Create.Group |
Any type of tab can be added. First example, a simple web URL. Microsft has a Teams app catalog with the full list of apps available, and their corresponding IDs. Your organisation may also have allowed apps, which can found using the this call in Graph (developer console is easiest)
GET https://graph.microsoft.com/v1.0/appCatalogs/teamsApps?$filter=distributionMethod eq ‘organization’
Remove the filter above to list every app available. There are quite a few. Or search on displayName; for example to find Dynamics:
https://graph.microsoft.com/v1.0/appCatalogs/teamsApps?$filter=startswith(displayName,’Dyn’)
which returns – “id”: “cd2d8695-bdc9-4d8e-9620-cc963ed81f41”.
To add a tab, the Team ID and the channel ID of the Team must be noted. A tab is added to a channel, not a Team. A plain Team will have a General Channel auto created, and it is that channel ID required if no other channels are present.
To get the IDs required from an existing Team, go into Teams, select the Team, and click on the ellipsis and choose Get Link to team, and copy the URL.

The URL will contain the groupID, which is the Teams ID, and the channel ID which is the part after team/ ending in tacv2.
Team ID = ef05f579-e17d-493c-a099-5ba678929b1f
Channel ID = 19%3aVZXryv0jR8KlDJjVAt26uP5I2bV-61OHhoIiE23MUB01%40thread.tacv2
In Flow, the HTTP POST action builds the URL with the above 2 values:
POST /teams/{team-id}/channels/{channel-id}/tabs to become:

The body contains the teamsApps for web tab, and the displayName and URL.
{
“teamsApp@odata.bind”: “https://graph.microsoft.com/v1.0/appCatalogs/teamsApps(‘com.microsoft.teamspace.tab.web’)”,
“displayName”: “A Pinned Website”,
“configuration”: {
“contentUrl”: “https://docs.microsoft.com/microsoftteams/microsoft-teams”
}

There is a good MS doc page on the pre-configured Team tabs, which explains the parameters required to add files and document libraries from SharePoint. This allows you to add Excel, Word, PDF and PowerPoint files.
Example of adding a Word document to a tab. The body of the previous request is altered to the below (replace MYSPDOMAIN with the relevant domain). Opening the file in SharePoint, the URL is required, and within that, the sourcedoc field ( the source docID is in the URL thus: sourcedoc=%7B{sourceDocId}%7D).
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('com.microsoft.teamspace.tab.file.staticviewer.word')",
"displayName": "My Word Doc",
"configuration": {
"entityId": "C58A79C2-A206-442B-891D-95A628AB09A8",
"contentUrl": "https://MYSPDOMAIN.sharepoint.com/:w:/r/sites/DemoSite/_layouts/15/Doc.aspx?sourcedoc=%7BC58A79C2-A206-442B-891D-95A628AB09A8%7D&file=RTF1.docx"
}
}

To set up a tab for OneNote, PowerBI, Forms, Planner, Stream and SharePoint lists, the info is all in the MS doc page and here for completeness. Note that these do not support configuration, so the tab is added but there is no content. When the tab is first entered, it has to be configured at that point, for example, choosing the relevant OneNote notebook to add.
Type | teamsAppId | Configuration |
Wiki | com.microsoft.teamspace.tab.wiki | None |
Planner | com.microsoft.teamspace.tab.planner | None |
Stream | com.microsoftstream.embed.skypeteamstab | None |
Forms | 81fef3a6-72aa-4648-a763-de824aeafb7d | None |
OneNote | 0d820ecd-def2-4297-adad-78056cde7c78 | None |
PowerBI | com.microsoft.teamspace.tab.powerbi | None |
SharePoint Page/List | 2a527703-1f6f-4559-a332-d8a7d288cd88 | None |
White Board | 95de633a-083e-42f5-b444-a4295d8e9314 | None |
For any of these, the body is quite simple. Here is an example of adding a White Board. in the odata.bind, in the teamsApps(’95de633a-083e-42f5-b444-a4295d8e9314′) part, replace the value in single quotes with the value form the table above, a GUID or a phrase. Display Name is the one thing under control here.
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('95de633a-083e-42f5-b444-a4295d8e9314')",
"displayName": "My White Board"
}
Dynamics Tab
To add a specific page in Dynamics to Teams, for example, All Contacts,
Deleting the Wiki Tab
The wiki tab in Teams does not seem popular for some reason, but is auto created. To delete the this tab, or any tab, the ID of the tab is required. The simplest way is to list the tabs in a channel, parse for the display name (Wiki by default), and then do a Graph call to delete it.
First, use the same HTTP Graph call from before, but this time switching POST to GET. Throw the results into a Parse JSON for legability, then filter the array on the name of the tab, and finally DELETE the tab passing in the ID:

The parse JSON uses the schema:
{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"@@odata.count": {
"type": "integer"
},
"value": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"displayName": {
"type": "string"
},
"webUrl": {
"type": "string"
},
"configuration": {
"type": "object",
"properties": {
"entityId": {},
"contentUrl": {},
"removeUrl": {},
"websiteUrl": {},
"wikiTabId": {
"type": "integer"
},
"wikiDefaultTab": {
"type": "boolean"
},
"hasContent": {
"type": "boolean"
}
}
}
},
"required": [
"id",
"displayName",
"webUrl",
"configuration"
]
}
}
}
}

and the DELETE action block uses the formula:
first(body(‘Filter_array’))?[‘id’]
to avoid a Apply to Each loop. And there goes the Wiki tab, or any other undesired tab.
6. The Big Bang approach
For simplicity, but not for speed( creating everything in one hit seems to take a while for it all to appear in Teams, much longer than individually creating), the whole Graph call can be done in one action. To create the following Team, with 3 channels, and tabs on B1 Channel:

requires just one Graph call. The top of the action is:

and the full body is below:
This creates a private team of name “A Big Bang”, adds 3 channels
{
"template@odata.bind": "https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
"visibility": "Private",
"displayName": "A Big Bang",
"description": "This is a sample engineering team, used to showcase the range of properties supported by this API",
"channels": [
{
"displayName": "A1 Channel",
"membershipType": "private",
"isFavoriteByDefault": true,
"description": "This is a private channel for A1 group members."
},
{
"displayName": "B1 Channel",
"membershipType": "private",
"isFavoriteByDefault": true,
"description": "This is a private channel for B2 group members.",
"tabs": [
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('com.microsoft.teamspace.tab.web')",
"displayName": "A Pinned Website",
"configuration": {
"contentUrl": "https://docs.microsoft.com/microsoftteams/microsoft-teams"
}
},
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('com.microsoft.teamspace.tab.youtube')",
"displayName": "A Pinned YouTube Video",
"configuration": {
"contentUrl": "https://tabs.teams.microsoft.com/Youtube/Home/YoutubeTab?videoId=X8krAMdGvCQ",
"websiteUrl": "https://www.youtube.com/watch?v=X8krAMdGvCQ"
}
},
{
"displayName": "Whiteboard",
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps/95de633a-083e-42f5-b444-a4295d8e9314",
"configuration": {
"entityId": null,
"contentUrl": null,
"removeUrl": null,
"websiteUrl": null
}
}
]
},
{
"displayName": "C1 Channel",
"membershipType": "private",
"isFavoriteByDefault": true,
"description": "This is a private channel for C1 group members.",
"members": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"user@odata.bind": "https://graph.microsoft.com/v1.0/users('7b1c736d-1a63-4760-89da-360d22144bb8')"
}
]
}
],
"members": [
{
"@odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"user@odata.bind": "https://graph.microsoft.com/v1.0/users('7b1c736d-1a63-4760-89da-360d22144bb8')"
}
],
"memberSettings": {
"allowCreateUpdateChannels": true,
"allowDeleteChannels": true,
"allowAddRemoveApps": true,
"allowCreateUpdateRemoveTabs": true,
"allowCreateUpdateRemoveConnectors": true
},
"guestSettings": {
"allowCreateUpdateChannels": false,
"allowDeleteChannels": false
},
"funSettings": {
"allowGiphy": true,
"giphyContentRating": "Moderate",
"allowStickersAndMemes": true,
"allowCustomMemes": true
},
"messagingSettings": {
"allowUserEditMessages": true,
"allowUserDeleteMessages": true,
"allowOwnerDeleteMessages": true,
"allowTeamMentions": true,
"allowChannelMentions": true
},
"discoverySettings": {
"showInTeamsSearchAndSuggestions": true
},
"installedApps": [
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('com.microsoft.teamspace.tab.vsts')"
},
{
"teamsApp@odata.bind": "https://graph.microsoft.com/v1.0/appCatalogs/teamsApps('1542629c-01b3-4a6d-8f76-1938b779e48d')"
}
]
}
I’ll stop here and continue in a Part 2 or I’ll never finish ! Part 2 will discuss the PowerShell alternative for people happier in that world, and the following issues:
Polling a created team/channel for creation. Teams are created in the background so one cannot assume they are there straight after creation.
Authentication; token vs secret.
Child Flows to retry adding members etc. / bulk adding members. Again, members cannot be added till the Team exists!
Speed of big bang vs individually. Big bang is easier to script, but seems to take a long time to build.