Creating a Teams owner report in CSV


I’m working on creating a CSV report with Teams and Owners and it’s not really working as I expect it to.

Basically I want to get the Teams name, MailNickName, Description and a list of the owners.
But it seems to go awry when I have more than one owner on a Team, which is required in parts of the tenant.

The headers in the CSV are:

Where owners should be a string containing “owner1.Name (owner1.EmailAddress), owner2.Name (owner2.EmailAddress)…”

And I get the three first items correctly from each team, but as a general rule I only get one owner for a team. And on some lines I get the email-address or name of a team owner on a separate line without quotation marks.

As far as I can tell it’s when I try to create the string of owners for each team that I get something wrong.

We have ~4k teams in the tenant, but the CSV returns an extra 137 lines

Here’s the scaled back version of the script without progress bar and some comments:

#Requires -PSEdition Desktop
#Requires -version 5.1
#Requires -Module MicrosoftTeams
Param ()
$DateTime = Get-Date -f "yyyyMMdd" 
$CSVFile = $DateTime + "-TeamsOwners.csv" 
$CSVOutput = @() 

Try {
Catch {
  Write-Warning -Message "Error: Unable to connect to MS Teams $($_.Exception)"

$allTeams = Get-Team

# Check that we actually got the teams
if ($allTeams.Count -eq 0) {
  Write-Warning -Message "Unable to get Teams. Please try again later"
foreach ($team in $allTeams) { 
    $Owners = "" 

    # Get teams owners and add to string
    $allTeamsOwners = Get-TeamUser -GroupId $team.GroupId -Role Owner
    if ($allTeamsOwners) {
      foreach ($owner in $allTeamsOwners) {
        $ownerName = $owner.Name
        $ownerUPN = $owner.User
        $ownerInfo = "$ownerName ($ownerUPN)"
      $Owners = $Owners + ',' + $ownerInfo
    # Check for owners to avoid error for empty groups 
    if ($Owners) { 
        $Owners = $Owners.Substring(1,($Owners.Length) -1) 

    # Set up hash table and add values 
    $HashTab = $NULL 
    $HashTab = [ordered]@{ 
        "Name" = $team.DisplayName 
        "E-mail" = $team.MailNickName 
        "Description" = $team.Description
        "Owners" = $Owners 
    # Add hash table to CSV data array 
    $CSVOutput += New-Object PSObject -Property $HashTab 
# Export to CSV files 
$CSVOutput | Sort-Object Name | Export-Csv $CSVFile -NoTypeInformation -Encoding utf8 -Delimiter ';'


Any feedback is appreciated.

If I got it right something like this could work actually:

if ($allTeamsOwners) {
    $OwnerList =
    foreach ($owner in $allTeamsOwners) {
        "$owner.Name ($owner.User)"
    $Owners = $OwnerList -join ', '

I actually started with something similar:

      foreach ($owner in $allTeamsOwners) {
        $ownerInfo = "$owner.Name ($owner.User)"

But what I got from that was: Microsoft.TeamsCmdlets.PowerShell.Custom.GetTeamUser+GetTeamUserResponse.Name (Microsoft.TeamsCmdlets.PowerShell.Custom.GetTeamUser+GetTeamUserResponse.User)"
So it seems there was some issue parsing it if I didn’t explicitly expand the variables.

I tried your stripped back version again with the join and it gave me a string with a number of values however it was still in this form: "icrosoft.TeamsCmdlets.PowerShell.Custom.GetTeamUser+GetTeamUserResponse.Name (Microsoft.TeamsCmdlets.PowerShell.Custom.GetTeamUser+GetTeamUserResponse.User)"
So it doesn’t expand the variable.Attribute pairs automatically - and it strips the first letter from the $owner.Name!?

I wrapped each variable.Attribute pair in $() like so:

$OwnerList = 
      foreach ($owner in $allTeamsOwners) {
        "$($owner.Name) ($($owner.User))"
      $Owners = $OwnerList -join ', '

And now it expands correctly.

Also the fact that our name standard is “SurName, GivenName - DepartmentInitials” means that the CSV parser trips over the comma in the $owner.Name pair, but that’s a minor problem. I should probably also switch the -join character to the pipe as the comma is already used in the name.

Will the -join operator throw in a delimiter if there are no Team owners / $OwnerList is an empty string?

Oh … yeah … I should have thought about that before … sorry.

Actually Export-Csv should handle that gracefully by surrounding everythinf with quotes. But if that doesn’t work you may use another delimiter if that doesn’t prevent further steps. :wink:

You may figure that out for yourself quite easily … :wink:

@('One single Element') -join ';'
# empty string ...
'' -join ';'

Yeah, sorry that was me being unclear… The string is actually wrapped in quotes. But I use a CSV-plugin in VSCode that apparently tripped over the mix of commas and semi-colons so it borked the visual output. Oddly enough when I changed -join character to ’ | ’ it of course retained the comma in the user name, but it happily shows the CSV correctly now.

It seems that I may need to do some additional cleanup as some of the description fields contain line breaks or single quotation marks which breaks the output to the CSV in other exciting ways. I have one team which becomes 10 separate lines in the CSV because of that! :roll_eyes:

Again, sorry. That was just me being lazy here, I just ran with it and checked the CSV for the Teams I knew were without owners. And as you know, it left an empty string.

Thank you for your help!