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:
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:
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:
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?
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.
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
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