Browse Category

Teams

Get Office 365 Groups with Teams via PowerShell and the Microsoft Graph

Office 365 Groups are the backbone of a lot applications in Microsoft. The core principal is that an Office 365 Group is the security model that supports a Team. A good start to learn more about this is from the Microsoft documentation about the two.

Here is a more detailed image about how a Team is a workload that is supported by Office 365 Groups as the identity layer. This means that not all groups have an associated Team but all Teams are supported by a group.

Getting Groups with associated Teams

I had a client ask me recently to get a list of what groups have a Microsoft Teams chat connected vs Office 365 groups that don’t have a team connected. I have done this in the past using the method here on the TechCommunity. I then saw in some updated documentation that the beta Graph API includes a filterable property called resourceProvisioningOptions. The documentation can be found here. Filtering by this property is currently on the beta API so it is not recommended to utilize this in a production solution. 

Using the /groups Graph API we can retrieve all groups in the tenant that have a team. Any group that has a team has a resourceProvisioningOptions property that contains “Team”. 

  • Currently teams that were deleted may be included
  • This property can be changed but don’t do it
  • This also is populated for a group that has a Team added to it after the fact

One of the following permissions is required to call this API. To learn more, including how to choose permissions, see Permissions.

Permission type Permissions (from least to most privileged)
Delegated (work or school account) Group.Read.All, Group.ReadWrite.All
Delegated (personal Microsoft account) Not supported.
Application Group.Read.All, Group.ReadWrite.All

Here is the script and I will break it down below

#Enter scopes or app data - If a scope is entered it will used
#If scopes is empty it will check to run via app 
$scopes = 'Group.Read.All'

$appid = ''
$appsecret = ''
$appaaddomain = ''

#Graph URLs - uncomment one to run

#Get all groups
#$url = "https://graph.microsoft.com/v1.0/groups?`$filter=groupTypes/any(c:c eq 'Unified')&`$select=displayname,resourceProvisioningOptions"
#Get all groups with teams
$url = "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')"

#Establish connection
If($scopes.Length -gt 0){
    Connect-PnPOnline -Scopes "Group.Read.All"
} elseif($appid.Length -gt 0) {
    Connect-PnPOnline -AppId $appid -AppSecret $appsecret  -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
}

#Parse data
if($response){
foreach($r in $response.value){ 
    if($r.resourceProvisioningOptions -eq 'Team'){
        write-host $r.displayname "is a Team enabled Group" -ForegroundColor Yellow
        #Do fancy stuff in here
    } else {
        write-host $r.displayname "is a regular O365 Group" -ForegroundColor Green
    }
}
} else {
    write-host 'Response issue' -ForegroundColor Red
}

Connecting to the Graph via PowerShell

To connect to the Graph via PowerShell I am using the PnP PowerShell module. SharePoint Patterns and Practices (PnP) contains a library of PowerShell commands (PnP PowerShell) that allows you to perform complex provisioning and artifact management actions towards SharePoint. The commands use CSOM and can work against both SharePoint Online as SharePoint On-Premises. Details about how to work with this module and its cmdlets can be found here.

The cmdlet that is used to connect is Connect-PnPOnline. This cmdlet can be used to connect to multiple entry points. When connecting to the Graph you can connect through Azure AD and declare permissions scopes with the -Scopes parameter or connect with app level permissions using the -AppId, -AppSecret, and -AADDomain parameters.

I have setup the script to handle either depending on what you enter at the top for the variables. Details for different types of permissions can be found here.

Calling the Graph via PowerShell

To call the Graph I am using the Invoke-RestMethod cmdlet to make the REST request. To handle the Graph call we need to pass along a bearer token. I am getting the token through the PnP cmdlet Get-PnPAccessToken. The data will then be returned as an object. You could convert the data into JSON to utilize it if necessary.

Along with the token we need to pass along the Graph Uri call. I have setup 2 different options to get the data. Swap the comment (#) tags for either $url line. 

Here is a breakdown of each option:

  • Get all groups which have Teams
    • This will return the filtered list of Groups
      • /v1.0/groups?$filter=groupTypes/any(c:c eq ‘Unified’)&`$select=displayname,resourceProvisioningOptions
  • Get all groups
    • This will return all groups and then go through all returned groups and perform an action for ones that have a connected Team
      • /beta/groups?$filter=resourceProvisioningOptions/Any(x:x eq ‘Team’)
      • Currently this only does a Write-Host but any business logic could be added here.

Make sure you copy and paste from the code block for proper formatting.

The best way to test Graph calls before working with them is through the Graph Explorer. I highly recommend this one!

Securing the app permissions

One idea that I did not put in here but would be a good idea if you wanted to set up a recurring solution around this would be to protect the app data through the Azure Key Vault.  Here are details on how this can be completed – 

Using Azure Key Vault with PowerShell – Part 1

More information about setting up an Azure AD app can be found here:

Interact with Graph and make O365 Groups with AzureFunctions PowerShell