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
         }
      
     }

}

Export Microsoft Teams Information using Graph API


As we already know that Microsoft Teams PowerShell does not provide cmdlets to get detailed information from Microsoft Teams.  It may evolve over next few months but we do have Microsoft Graph API that provides new has endpoints that you can use to export information about Team, Channels, Messages, Members and owners etc.  The sample below does some of the basic functions.  It all the teams and then try to get some information to an array of objects.  This is no way a complete sample but a good starting point.   It might help you get started with Teams.

I am using PNPOnline Powershell Module to get connect to Micorosft Graph and Get the Access token.  There couple of different ways to do that but PNP makes it lot easier.  Make sure you install the SharePointPnPPowerShellOnline module.

You can create an App in Azure Active Directory that has the Group.Read.all and User.Read.All permissions to make it easy for you.  Make sure you click on Grant permission after adding the Graph API permission.

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

$ApplicationID = “”
$Password = ”
$appaaddomain = ‘tenant.onmicrosoft.com’
 
$GraphURL = “https://graph.microsoft.com/beta”
$url = “$GraphURL/groups?`$filter=resourceProvisioningOptions/Any(x:x eq ‘Team’)”

#Establish connection
If($scopes.Length -gt 0){
    Connect-PnPOnline -Scopes $scopes
} elseif($ApplicationID.Length -gt 0) {
    Write-Host “Connecting using Application” -ForegroundColor Yellow
    Connect-PnPOnline -AppId $ApplicationID -AppSecret $Password -AADDomain $appaaddomain
} else {
    write-host ‘Connection issue’ -ForegroundColor Red
    exit
}
 
#Get token
$token = Get-PnPAccessToken
 
#Call graph
if($token){
    $response = Invoke-RestMethod -Uri $url -Headers @{Authorization = “Bearer $token”}
} else {
    write-host ‘Token issue’ -ForegroundColor Red
    exit
}

$TeamsData = $null
$TeamsData = @()

#Parse data
if($response){
    foreach($r in $response.value){
        if($r.resourceProvisioningOptions -eq ‘Team’){
           
            $teamDataObj = New-Object -TypeName PSObject
           
            $GroupClassification = $r.classification
            $GroupCreatedDateTime = $r.createdDateTime
            $visibility = $r.visibility
            $TeamName = $r.displayname
            write-host “Team Name:$TeamName Classification:$GroupClassification CreatedOn:$GroupCreatedDateTime” -ForegroundColor Yellow
            $TeamID = $r.id
            $TeamUrl =  “$GraphURL/groups/$TeamID/members”
            $TeamsOwnerUrl =  “$GraphURL/groups/$TeamID/owners”
            $ChannelsUrl =  “$GraphURL/groups/$TeamID/channels”
           
            $teamDataObj | Add-Member -Type NoteProperty -Name TeamName -Value $TeamName
            $teamDataObj | Add-Member -Type NoteProperty -Name Createdon -Value $GroupCreatedDateTime
            $teamDataObj | Add-Member -Type NoteProperty -Name Classification -Value $GroupClassification
            $teamDataObj | Add-Member -Type NoteProperty -Name Visibility -Value $visibility
           
            if($token){
                $rTeam = Invoke-RestMethod -Uri $TeamUrl -Headers @{Authorization = “Bearer $token”}
                $rTeamsOwners = Invoke-RestMethod -Uri $TeamsOwnerUrl -Headers @{Authorization = “Bearer $token”}
                $rTeamChanel = Invoke-RestMethod -Uri $ChannelsUrl -Headers @{Authorization = “Bearer $token”}
            } else {
                write-host ‘Token issue’ -ForegroundColor Red
                exit
            }
            $TeamOwnersAll = “”
            if($rTeamsOwners)
            {
                Write-Host ”    Team Owners:”
                foreach($owner in $rTeamsOwners.value)
                {
                    $OwnerName = $owner.displayName
                    $OwnerEmail = $owner.mail
                    Write-Host ”        $OwnerName”
                    $TeamOwnersAll +=”$OwnerEmail#”
                }
         
            }
            $teamDataObj | Add-Member -Type NoteProperty -Name Owners -Value $OwnerEmail
            if($rTeam)
            {
                $TeamMembersAll = “”
                Write-Host ”    Team Members:”
                foreach($member in $rTeam.value)
                {
                    $TeamMember = $member.displayName
                    $TeamMemberEmail = $member.mail
                    $TeamMemberRole = $member.assignedLicenses
                    Write-Host ”        $TeamMember”
                    $TeamMembersAll +=”$TeamMemberEmail#”
                }
         
            }
            $teamDataObj | Add-Member -Type NoteProperty -Name TeamMembers -Value $TeamMembersAll
            if($rTeamChanel)
            {
                Write-Host ”    Channels”
                $AllChannels = “”
                foreach($channel in $rTeamChanel.value)
                {
                    $ChannelName = $channel.displayName
                    $ChannelId = $channel.id
                    Write-Host ”        Channels: $ChannelName”
                    $AllChannels +=”$ChannelName#”
                   
           
                    #/teams/{id}/channels/{id}/messages
           
                    $ChannelsMessageUrls =  “$GraphURL/teams/$TeamID/channels/$ChannelId/messages”
           

                    if($token){
                        $rMessages = Invoke-RestMethod -Uri $ChannelsMessageUrls -Headers @{Authorization = “Bearer $token”}
                    } else {
                        write-host ‘Token issue’ -ForegroundColor Red
                        exit
                    }
                   
                    $MessageCount = 0
                    $Replies = 0
           
                    if($rMessages)
                    {
                        foreach($Message in $rMessages.value)
                        {
                            $MessageId = $Message.id
                            $messageBody = $Message.body
                            $MessagecreatedDateTime = $message.createdDateTime
                            $MessageCount++;
                            Write-Host ”        Message: $messageBody $MessageId $MessagecreatedDateTime”
                            $ChannelsRepliesUrls =  “$GraphURL/teams/$TeamID/channels/$ChannelId/messages/$MessageId/replies”
                            if($token){
                                $rReplies = Invoke-RestMethod -Uri $ChannelsRepliesUrls -Headers @{Authorization = “Bearer $token”}
                                if($rReplies)
                                {
                                    foreach($rReplie in $rReplies.Value)
                                    {
                                        $rreplyId = $rReplie.body
                                        $rcreatedDateTime = $rReplie.createdDateTime
                                        $Replies++;
                                        Write-Host ”            Reply:$rcreatedDateTime”
                                    }
                                }
                            } else {
                                write-host ‘Token issue’ -ForegroundColor Red
                                exit
                            }
                        }
                    }
       
                }
                $teamDataObj | Add-Member -Type NoteProperty -Name Channels -Value $AllChannels
                $teamDataObj | Add-Member -Type NoteProperty -Name MessageCount -Value $MessageCount
                $teamDataObj | Add-Member -Type NoteProperty -Name RepliesCount -Value $Replies
            }
           
            $TeamsData += $teamDataObj
       
            #Do fancy stuff in here
        } else {
            write-host $r.displayname “is a regular O365 Group” -ForegroundColor Green
        }
    }
} else {
    write-host ‘Response issue’ -ForegroundColor Red
}

$TeamsData | Out-GridView
$TeamsData | Export-Csv -Path C:\temp\TeamsInfo.csv –NoTypeInformation

Technet Link for Code.

https://gallery.technet.microsoft.com/Export-Teams-Information-2ea6b3db