PowerShell Teams: Manage Guest Access Policies via Graph

Why Guest Access Governance Matters
Microsoft Teams guest access is one of the most commonly misconfigured areas in a Microsoft 365 tenant. When external partners, vendors, and contractors join Teams channels, they accumulate silently — and without regular audits, former guests retain access long after their engagement ends. Security teams face compliance exposure, and license auditors find inconsistencies that manual reviews in the Teams admin center can never fully catch. Automating guest access reporting and policy enforcement with the Microsoft Graph PowerShell SDK turns a quarterly manual task into a nightly automated check.
Quick Answer
Use Get-MgUser with a -Filter "userType eq 'Guest'" to list all guest accounts, Get-MgUserMemberOf to find their Team memberships, and Get-MgPolicyAuthorizationPolicy to inspect and enforce the tenant-wide guest invite policy. All three require the Microsoft Graph PowerShell SDK with appropriate scopes.
Listing All Guest Users in Entra ID
The Graph SDK’s Get-MgUser cmdlet requires an explicit filter on userType. Without the filter it returns member accounts only — guests are excluded from default queries. Connect with at least the User.Read.All delegated or application scope before running the filter.
Connect-MgGraph -Scopes "User.Read.All","Directory.Read.All","Policy.Read.All","Team.ReadBasic.All"
$guests = Get-MgUser -Filter "userType eq 'Guest'" -All `
-Property Id,DisplayName,Mail,SignInActivity,CreatedDateTime
Write-Host "Total guest accounts: $($guests.Count)"
$guests | Select-Object DisplayName, Mail, CreatedDateTime | Format-Table -AutoSize
The -All switch handles pagination automatically on the v1.0 endpoint. The SignInActivity property is useful for identifying inactive guests but requires an Azure AD Premium P1 or P2 license on the tenant.
Finding Each Guest User’s Team Memberships
To map every guest to the Teams they belong to, iterate over the guest list and call Get-MgUserMemberOf. Filter the returned objects to Microsoft.Graph.Group objects that have GroupTypes containing Unified — those are Microsoft 365 Groups backing Teams. Collecting this data into a flat table makes the export phase straightforward.
$guestMemberships = foreach ($guest in $guests) {
$memberships = Get-MgUserMemberOf -UserId $guest.Id -All
foreach ($group in $memberships) {
$detail = Get-MgGroup -GroupId $group.Id -ErrorAction SilentlyContinue
if ($detail -and $detail.GroupTypes -contains "Unified") {
[PSCustomObject]@{
GuestName = $guest.DisplayName
GuestMail = $guest.Mail
TeamName = $detail.DisplayName
TeamId = $detail.Id
GuestCreated = $guest.CreatedDateTime
}
}
}
}
$guestMemberships | Format-Table -AutoSize
Checking Guest Invite Policy
The tenant-wide guest invite policy is stored in the authorization policy object. Get-MgPolicyAuthorizationPolicy returns a single object with an AllowInvitesFrom property. Valid values are none, adminsAndGuestInviters, adminsGuestInvitersAndAllMembers, and everyone. Most security baselines require this to be set to adminsAndGuestInviters or stricter.
$authPolicy = Get-MgPolicyAuthorizationPolicy
Write-Host "Current guest invite policy: $($authPolicy.AllowInvitesFrom)"
if ($authPolicy.AllowInvitesFrom -notin @("none","adminsAndGuestInviters")) {
Write-Warning "Guest invite policy is too permissive: $($authPolicy.AllowInvitesFrom)"
}
Disabling Guest Invite for Non-Admins
To lock down guest invitations to admins only, update the authorization policy using Update-MgPolicyAuthorizationPolicy. This is a tenant-level change and requires the Policy.ReadWrite.Authorization scope. Always test in a non-production tenant first and document the change in your change management system before executing in production.
Connect-MgGraph -Scopes "Policy.ReadWrite.Authorization"
Update-MgPolicyAuthorizationPolicy -AllowInvitesFrom adminsAndGuestInviters
# Verify the change
$updated = Get-MgPolicyAuthorizationPolicy
Write-Host "Updated policy: $($updated.AllowInvitesFrom)"
Reporting Inactive Guest Accounts for Review
Guests who have never signed in or whose last sign-in was more than 90 days ago are strong candidates for removal. The SignInActivity.LastSignInDateTime property provides this data when the tenant holds Azure AD Premium licenses. Build a report of stale guests with their Team memberships for the access review process.
$threshold = (Get-Date).AddDays(-90)
$inactiveGuests = $guests | Where-Object {
$_.SignInActivity.LastSignInDateTime -lt $threshold -or
$null -eq $_.SignInActivity.LastSignInDateTime
}
Write-Host "Inactive guests (90+ days): $($inactiveGuests.Count)"
$inactiveGuests | Select-Object DisplayName, Mail,
@{N="LastSignIn"; E={ $_.SignInActivity.LastSignInDateTime }} |
Export-Csv "InactiveGuests_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
Exporting the Guest Membership Matrix to CSV
Combine the guest list, membership data, and last sign-in into a single exportable matrix. This file serves as the evidence artifact for access reviews and can be imported into ticketing systems for remediation workflow. Schedule this export to run nightly so the review board always has a fresh snapshot.
$reportPath = "GuestMembershipMatrix_$(Get-Date -Format yyyyMMdd).csv"
$guestMemberships |
Select-Object GuestName, GuestMail, TeamName, GuestCreated |
Export-Csv $reportPath -NoTypeInformation
Write-Host "Report exported to: $reportPath"
Common Errors
- Get-MgUser returns no guests without the -Filter parameter. The default query omits guest accounts. Always include
-Filter "userType eq 'Guest'"explicitly. Omitting it means your compliance report silently covers zero guests. - Teams membership lookup fails with “Forbidden”. The
Directory.Read.Allscope alone is insufficient. Teams group membership enumeration requires theTeam.ReadBasic.AllorGroup.Read.Allscope to be explicitly consented. Add it to yourConnect-MgGraph -Scopescall.
Related Cmdlets / See Also
Wrapping Up
Guest access governance in Teams is not a one-time configuration task — it is a continuous process. The Graph PowerShell SDK gives you the primitives to enumerate guest accounts, inspect their memberships, enforce invite policies, and export audit-ready reports. Schedule these scripts as nightly automation to keep your tenant guest posture current without relying on manual admin center reviews.


