Teams Management with PowerShell : What you need to know

The Microsoft Teams PowerShell module lets you manage teams, channels, members, and policies in bulk — anything that’s tedious clicking through the admin center one team at a time.


In this post: Create a team and add members · Report on all teams · Find inactive teams · Bulk policy assignment · PowerShell vs the alternatives · When would you actually use this? · References


Create a team and add members
# Connect to Microsoft Teams
Connect-MicrosoftTeams

# Create a new Team
$team = New-Team -DisplayName "Project Alpha Team" -Visibility Private -Description "Team for Project Alpha collaboration"

# Add members
Add-TeamUser -GroupId $team.GroupId -User "jane.doe@yourcompany.com"
Add-TeamUser -GroupId $team.GroupId -User "john.doe@yourcompany.com"
Report on all teams
# Get all Teams
$teams = Get-Team

# Export basic info
$teams | Select DisplayName, Description, Visibility, Archived | Export-Csv "AllTeamsReport.csv" -NoTypeInformation
Find inactive teams

Worth correcting directly: there’s no Get-TeamActivityReport cmdlet in the Teams module — that one shows up in some older guides but doesn’t actually exist. Team-level activity data comes from the Microsoft Graph Reports API instead, via the Microsoft Graph PowerShell SDK, and it works differently: it exports a CSV rather than returning live objects you can query directly.

Connect-MgGraph -Scopes "Reports.Read.All"

# Pull the last-180-days team activity report to a CSV
$reportPath = "$env:TEMP\TeamsActivity.csv"
Get-MgReportTeamActivityDetail -Period 'D180' -OutFile $reportPath

# Import it and find teams with no activity in 6 months
$activityData = Import-Csv -Path $reportPath
$cutoff = (Get-Date).AddMonths(-6)

$activityData | Where-Object {
    [string]::IsNullOrEmpty($_.'Last Activity Date') -or
    [datetime]$_.'Last Activity Date' -lt $cutoff
} | ForEach-Object {
    Write-Host "$($_.'Team Name') is inactive since $($_.'Last Activity Date')"
}

Bulk policy assignment

This is the other place PowerShell earns its keep over the admin center — assigning a policy to a whole department at once instead of one user at a time. Pull the target users from Entra ID by department, then grant the policy in a loop:

Connect-MicrosoftTeams
Connect-MgGraph -Scopes "User.Read.All"

$salesUsers = Get-MgUser -Filter "department eq 'Sales'" -All

foreach ($user in $salesUsers) {
    Grant-CsTeamsMeetingPolicy -PolicyName "SalesExternalMeetings" -Identity $user.UserPrincipalName
}

The same pattern works for messaging policies, calling policies, or app permission policies — swap the cmdlet, keep the same “filter users, loop, grant” structure. This is the actual answer to “assign this policy to 200 people” that doesn’t involve 200 clicks in the admin center.


PowerShell vs the alternatives
FeaturePowerShellTeams Admin CenterGraph APIPower Automate
AutomationFull scriptingManualYes, with codingVisual flows
Bulk operationsEasy via loopsVery limitedPossibleHard at scale
Ease of useModerateEasiestNeeds dev skillsFriendly UI
Best forAdmins, engineersNew admins, light usageDevelopers, custom integrationCitizen developers, light tasks

Full control and scriptability, at the cost of needing to actually know the cmdlets before running them against production teams.

When would you actually use this?
  • Onboarding automation: auto-create a team and channels when HR adds a new department, instead of someone remembering to do it manually.
  • Bulk policy enforcement: assign messaging or meeting policies to a whole group of users by location or department in one script instead of one-by-one.
  • Guest access auditing: find which teams have external members and report on their access — something that’s painful to check per-team in the UI.
  • Lifecycle cleanup: archive teams that have gone quiet for 6+ months, using the exact script above.

The tradeoff versus the admin center UI: full control and scriptability, at the cost of needing to actually know the cmdlets and test scripts before running them against production teams.


References

That’s the rundown. Let me know how it goes for you.


App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning

Leave a Comment

Your email address will not be published. Required fields are marked *