Developing an Audit Report Using PowerShell for Microsoft Teams

Did you know that you can work with Teams from PowerShell?  Neither did I!  Until recently anyway, when I had the opportunity to work on a script within PowerShell for Microsoft Teams Administration that a co-worker of mine, Will Holland, had previously written for one of our clients. This client utilizes Teams heavily and needed an audit report, generated each quarter, that would pull all the users and their permission levels in order to help manage security.

The script as it stood was only showing users from the Members and Owners groups.  Our client asked us if we could also identify any guest users, since they have a handful of external users who access Teams. That’s where my opportunity to learn came in.  Yay!

Getting Started

To access Teams from PowerShell, the first thing you need to do is install the Microsoft Teams module found in the PowerShell Gallery.  To do this, run PowerShell as an administrator by right-clicking the Windows PowerShell prompt and selecting ‘Run as administrator’.  Be sure to say Yes to the ‘allow this app to make changes’ prompt.

At the PowerShell prompt, enter:

Install-Module MicrosoftTeams

This will direct PowerShell to go out to the PowerShell Gallery to download and install the module. When installing, you will be prompted with an ‘Untrusted repository’ message to which you should answer Yes.

Now you can connect to Teams and do some stuff!

Connecting to Teams is as simple as entering the below command and providing your credentials at the standard Microsoft sign in screen:


Once You’re Connected

Now that you are connected, there are many things you can do to administer Teams, such as adding and removing Teams, Channels and users.  Here I’ll show you how you can pull all the users with access by Team and then write the output to a CSV file (full script found at the end).

First step is to connect to Teams (enter credentials when prompted):

Connect-MicrosoftTeams | Out-Null

For this exercise we need get a reference to all the teams in the tenant.  You could also pull a specific team by specifying properties such as -DisplayName or -GroupId or using one of many more options.  Here we are simply pulling all teams, with no filter:

$teams = Get-Team

Each instance of a Team will now have certain basic information available in the $teams object, such as DisplayName, GroupId, Users, etc.

The GroupId is required to pull all users associated with a Team.  Here I am pulling and displaying the users from the 4th(zero-based) item of our $teams collection using its GroupId.

$users = Get-TeamUser -GroupId $teams[3].GroupId

Shown here are the properties returned for each user, including their role (owner, member, guest):

For our purposes, we needed to break this collection of users into their discrete ‘types’.   We do this by using the Where-Object on the collection and filtering on the Role attribute:

$owners = Format-Users ($users | Where-Object { $_.Role -eq "owner"})

$members = Format-Users ($users | Where-Object { $_.Role -eq "member"})

$guests = Format-Users ($users | Where-Object { $_.Role -eq "guest"})

NOTE: ‘Format-Users’ is a function in our script used to present a more user-friendly version of the user info.

We then build out an object and add it to a collection so that we can later direct it into a CSV file:

<em>$obj = New-Object -TypeName PSObject</em>

<em>$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $name</em>

<em>$obj | Add-Member -MemberType NoteProperty -Name "Owners" -Value $owners</em>

<em>$obj | Add-Member -MemberType NoteProperty -Name "Members" -Value $members</em>

<em>$obj | Add-Member -MemberType NoteProperty -Name "Guests" -Value $guests</em>

<em>$teamInfo += $obj</em>


After we finish looping through all the teams and capturing all their users, we then output the results:

$fileName = "Teams-Audit-$(Get-Date -Format yyyy-MM-dd).csv"

$teamInfo | Export-CSV -Path $fileName -Encoding UTF8 -NoTypeInformation

Final output when opened in Excel:

And that is all you need to pull a basic audit report from Teams.

Of course, this is just one of the many things you can do via PowerShell when working with Teams. Be sure to check out Microsoft’s documentation on each of the available commands that are at your disposal.

Here is the Script


function Format-Users{


$s = ''

foreach($user in $users){

$s += "$($user.Name) ($($user.User))`n"


return $s


$teamInfo = @()



#Connect to Teams

Connect-MicrosoftTeams | Out-Null

#Get List of All Teams

Write-Progress -Id 1 -Activity "Running" -Status "Fetching All Teams"

$teams = Get-Team

#Foreach Team...

$processed = 0;

$total = $teams.Count

foreach($team in $teams){

$name = $team.DisplayName

$percentComplete = ($processed/$total) * 100

Write-Progress -Id 1 -Activity "Processing Teams" -Status "$($processed + 1) of $total" -CurrentOperation $name -PercentComplete $percentComplete

#Get list of Owners & Members

$users = Get-TeamUser -GroupId $team.GroupId

$owners = Format-Users ($users | Where-Object { $_.Role -eq "owner"})

$members = Format-Users ($users | Where-Object { $_.Role -eq "member"})

$guests = Format-Users ($users | Where-Object { $_.Role -eq "guest"})

$obj = New-Object -TypeName PSObject

$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $name

$obj | Add-Member -MemberType NoteProperty -Name "Owners" -Value $owners

$obj | Add-Member -MemberType NoteProperty -Name "Members" -Value $members

$obj | Add-Member -MemberType NoteProperty -Name "Guests" -Value $guests

$teamInfo += $obj





#Export Report

$fileName = "Teams-Audit-$(Get-Date -Format yyyy-MM-dd).csv"

Write-Progress -Id 1 -Activity "Finishing" -Status "$($processed + 1) of $total" -CurrentOperation "Exporting file to $filename" -PercentComplete 100

$teamInfo | Export-CSV -Path $fileName -Encoding UTF8 -NoTypeInformation



Share and Enjoy !

Related Content: