Assign the Teams Administrator role with PowerShell
Prerequisites
- PowerShell 7+ (recommended)
- One of these admin roles on your account: Privileged Role Administrator or Global Administrator
- Tenant has auditing/MFA enabled for admins (best practice)
1) Install & import Graph modules
# Run as Administrator (first time only)
Install-Module Microsoft.Graph -Scope AllUsers -Force
# Import
Import-Module Microsoft.Graph
You don’t need the Beta module for this task.
2) Connect with the right permissions
Use the least privileges needed to read users and manage role assignments.
Connect-MgGraph -Scopes "User.Read.All","RoleManagement.ReadWrite.Directory"
Select-MgProfile -Name "v1.0"
3) One-off, quick assignment (copy/paste)
Change the UPN if needed.
$UserUpn = "AlexW@contoso.com"
$RoleName = "Teams Administrator"
# Ensure the directory role is active in the tenant
$role = Get-MgDirectoryRole | Where-Object DisplayName -eq $RoleName
if (-not $role) {
$tmpl = Get-MgDirectoryRoleTemplate | Where-Object DisplayName -eq $RoleName
if (-not $tmpl) { throw "Role template '$RoleName' not found." }
New-MgDirectoryRole -RoleTemplateId $tmpl.Id | Out-Null
$role = Get-MgDirectoryRole | Where-Object DisplayName -eq $RoleName
}
# Get the user
$user = Get-MgUser -Filter "userPrincipalName eq '$UserUpn'"
if (-not $user) { throw "User '$UserUpn' not found." }
# Idempotent add (skip if already a member)
$already = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All |
Where-Object Id -eq $user.Id
if (-not $already) {
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id `
-OdataId "https://graph.microsoft.com/v1.0/directoryObjects/$($user.Id)"
Write-Host "Assigned '$RoleName' to $UserUpn"
} else {
Write-Host "$UserUpn already has '$RoleName'."
}
4) Verify the assignment
# Option A: list members of the role
Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All |
Where-Object Id -eq $user.Id
# Option B: list user’s directory roles
Get-MgUserMemberOf -UserId $user.Id -All |
Where-Object '@odata.type' -eq '#microsoft.graph.directoryRole' |
Select-Object DisplayName
Reusable function (assign or confirm)
Drop this into your scripts for repeat use.
function Add-TeamsAdminRole {
param(
[Parameter(Mandatory)] [string] $UserUpn,
[string] $RoleName = "Teams Administrator"
)
$role = Get-MgDirectoryRole | Where-Object DisplayName -eq $RoleName
if (-not $role) {
$tmpl = Get-MgDirectoryRoleTemplate | Where-Object DisplayName -eq $RoleName
if (-not $tmpl) { throw "Role template '$RoleName' not found." }
New-MgDirectoryRole -RoleTemplateId $tmpl.Id | Out-Null
$role = Get-MgDirectoryRole | Where-Object DisplayName -eq $RoleName
}
$user = Get-MgUser -Filter "userPrincipalName eq '$UserUpn'"
if (-not $user) { throw "User '$UserUpn' not found." }
$already = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All |
Where-Object Id -eq $user.Id
if ($already) { return "$UserUpn already has '$RoleName'." }
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id `
-OdataId "https://graph.microsoft.com/v1.0/directoryObjects/$($user.Id)"
return "Assigned '$RoleName' to $UserUpn."
}
# Example:
# Connect-MgGraph -Scopes "User.Read.All","RoleManagement.ReadWrite.Directory"
# Add-TeamsAdminRole -UserUpn "AlexW@contoso.com"
Bulk example (CSV)
users.csv with a header UserPrincipalName
$csv = Import-Csv .\users.csv
foreach ($row in $csv) {
Write-Host (Add-TeamsAdminRole -UserUpn $row.UserPrincipalName)
}
Remove the role (if needed)
# Find the membership reference for the user and remove it
$membership = Get-MgDirectoryRoleMember -DirectoryRoleId $role.Id -All |
Where-Object Id -eq $user.Id
if ($membership) {
Remove-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id -DirectoryObjectId $user.Id
Write-Host "Removed '$RoleName' from $UserUpn"
}
Notes & best practices
- Use PIM (Privileged Identity Management) for eligible / time-bound access if you have Entra ID P2.
- Audit roles regularly: review
Directory rolesmembership in Entra. - Enforce MFA for all administrators.
- Prefer least-privilege scopes when connecting to Graph.

