Table of Contents
How to Find Yammer Groups and Teams Groups in a Tenant
The question of how to find the set of Microsoft 365 Groups (previously known as Office 365 Groups) enabled for Teams in a tenant using PowerShell has existed since Teams arrived in November 2016. In many cases, the desire is to create an array of teams where each item is subsequently processed. For example, you might want to create a report about the teams and groups in a tenant.
Several theories were advanced about the best way find Teams-enabled groups, many centering on the ProvisioningOption property returned by the Get-UnifiedGroup cmdlet. This property is long since deprecated, even if you can still find old articles about its use among the debris of the internet.
Get-Team is a Slow Cmdlet
The Teams PowerShell module contains the Get-Team cmdlet to find team-enabled groups. Although Get-Team does a fine job of returning the set of teams in a tenant, it is slow. Painfully slow. What’s surprising about this is that the underlying Graph call returns the data fast.
This code requests the set of teams in a tenant. The code uses pagination to find all the teams, 100 at a time. The result is a hashtable containing the object identifier and display name of the teams.
$Uri = "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')" $headers = @{Authorization = "Bearer $token"} # Create list of Teams in the tenant Write-Host "Fetching Teams…" # Build a hashtable containing the temas. If more than 100 teams exist, fetch and continue processing using the NextLink $Teams = Invoke-WebRequest -Method GET -Uri $Uri-ContentType "application/json" -Headers $headers | ConvertFrom-Json $TeamsHash = @{} $Teams.Value.ForEach( { $TeamsHash.Add($_.Id, $_.DisplayName) } ) $NextLink = $Teams.'@Odata.NextLink' While ($NextLink -ne $Null) { $Teams = Invoke-WebRequest -Method GET -Uri $NextLink -ContentType $ctype -Headers $headers | ConvertFrom-Json $Teams.Value.ForEach( { $TeamsHash.Add($_.Id, $_.DisplayName) } ) $NextLink = $Teams.'@odata.NextLink' }
The equivalent use of Get-Team to create an array of teams holding just the identifier and display name is:
[array]$Teams = Get-Team | Select GroupId, DisplayName
When I ran the code in my tenant against 65 teams (of 191 groups), Get-Team returns in a little over ten seconds while the Graph call takes less than a second. That’s quite a difference. In both cases, the result is an average over ten runs.
Note: Microsoft improved the performance of the Get-Team cmdlet in V2.0 of the MicrosoftTeams PowerShell module. Using Get-Team to find the set of teams in a tenant is now much faster.
Using Get-UnifiedGroup to Find Teams
The Graph call finds Teams by applying a filter for a GET against the Groups endpoint. You can do the same using the Get-UnifiedGroup cmdlet:
[array]$Groups = Get-UnifiedGroup -Filter {ResourceProvisioningOptions -eq "Team"} -ResultSize Unlimited | Select-Object ExternalDirectoryObjectId, DisplayName
The command completes in less than six seconds.
Obviously, we’re not comparing apples with apples here. The Get-Team and Get-UnifiedGroup cmdlets do other processing when they fetch information, such as populating a set of useful properties about teams and groups that we might wish to access. But the basic point remains true: if you just want to fetch a set of groups or teams to use as input for whatever processing is necessary, a call to the Graph is more complicated but much faster.
Another thing to note is that the ResourceProvisioningOptions property might not contain “Team” for some old or inactive teams. This is a known issue with the Graph.
Finding Yammer-Enabled Groups
Given that the ResourceProvisioningOptions property is populated for Teams, could the property be used to find Microsoft 365 Groups used by Yammer communities in networks configured in Microsoft 365 native mode? The answer is no. “Team” appears to be the only option populated by Groups.
To find the set of groups used by Yammer, you can run the command:
[array]$YammerGroups = Get-UnifiedGroup -ResultSize Unlimited | Where-Object {$_.GroupSku -eq "Yammer"}
The command is slow because it uses a client side filter.
A close examination of group properties reveals another property called ResourceBehaviorOptions. Some groups have “YammerProvisioning” in this property, so can we run this command to find Yammer-connected groups?
[array]$YammerGroups = Get-UnifiedGroup -Filter {ResourceBehaviorOptions -eq "YammerProvisioning"} -ResultSize Unlimited
Alas, the answer is no. Although Groups use the ResourceBehaviorOptions property to understand what options are configured by applications using the group, it seems that only Yammer groups created before April 2019 populate the property, so you’re forced to use the slower command to find the complete set of Yammer groups.
Teams Resource Behaviors
By comparison, groups used by Teams created after May 2018 populate the property with WelcomeEmailDisabled, SubscribeMembersToCalendarEventsDisabled, and HideGroupInOutlook. WelcomeEmailDisabled means that Teams sends its own “welcome to Teams” email to new members instead of the generic “welcome to the group” message. HideGroupInOutlook means that the group is hidden from Exchange address lists and isn’t visible to Outlook clients.
SubscribeMembersToCalendarEventsDisabled is the most interesting option. It means that members of the team don’t receive updates for events scheduled in the group calendar. People often wonder why team members don’t receive notifications for channel meetings, which are created in the group calendar. Teams disables the subscription to the group calendar to stop team members receiving email notifications (a big thing for Teams is to reduce the amount of email). Therefore, the only people who receive email notifications for channel meetings are those who are explicitly added as a meeting participant.
Flexibility of PowerShell
The beauty of PowerShell is that it’s very flexible. That can also be its downfall as many ways often exist to get work done. The trick is to figure out which is the fastest or most efficient method in different circumstances. Sometimes it will be a cmdlet from one module, sometimes a cmdlet from a different module, or maybe even a quick call to the Graph.
Learn more about how Office 365 really works on an ongoing basis by subscribing to the Office 365 for IT Pros eBook. Our monthly updates keep subscribers informed about what’s important across the Office 365 ecosystem.
Hi Tony,
Do you also happen to figure out a way to find the list of groups that are using planner or the total plans/all planner groups in the tenant ?
You’d have to handle Planner through the Graph. I explore how to retrieve Planner data using a mixture of Graph and PowerShell in https://petri.com/working-planner-data-through-graph