Powershell script to find out Teams policies by users

Iron Contributor

Hey everyone, do you know if there is a way to run a script to find what Teams policies are assigned to what user?  We have a private channel policy in place- I would like to find out a list of users that policy is assigned to.


Also, if you delete a user from a custom policy does that user get the default policy?  Thanks!

16 Replies

@Ethan Stern I wrote a quick query for this information.  I was surprised there were not any examples.  You can add additional elements if needed.  

$TeamsUsers = Get-CsOnlineUser | Select-Object DisplayName,ObjectId,UserPrincipalName, `
    SipAddress,Enabled,WindowsEmailAddress,LineURI,HostedVoiceMail,OnPremEnterpriseVoiceEnabled,OnPremLineURI,SipProxyAddress, `

$TeamsReport = @()

Foreach ($User in $TeamsUsers) {
    $Info = "" | Select "DisplayName","ObjectId","UserPrincipalName","SipAddress","Enabled","LineURI", `
    "WindowsEmailAddress","HostedVoiceMail","OnPremEnterpriseVoiceEnabled","OnPremLineURI","SipProxyAddress", `
    "OnlineDialinConferencingPolicy","TeamsUpgradeEffectiveMode","TeamsUpgradePolicy","HostingProvider", `
    "VoicePolicy","MeetingPolicy","TeamsMeetingPolicy","TeamsMessagingPolicy","TeamsAppSetupPolicy", `
    "TeamsCallingPolicy","VoicePolicySource","MeetingPolicySource","TeamsMeetingPolicySource", `

    Write-Host "Querying policy information for" $User.DisplayName -ForegroundColor Green

    $UserPolicies = Get-CsUserPolicyAssignment -Identity $User.ObjectId

    $Info.DisplayName = $User.DisplayName
	$Info.ObjectId = $User.ObjectId
	$Info.UserPrincipalName = $User.UserPrincipalName
	$Info.SipAddress = $User.SipAddress
	$Info.Enabled = $User.Enabled
	$Info.LineURI = $User.LineURI
	$Info.WindowsEmailAddress = $User.WindowsEmailAddress
	$Info.HostedVoiceMail = $User.HostedVoiceMail
	$Info.OnPremEnterpriseVoiceEnabled = $User.OnPremEnterpriseVoiceEnabled
	$Info.OnPremLineURI = $User.OnPremLineURI
	$Info.SipProxyAddress = $User.SipProxyAddress
	$Info.OnlineDialinConferencingPolicy = $User.OnlineDialinConferencingPolicy
	$Info.TeamsUpgradeEffectiveMode = $User.TeamsUpgradeEffectiveMode
	$Info.TeamsUpgradePolicy = $User.TeamsUpgradePolicy
	$Info.HostingProvider = $User.HostingProvider
    $Info.VoicePolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "VoicePolicy"}).PolicyName
    $Info.VoicePolicy = (($UserPolicies | Where-Object {$_.PolicyType -eq "VoicePolicy"}).PolicySource).AssignmentType
    $Info.MeetingPolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "MeetingPolicy"}).PolicyName
    $Info.MeetingPolicySource = (($UserPolicies | Where-Object {$_.PolicyType -eq "MeetingPolicy"}).PolicySource).AssignmentType
    $Info.TeamsMeetingPolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsMeetingPolicy"}).PolicyName
    $Info.TeamsMeetingPolicySource = (($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsMeetingPolicy"}).PolicySource).AssignmentType
    $Info.TeamsMessagingPolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsMessagingPolicy"}).PolicyName
    $Info.TeamsMessagingPolicySource = (($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsMessagingPolicy"}).PolicySource).AssignmentType
    $Info.TeamsAppSetupPolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsAppSetupPolicy"}).PolicyName
    $Info.TeamsAppSetupPolicySource = (($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsAppSetupPolicy"}).PolicySource).AssignmentType
    $Info.TeamsCallingPolicy = ($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsCallingPolicy"}).PolicyName
    $Info.TeamsCallingPolicySource = (($UserPolicies | Where-Object {$_.PolicyType -eq "TeamsCallingPolicy"}).PolicySource).AssignmentType

    $TeamsReport += $Info
    $Info = $null

$TeamsReport | Export-Csv .\TeamsReport.csv -NoTypeInformation


@Ethan Stern 


Just to let you know, works without code as well by using the filter option (click on "Users" in the left navigation then on the filter symbol and add the condition). 

(screenshot as an example)

I hope it helps.


@JohnLockett.... great piece of code! :smile:

Please let me know how do you export the results to excel or CSV after applying the Filter on Teams Admin Center.
Hi Sanat,

You don't there isn't an option in Teams Admin Center... thats why the about PowerShell is so useful.

Note - some of the properties in the above PS are not exported so you may have to add on TeamsAppPermissionPolicy.


@JohnLockett @Dlewis-79 .. Thank you for the details and confirmation, it's really helpful.
I have only 1 query, It took 2.5+ days and the query was still running which collected over 38000+ User objects, however, I had to cancel as it entered today production hours.
Is there any way to limit or place a condition like CountryCode or ExtensionAttribute or CustomAttribute to pull a more small and specific report.

@SanatKMahapatra wow that a long time. depending on what information you want to return in the excel you could limit the $Info = "" | Select to reduce the content that is returned? 


I need to limit my next run by office/location but I haven't had the time to rework the PS yet to do that. But looking quickly you could add a | where {$_.CountryOrRegionDisplayName -eq "xxxx"} to the end of the $TeamsUsers = Get-CsOnlineUser | Select-Object section. That might work or use the CountryAbbreviation property instead. 



Yes, you can update the top of the script to use a filter and select the attributes you want to filter on.  I would suggest you query some of your users and verify that the Teams PS Module sees those attributes before trying it.  For example:

     Get-CsOnlineUser -Filter {CountryAbbreviation  -eq "US"}


     Get-CsOnlineUser -Filter {City -eq "Phoenix"}


     Get-CsOnlineUser -Filter {(City -eq "Dallas") -or (City -eq "Phoenix")} 

Thank you so much @Dlewis-79 & @JohnLockett for the inputs, I will reduce the amount of information needed for the first complete run even though I need all the attributes in the Info section of the script. Will apply the Filters to the Get-CSOnlineUser command.
Hi John,
Get-CSOnlineUser only returns a value for Teams policies when they have been assigned directly. When policies are inherited from a group, they don't show up.
Get-CsUserPolicyAssignment will only return information about policies assigned directly or inherited. It won't return anything if you have the global default policy which make it hard to use to report a decent report.
Did anyone find a work around?

The filter only works is the polices have been directly assigned. If the user inherits a policy from being in a group then they do not show up in the results
Get-CsUserPolicyAssignment : Cannot bind argument to parameter 'Identity' because it is an empty string.
At C:\PSScripts\teams_assigned-policies.ps1:17 char:58
+ ...   $UserPolicies = Get-CsUserPolicyAssignment -Identity $User.ObjectId
+                                                            ~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Get-CsUserPolicyAssignment], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Get-CsUserPolicyAssignment

 Also no data is presented in csv at all for any user (all users have the policies assigned by group membership)


Late to the party but I've created a powershell function to show the order of policies (global, direct and groups if appropriate)






jchr-msft/TeamsAdmin (github.com)

Its not the fastest in the world, but it does the job

It runs without -Policy & gives odd output:

Assignment PolicyName Rank
---------- ---------- ----
[3] Global <not set>
I thought I'd made policy mandatory. my bad :D