PowerShell: Find Teams with Members but no Owners, and set all Members to Owners

 


When a Team owner leaves the organization, they may leave behind a Team with no owners. This is bad from a number of perspectives. There is no one left to manage the Team, IT doesn't know who the Team belongs to, and no members can leave the Team if there is no owner. 

This PowerShell script looks through every Team in your organization, reports back Teams that have members but no owners, and sets every member of that Team to be an owner. 

Connect-MicrosoftTeams
# Define a new object to gather output
$OutputCollection=  @()
 
# Split path
$Path = Split-Path -Parent "C:\SWSetup\*.*"
$LogDate = Get-Date -f yyyyMMddhhmm
$path = $Path + "\TeamsWithMembersButNoOwners_$logDate.csv"
 
 
Write-Verbose "Getting Team Names and Details"         
 
Get-Team | ForEach-Object {
    # Get Owners, members and guests
    $TeamUsers = Get-TeamUser -GroupId $_.GroupID        
    $TeamOwnerCount = ($TeamUsers | Where-Object {$_.Role -like "owner"}).count
    $TeamMemberCount = ($TeamUsers | Where-Object {$_.Role -like "member"}).count
    $TeamGuestCount = ($TeamUsers | Where-Object {$_.Role -like "guest"}).count
 
  #If the Team has members but no owners
  If($TeamOwnerCount -eq 0 -And $TeamMemberCount -gt 0){  
  
        # Set each member to be an owner
        foreach($u in $TeamUsers| Where-Object {$_.Role -like "member"}){
            Add-TeamUser -GroupId $_.GroupID  -User $u.User -Role Owner
        }
 
        # Calculate Description word count           
        $DescriptionWordCount = $null
        $DescriptionWordCount = ($_.Description | Out-String | Measure-Object -Word).words
 
        #Get channel details
 
        $Channels = $null
        $Channels = Get-TeamChannel -GroupId $_.GroupID
        $ChannelCount = $Channels.count
 
        Write-host "Getting details for Team $($_.DisplayName)"
        # Put all details into an object
 
        $output = New-Object -TypeName PSobject
 
        $output | add-member NoteProperty "DisplayName" -value $_.DisplayName
        $output | add-member NoteProperty "Description" -value $_.Description
        $output | add-member NoteProperty "DescriptionWordCount" -value $DescriptionWordCount
        $output | add-member NoteProperty "Visibility" -value $_.Visibility
        $output | add-member NoteProperty "Archived" -value $_.Archived
        $output | Add-Member NoteProperty "ChannelCount" -Value $ChannelCount
        $output | Add-Member NoteProperty "OwnerCount" -Value $TeamOwnerCount
        $output | Add-Member NoteProperty "MemberCount" -Value $TeamMemberCount
        $output | Add-Member NoteProperty "GuestCount" -Value $TeamGuestCount
        $output | add-member NoteProperty "GroupId" -value $_.GroupId
 
        $output | Export-Csv -Path $path -NoTypeInformation -Append
    }
}

Summary Script

Before I could run this script, I had to do some investigation for management, giving them a summary of how many groups this would affect. The blow script outputs the numbers into a CSV for these categories:



$owners0 = 0

$owners0ppl2 = 0

$owners1 = 0

$owners1ppl1 = 0

$owners0ppl5=0

$ownersGood=0

$owners0pplMany=0

$AllTeams=0

$ErrorTeams=0

 

Connect-MicrosoftTeams

# Define a new object to gather output

$OutputCollection=  @()

 

# Split path

$Path = Split-Path -Parent "C:\SWSetup\*.*"

$datestring = (Get-Date).ToString(“s”).Replace(“:”,”-”)

$LogDate = Get-Date -f "yyyy-MM-dd hh:mm"

$d1 = $(Get-Date -f "yyyy-MM-dd hh:mm")

$path = $Path + "\TeamsWithMembersButNoOwnersSummary.csv"

$sitelist = Import-CSV C:\SWSetup\exportGroup_2023-2-14.csv

 

Write-Host "Getting Team Names and Details"

Write-Output "Start: $($logDate) | Curr Time: $($d1) | 0 Owners: $($owners0) | 0 owners & less than 2 people: $($owners0ppl2) | 0 owners & 2-5 people: $($owners0ppl5) | 0 owners & more than 5 people: $($owners0pplMany) | 1 Owner: $($owners1) | 1 Owner, 1 Member: $($owners1ppl1) | 2+ Owners: $($ownersGood) | Total: $($AllTeams) | Errors: $($ErrorTeams)"

 

#Get-Team | ForEach-Object {

foreach ($s in $sitelist)

if($s.source -eq "Cloud" -and $s.groupType -eq "Microsoft 365" -and $s.membershipType -eq "Assigned"){

        # Get Owners, members and guests

        try

        

              $TeamUsers = Get-TeamUser -GroupId $s.id      

                $TeamOwnerCount = ($TeamUsers | Where-Object {$_.Role -like "owner"}).count

                $TeamMemberCount = ($TeamUsers | Where-Object {$_.Role -like "member"}).count

                $TeamGuestCount = ($TeamUsers | Where-Object {$_.Role -like "guest"}).count

 

              #If the Team has members but no owners

              If($TeamOwnerCount -eq 0){

                $owners0++

                if($TeamMemberCount -lt 2){$owners0ppl2++}

                elseif($TeamMemberCount -lt 5){$owners0ppl5++}

                else{$owners0pplMany++}

               }

              elseif($TeamOwnerCount -eq 1){$owners1++

                 if($TeamMemberCount -eq 1){$owners1ppl1++}

              }

              else{$ownersGood++}

              $ts = New-TimeSpan $d1 $(get-date)

              if ($ts.Minutes -gt 29) {

                    $d1 = $(Get-Date -f "yyyy-MM-dd hh:mm")

                    Write-Output "Start: $($logDate) | Curr Time: $($d1) | 0 Owners: $($owners0) | 0 owners & less than 2 people: $($owners0ppl2) | 0 owners & 2-5 people: $($owners0ppl5) | 0 owners & more than 5 people: $($owners0pplMany) | 1 Owner: $($owners1) | 1 Owner, 1 Member: $($owners1ppl1) | 2+ Owners: $($ownersGood) | Total: $($AllTeams) | Errors: $($ErrorTeams)"

                    Write-Output "Start: $($logDate) | Curr Time: $($d1) | 0 Owners: $($owners0) | 0 owners & less than 2 people: $($owners0ppl2) | 0 owners & 2-5 people: $($owners0ppl5) | 0 owners & more than 5 people: $($owners0pplMany) | 1 Owner: $($owners1) | 1 Owner, 1 Member: $($owners1ppl1) | 2+ Owners: $($ownersGood) | Total: $($AllTeams) | Errors: $($ErrorTeams)" >> C:\SWSetup\errorlog_$datestring.txt

              }

              $AllTeams++

      }

      catch{

           $ErrorTeams++   

           Write-Output "Error occurred on: $($s.displayName) ($($s.id)) at $(Get-Date -f ""yyyy-MM-dd hh:mm"")" >> C:\SWSetup\errorlog_$datestring.txt

           Write-Output "Start:  $($logDate) | Curr Time: $($d1) | 0 Owners: $($owners0) | 0 owners & less than 2 people: $($owners0ppl2) | 0 owners & less than 5 people: $($owners0ppl5) | 0 owners & more than 5 people: $($owners0pplMany) | 1 Owner: $($owners1) | 1 Owner, 1 Member: $($owners1ppl1) | 2+ Owners: $($ownersGood) | Total: $($AllTeams) | Errors: $($ErrorTeams)" >> C:\SWSetup\errorlog_$datestring.txt

          

      }

  }

}

$endTime = Get-Date -f "yyyy-MM-dd hh:mm"

       $output = New-Object -TypeName PSobject

 

        $output | add-member NoteProperty "Start Time" -value $logDate

        $output | add-member NoteProperty "End Time" -value $endTime

        $output | add-member NoteProperty "Number of sites with 0 Owners?" -value $owners0

        $output | add-member NoteProperty "Number of sites with 0 owners and less than 2 people?" -value $owners0ppl2

        $output | add-member NoteProperty "Number of sites with 0 owners and less than 5 people?" -value $owners0ppl5

        $output | Add-Member NoteProperty "Number of sites with 0 owners and more than 5 people?" -Value $owners0pplMany

        $output | add-member NoteProperty "Number of sites with 1 Owners?" -value $owners1

        $output | add-member NoteProperty "Number of sites with 1 Owners & 1 Member?" -value $owners1ppl1

        $output | add-member NoteProperty "Number of sites with 2+ Owners?" -value $ownersGood

        $output | Add-Member NoteProperty "Number of Teams Total" -Value $AllTeams

        $output | Add-Member NoteProperty "Errors" -Value $ErrorTeams

 

        $output | Export-Csv -Path $path -NoTypeInformation -Append

 

Itemized User Script

I also needed a list of users so that I could email them about changes that were going to be made to their Team. This is a script that outputs the members of each Team, filtered by ones that have no owners and over 5 members. To get the CSV file I'm referencing in the script, I did an export from Azure AD Groups.

Connect-MicrosoftTeams

 

# Split path

$Path = Split-Path -Parent "C:\SWSetup\*.*"

$LogDate = Get-Date -f yyyyMMddhhmm

$path = $Path + "\TeamsWith5PlusMembersButNoOwners-ItemizedUsers_$logDate.csv"

$sitelist = Import-CSV C:\SWSetup\exportGroup_2023-2-14.csv

 

 

Write-Host "Getting Team Names and Details"         

 

#Get-Team | ForEach-Object {

 

foreach ($s in $sitelist)

if($s.source -eq "Cloud" -and $s.groupType -eq "Microsoft 365" -and $s.membershipType -eq "Assigned"){

  

    # Get Owners, members and guests

 

    $TeamUsers = Get-TeamUser -GroupId $s.id       

    $TeamOwnerCount = ($TeamUsers | Where-Object {$_.Role -like "owner"}).count

    $TeamMemberCount = ($TeamUsers | Where-Object {$_.Role -like "member"}).count

    $TeamGuestCount = ($TeamUsers | Where-Object {$_.Role -like "guest"}).count

 

  #If the Team has members but no owners

  If($TeamOwnerCount -eq 0 -And $TeamMemberCount -gt 4){  

  

        # Set each member to be an owner

        #foreach($u in $TeamUsers| Where-Object {$_.Role -like "member"}){

         #   Add-TeamUser -GroupId $_.GroupID  -User $u.User -Role Owner

       # }

 

 

       foreach($u in $TeamUsers| Where-Object {$_.Role -like "member"}){

 

        Write-host "Getting details for Team $($s.displayName): $($u.User)"

        # Put all details into an object

 

        $output = New-Object -TypeName PSobject

 

        $output | add-member NoteProperty "DisplayName" -value $s.displayName

        $output | add-member NoteProperty "GroupId" -value $s.id

        $output | Add-Member NoteProperty "UserId" -Value $u.UserId

        $output | Add-Member NoteProperty "UPN" -Value $u.User

        $output | Add-Member NoteProperty "Name" -Value $u.Name

        $output | Add-Member NoteProperty "Role " -Value $u.Role

       

 

        $output | Export-Csv -Path $path -NoTypeInformation -Append

        }

    }

    }

}

 

Sources:

 

 


Share on Google Plus

About Tom DeMeulenaere

Highly accomplished information technology professional with extensive knowledge in System Center Configuration Manager, Windows Server, SharePoint, and Office 365.
    Blogger Comment

0 comments:

Post a Comment

Note: Only a member of this blog may post a comment.