Creating Microsoft Team using Graph

In the previous script I provide a way to browse and export Microsoft Teams Information using Graph but this time I have taken that to next level.  The script below will allow you to create a Team, Channel, Members, Owners, Tabs and Message, all using Microsoft Graph.  The script is created for someone who do not have great knowledge of Graph and may act as starting point.  It is not a complete solution but can be use to provision team with basic to medium complexities.  Creating Team from Graph and PowerShell may look a bit complex but once you read the graph documentation, It become very easy.  The script uses both v1.0 and beta endpoints based on their availability.

The CSV format is as following

ID,TeamName,MailNickName,TeamType,Classification,DeleteExistingTeam,Description,Channels,Owners,Members,Tabs,
1,TeamMXC,TeamMXC,Private,Internal,Yes,Demo Team will provide support,Channel1#Channel2#Channel3,GarthF@tenant.onmicrosoft.com#jerryyasir@tenant.onmicrosoft.com,GarretV@tenant.onmicrosoft.com#abrown@tenant.onmicrosoft.com,C:\temp\CreateTeam-Members.csv,Channel1;Tab1;Tab2#Channel2;Tab3;Tab4

Script

#$scopes = @(“Group.Read.All”,”Group.ReadWrite.All”,”User.ReadWrite.All”, “Directory.Read.All”,”Reports.Read.All”)
$scopes = $null

$ApplicationID = “”
$Password = ”
$appaaddomain = ‘tenant.onmicrosoft.com’
$CurrentUser = “jerryyasir@tenant.onmicrosoft.com”
 
$GraphURL = “https://graph.microsoft.com/beta”
$graphV1Endpoint = “https://graph.microsoft.com/v1.0″

#Establish connection
If($scopes.Length -gt 0){
     Connect-PnPOnline -Scopes $scopes
} elseif($ApplicationID.Length -gt 0) {
     #Connect-PnPOnline -AppId $ApplicationID -AppSecret $Password -AADDomain $appaaddomain
     Connect-PnPMicrosoftGraph -AppId $ApplicationID -AppSecret $Password -AADDomain $appaaddomain
} else {
     write-host ‘Connection issue’ -ForegroundColor Red
     exit
}

$token = Get-PnPAccessToken

$CSVPath = “C:\temp\CreateTeam-Basic-Graph.csv”

$Data = Import-Csv -Path $CSVPath

foreach($team in $Data)
{
     Write-Host “Team Creation Started…” $team.TeamsName -ForegroundColor Yellow
     $TeamName       = $team.TeamName
     $displayname    = $team.TeamName
     $MailNickName    = $team.MailNickName
     $AccessType     = $team.TeamType
     $Description    = $team.Description
     $Classification = $team.Classification
     $TeamChannels   = $team.Channels
     $TeamMembers    = $team.Members
     $TeamOwners     = $team.Owners
     $DeleteExistingTeam    = $team.DeleteExistingTeam
  
     #$url = “$GraphURL/groups?`$filter=displayName eq ‘TeamABC'”
     $getTeamFromGraphUrl = “$GraphURL/groups?`$filter=displayName eq ‘” + $TeamName + “‘”
     $teamAlreadyExistResponse = Invoke-RestMethod -Uri $getTeamFromGraphUrl -Headers @{Authorization = “Bearer $token”}
     if($teamAlreadyExistResponse.value.Count -gt 0){
         foreach($r in $teamAlreadyExistResponse.value){
             if($r.resourceProvisioningOptions -eq ‘Team’){
        
                 $GroupCreatedDateTime = $r.createdDateTime
                
                 $TeamID = $r.id
                 $TeamsOwnerUrl =  “$GraphURL/groups/$TeamID/owners”
                 $teamsOwnersResponse = Invoke-RestMethod -Uri $TeamsOwnerUrl -Headers @{Authorization = “Bearer $token”}
                 $OwnerName = “”
                 if($teamsOwnersResponse)
                 {
                     Write-Host ”    Team Owners:”
                     foreach($owner in $teamsOwnersResponse.value)
                     {
                         $OwnerName += $owner.displayName + “;”
                     }
                     $teamsOwnersResponse = $null
                 }
                 write-host “The Team $($r.displayname) Created On $GroupCreatedDateTime Owned by $OwnerName already exist on the tenant.” -ForegroundColor Yellow
                
                 if($DeleteExistingTeam)
                 {
                    
                 }
            
             }
             else {
                 write-host $r.displayname “is an O365 Group.” -ForegroundColor Green
             }
         }
     }
    
     else
     {
         $arrayMembers = New-Object System.Collections.ArrayList
         try
         {
             $arrTeamMembers = $TeamMembers -split “#”
             if($arrTeamMembers)
             {
                 for($i =0; $i -le ($arrTeamMembers.count – 1) ; $i++)
                 {
                     $MemberUrl = “$graphV1Endpoint/users”
                     $UserUserPrincipalName = $arrTeamMembers[$i]
                     if($UserUserPrincipalName -ne $CurrentUser)
                     {
                         #$arrayMembers.Add(“$MemberUrl/$UserUserPrincipalName”)
                         $arrayMembers.Add($UserUserPrincipalName)
                     }
                 }
             }
         }
         Catch
         {
             Write-Host “There is issue with Channel settings in CSV, Check and Fix:. $teamchannels”
         }
                
         $arrayOwners = New-Object System.Collections.ArrayList
                
         try
         {
             $arrTeamOwners = $TeamOwners -split “#”
             if($arrTeamOwners)
             {
                 for($i =0; $i -le ($arrTeamOwners.count – 1) ; $i++)
                 {
                     $OwnerUserPrincipalName = $arrTeamOwners[$i]
                     $OwnerUrl = “$graphV1Endpoint/users”
                     $arrayOwners.Add($OwnerUserPrincipalName)
                 }
             }
         }
         Catch
         {
             Write-Host “There is issue with Channel settings in CSV, Check and Fix:. $teamchannels”
         }

        $arryGroupType = @(“Unified”)
        
         $arrayOwnersInREST = New-Object System.Collections.ArrayList
         $arrayMembersInREST = New-Object System.Collections.ArrayList
         foreach($Member in $arrayMembers)
         {
             $FindMemberUrl = “https://graph.microsoft.com/v1.0/users/” + $Member + “?`$Select=Id”
             $Response = Invoke-RestMethod -Uri $FindMemberUrl -Headers @{Authorization = “Bearer $token”} -Method Get -ContentType “application/json” -Verbose
             if($Response)
             {
                 $Response.id
                 $MembersUrl = “https://graph.microsoft.com/v1.0/Users/$($Response.id)”
                 $arrayMembersInREST.Add($MembersUrl)
             }
         }
         foreach($owner in $arrayOwners)
         {
             $FindOwnerUrl = “https://graph.microsoft.com/v1.0/users/” + $owner + “?`$Select=Id”
             $Response = Invoke-RestMethod -Uri $FindOwnerUrl -Headers @{Authorization = “Bearer $token”} -Method Get -ContentType “application/json” -Verbose
             if($Response)
             {$Response.id
                 $OwnerUrl = “https://graph.microsoft.com/v1.0/Users/$($Response.id)”
                 $arrayOwnersInREST.Add($OwnerUrl)
             }
         }
        
         $FindOwnerUrl = “https://graph.microsoft.com/v1.0/users/” + $CurrentUser + “?`$Select=Id”
         $Response = Invoke-RestMethod -Uri $FindOwnerUrl -Headers @{Authorization = “Bearer $token”} -Method Get -ContentType “application/json” -Verbose
         if($Response)
         {
             $Response.id
             $CurrentUserAsMemberUrl = “https://graph.microsoft.com/v1.0/directoryobjects/$($Response.id)”
                    
             $CurrentUserAsMember = “$graphV1Endpoint/groups/$TeamID/members/`$ref”
             $body = [ordered]@{
                 “@odata.id” = $CurrentUserAsMemberUrl
             }
             $bodyJSON = $body | ConvertTo-Json 
             Invoke-RestMethod -Uri $CurrentUserAsMember -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
                    
             $PlannerUri = “$GraphURL/planner/plans”
             $body = [ordered]@{
                 owner = $TeamID;
                 title = $TeamName;
             }
             $bodyJSON = $body | ConvertTo-Json 
             Invoke-RestMethod -Uri $PlannerUri -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
             Write-Host ”      A planner plan $TeamName is now added to the Team.” -ForegroundColor Green
         }
                
         $GroupUrl = “$graphV1Endpoint/groups”
         $body = [ordered]@{
             displayName = $TeamName;
             description = $Description;
             groupTypes = $arryGroupType;
             mailEnabled= $true;
             mailnickname = $MailNickName;
             securityEnabled=$false;
             “members@odata.bind” = $arrayMembersInREST;
             “owners@odata.bind” = $arrayOwnersInREST;
         }
        
         $bodyJSON = $body | ConvertTo-Json 
         $Response = Invoke-RestMethod -Uri $GroupUrl -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
        
         $GroupCreationResponse = $null
         $Stoploop = $false
         $GroupId = $null
         do {
             $GroupQueryUrl=$GroupUrl + “/?`$filter=displayName eq ‘” + $TeamName + “‘”
             $GroupCreationResponse = Invoke-RestMethod -Uri $GroupQueryUrl -Headers @{Authorization = “Bearer $token”} -Method Get -Verbose 
             if($GroupCreationResponse.value.Count -gt 0){
                 $Stoploop = $true
                 foreach($val in $GroupCreationResponse.value)
                 {
                     $GroupId = $val.Id
                 }
                
             }
         }
         While ($Stoploop -eq $false)
        
         $memberSettings = @{}
         $memberSettings.Add(“allowCreateUpdateChannels”,$true)
        
         $messagingSettings = @{}
         $messagingSettings.Add(“allowUserEditMessages”,$true)
         $messagingSettings.Add(“allowUserDeleteMessages”,$true)

        $funSettings = @{}
         $funSettings.Add(“allowGiphy”,$true)
         $funSettings.Add(“giphyContentRating”,$true)
        
         $TeamCreationUrl = “$GraphURL/groups/$GroupId/team”
         $body = [ordered]@{
         }
         $bodyJSON = $body | ConvertTo-Json
        
         $TeamCreationResponse = $null
         $TeamCreationResponse=Invoke-RestMethod -Uri $TeamCreationUrl -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Put -ContentType “application/json” -Verbose
         if($TeamCreationResponse -eq $null)
         {
             $Stoploop = $false
             do {
                 $TeamCreationResponse = Invoke-RestMethod -Uri $getTeamFromGraphUrl -Headers @{Authorization = “Bearer $token”} -Method Get -Verbose 
                 if($TeamCreationResponse){
                     $Stoploop = $true
                 }
             }
             While ($Stoploop -eq $false)
         }
        
      
         if($TeamCreationResponse){
             foreach($t in $TeamCreationResponse){
                 $newTeamDisplayName = $t.displayName
                 $TeamId = $t.Id
                 Write-Host “Team $newTeamDisplayName has been created successfully…” -ForegroundColor Green
                
             }
            
            
             Write-Host “Adding Channels to $newTeamDisplayName Team…” -ForegroundColor Yellow
             $TeamsChannelsUrl = “$GraphURL/teams/$TeamId/channels”
                
             try
             {
                 $arrteamchannels = $TeamChannels -split “#”
                 if($arrteamchannels)
                 {
                     for($i =0; $i -le ($arrteamchannels.count – 1) ; $i++)
                     {
                         $ChannelName = $arrteamchannels[$i]
                         $ChannelDescription = “Channel 1 Description”
                         $body = [ordered]@{
                             displayName = $ChannelName;
                             description = $ChannelDescription;
                         }
                         $bodyJSON = $body | ConvertTo-Json 
                         Invoke-RestMethod -Uri $TeamsChannelsUrl -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
                         Write-Host ”      Channel $ChannelName is now added to the Team.” -ForegroundColor Green
                     }
                 }
             }
             Catch
             {
                 Write-Host “There is issue with Channel settings in CSV, Check and Fix:. $teamchannels”
             }
            
             $GeneralChannelsUrl = “$TeamsChannelsUrl” + “?`$filter=displayName eq ‘General’&`$select=Id”
             $GeneralChannelResponse = Invoke-RestMethod -Uri $GeneralChannelsUrl -Headers @{Authorization = “Bearer $token”} -Method Get -Verbose 
             $ChannelID = $GeneralChannelResponse.value[0].id;
             $GeneralChannelMessageUrl = “$TeamsChannelsUrl/$ChannelID/messages”
            
             $Message = “<H1>Welcome to Microsoft Teams From DXC Technology</H1>”
             $RootMessage = @{}
             $MessageBody = @{}
             $MessageBody.Add(“ContentType”,1)
             $MessageBody.Add(“content”,$Message)
             $RootMessage.Add(“body”,$MessageBody)
            
             $body = [ordered]@{
                 rootMessage = $RootMessage;
             }
             $bodyJSON = $body | ConvertTo-Json 
             Invoke-RestMethod -Uri $GeneralChannelMessageUrl -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
             Write-Host ”      Message has been posted on the Channel.” -ForegroundColor Green
            
             #Adding Tab in General
             $TeamsUrl = “$GraphURL/teams/$TeamID”
             $TeamsAppsUrl = “$TeamsUrl/installedApps”
            
             $TabConfiguration = @{}
             $TabConfiguration.Add(“entityId”,$null)
             $TabConfiguration.Add(“contentUrl”,”https://www.bing.com/maps/embed?h=768&w=800&cp=39.90073511625853~-75.16744692848968&lvl=18&typ=d&sty=h&src=SHELL&FORM=MBEDV8″)
             $TabConfiguration.Add(“websiteUrl”,”https://binged.it/2BqOkiG”)
             $TabConfiguration.Add(“removeUrl”,$null)
            
             $TabPath = $GraphURL + “/appCatalogs/teamsApps/com.microsoft.teamspace.tab.web”
             $body = [ordered]@{
                 “name”=”Places to Go”
                 “teamsApp@odata.bind”=$TabPath
                 Configuration = $TabConfiguration;
             }
            
             $bodyJSON = $body | ConvertTo-Json 
             $GeneralChannelTabs = “$TeamsChannelsUrl/$ChannelID/tabs”
            
             Invoke-RestMethod -Uri $GeneralChannelTabs -Headers @{Authorization = “Bearer $token”} -Body $bodyJSON -Method Post -ContentType “application/json” -Verbose
             Write-Host ”      Message has been posted on the Channel.” -ForegroundColor Green
         }
      
     }

}

5 thoughts on “Creating Microsoft Team using Graph

  1. Hi Jerry Yasir, Thank you for sharing this with us all. However I have question. I want to create a teams type of EDU_CLASS which is a classes type of teams. How can I get this script to do this?

    1. Hello Kamran, You can pass the Template Path using the Body of the Create Team Operation of Graph. I suggest you to read the documentation and then update the script to include that line. I have done in using Custom application but not using the PowerShell version. I will try to create quick video about it. Thanks.

      1. Hello Kamran,
        The solution is simple, you just need update the script a little bit to get this done.

        $TeamCreationUrl = “$GraphURL/teams”
        #Teams Template
        $body = [ordered]@{
        “template@odata.bind” = “https://graph.microsoft.com/beta/teamsTemplates(‘educationClass’)”
        “displayName” = $TeamName
        “description” = $Description
        }

        You can find the updated script and excel file at
        https://github.com/jerryyasir/Samples/blob/master/Create-TeamsFromExcelusingPnPPowerShell.ps1

        I have also created a video about the script

        Thanks.
        Jerry

  2. Hi Jerry, Thanks for your rapid response and support. I am a beginner in Graph API. I found this: POST https://graph.microsoft.com/beta/teams
    Content-Type: application/json

    {
    “template@odata.bind”: “https://graph.microsoft.com/beta/teamsTemplates(‘educationClass’)”,
    “displayName”: “My Class Team”,
    “description”: “My Class Team’s Description”
    }

    Where would I add this to your script and have it use the displayname from the CSV and description etc.

    Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s