Thursday, April 9, 2026

How to Get, Remove Owner & Remove Member from Exchange Online Groups Using PowerShell

How to Get, Remove Owner & Remove Member from Exchange Online Groups Using PowerShell

As an M365 administrator, you often need to audit or clean up group ownership and membership — especially during employee offboarding or role transitions. The challenge? Microsoft 365 has three different group types, each managed by different cmdlets.

In this post, I'll share three ready-to-use PowerShell scripts that cover:

  • Get owners of a group (all three types)
  • Remove a user as an owner
  • Remove a user as a member

All scripts read group names from a CSV file, making them ideal for bulk operations.


The Three Group Types in Exchange Online

Group TypeRecipientTypeDetailsCmdlet Used
Microsoft 365 GroupGroupMailboxGet-UnifiedGroup
Distribution GroupMailUniversalDistributionGroupGet-DistributionGroup
Mail-enabled Security GroupMailUniversalSecurityGroupGet-DistributionGroup

Each type stores ownership and membership differently, which is why a single cmdlet won't work for all.


Prerequisites

Install the required modules if not already installed:

Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber
Install-Module -Name Microsoft.Graph -Force -AllowClobber

Connect before running any script:

Set-MgGraphOption -DisableLoginByWAM $true   # Fix WAM broker error on Windows
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
Note: Set-MgGraphOption -DisableLoginByWAM $true is required on some Windows environments to avoid a known MSAL authentication error.

Input: groups.csv

All three scripts read from a CSV with one column — GroupEmail:

GroupEmail
hr-team@contoso.com
all-staff@contoso.com
it-security@contoso.com

Script 1: Get Group Owners

This script detects the group type automatically and lists all current owners.

# ============================================================
# Get Group Owners from CSV
# ============================================================

Set-MgGraphOption -DisableLoginByWAM $true
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

$CsvPath = "C:\Scripts\groups.csv"

foreach ($row in (Import-Csv $CsvPath)) {
    $GroupEmail = $row.GroupEmail

    Write-Host "`n========== Detecting Group Type: $GroupEmail ==========`n" -ForegroundColor Cyan

    # Detect group type
    $unifiedGroup = Get-UnifiedGroup      -Identity $GroupEmail -ErrorAction SilentlyContinue
    $distGroup    = Get-DistributionGroup -Identity $GroupEmail -ErrorAction SilentlyContinue

    $groupType = if ($unifiedGroup) { "M365Group" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalDistributionGroup") { "DistributionGroup" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalSecurityGroup")     { "SecurityGroup" }
                 else { "Unknown" }

    Write-Host "Detected Type: $groupType" -ForegroundColor Yellow

    # Get owners based on type
    $owners = @()

    if ($groupType -eq "M365Group") {
        $owners = Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners -ResultSize Unlimited |
                  Select-Object DisplayName, PrimarySmtpAddress,
                                @{N="GroupType"; E={"M365Group"}},
                                @{N="GroupEmail"; E={$GroupEmail}}
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $owners = $distGroup.ManagedBy | ForEach-Object {
            $recipient = Get-Recipient $_ -ErrorAction SilentlyContinue
            [PSCustomObject]@{
                DisplayName        = $recipient.DisplayName
                PrimarySmtpAddress = $recipient.PrimarySmtpAddress
                GroupType          = $groupType
                GroupEmail         = $GroupEmail
            }
        }
    }

    if ($owners) {
        Write-Host "`nOwners found:" -ForegroundColor Green
        $owners | Format-Table DisplayName, PrimarySmtpAddress, GroupType, GroupEmail -AutoSize
    } else {
        Write-Host "No owners found or group type is Unknown." -ForegroundColor Red
    }
}

Script 2: Remove a User as Owner

This script removes a specific user from the owners list only — membership is not affected. It also includes safety checks: skips if the user is not an owner, and blocks removal if they are the only owner.

Important: Exchange Online does not allow removing the last owner of a group. You must assign another owner first.
# ============================================================
# Remove Owner from Groups (CSV)
# ============================================================

Set-MgGraphOption -DisableLoginByWAM $true
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

$CsvPath     = "C:\Scripts\groups.csv"
$RemoveOwner = "john.doe@contoso.com"

foreach ($row in (Import-Csv $CsvPath)) {
    $GroupEmail = $row.GroupEmail

    Write-Host "`n========== Detecting Group Type: $GroupEmail ==========`n" -ForegroundColor Cyan

    $unifiedGroup = Get-UnifiedGroup      -Identity $GroupEmail -ErrorAction SilentlyContinue
    $distGroup    = Get-DistributionGroup -Identity $GroupEmail -ErrorAction SilentlyContinue

    $groupType = if ($unifiedGroup) { "M365Group" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalDistributionGroup") { "DistributionGroup" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalSecurityGroup")     { "SecurityGroup" }
                 else { "Unknown" }

    Write-Host "Detected Type: $groupType" -ForegroundColor Yellow

    # Get owners
    $owners = @()
    if ($groupType -eq "M365Group") {
        $owners = Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners -ResultSize Unlimited |
                  Select-Object DisplayName, PrimarySmtpAddress,
                                @{N="GroupType"; E={"M365Group"}},
                                @{N="GroupEmail"; E={$GroupEmail}}
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $owners = $distGroup.ManagedBy | ForEach-Object {
            $recipient = Get-Recipient $_ -ErrorAction SilentlyContinue
            [PSCustomObject]@{
                DisplayName        = $recipient.DisplayName
                PrimarySmtpAddress = $recipient.PrimarySmtpAddress
                GroupType          = $groupType
                GroupEmail         = $GroupEmail
            }
        }
    }

    if ($owners) {
        Write-Host "`nOwners found:" -ForegroundColor Green
        $owners | Format-Table DisplayName, PrimarySmtpAddress, GroupType, GroupEmail -AutoSize
    } else {
        Write-Host "No owners found or group type is Unknown." -ForegroundColor Red
    }

    # --------------------------------------------------------
    # Remove Owner
    # --------------------------------------------------------
    Write-Host "`n========== Removing Owner: $RemoveOwner ==========`n" -ForegroundColor Cyan

    if ($groupType -eq "M365Group") {
        $currentOwners = Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners -ResultSize Unlimited
        $isOwner       = $currentOwners | Where-Object { $_.PrimarySmtpAddress -eq $RemoveOwner }

        if (-not $isOwner) {
            Write-Host "$RemoveOwner is not an owner of this group. Skipping." -ForegroundColor Yellow
        }
        elseif ($currentOwners.Count -eq 1) {
            Write-Host "Cannot remove $RemoveOwner - they are the only owner. Assign another owner first." -ForegroundColor Red
        }
        else {
            Remove-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners -Links $RemoveOwner -Confirm:$false
            Write-Host "Owner removed successfully from M365 Group." -ForegroundColor Green
        }
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $isOwner = $distGroup.ManagedBy | Where-Object { $_ -like "*$($RemoveOwner.Split('@')[0])*" }

        if (-not $isOwner) {
            Write-Host "$RemoveOwner is not an owner of this group. Skipping." -ForegroundColor Yellow
        }
        elseif ($distGroup.ManagedBy.Count -eq 1) {
            Write-Host "Cannot remove $RemoveOwner - they are the only owner. Assign another owner first." -ForegroundColor Red
        }
        else {
            Set-DistributionGroup -Identity $GroupEmail -ManagedBy @{Remove = $RemoveOwner}
            Write-Host "Owner removed successfully from $groupType." -ForegroundColor Green
        }
    }
    else {
        Write-Host "Cannot remove owner - Group type is Unknown." -ForegroundColor Red
    }
}

Script 3: Remove a User as Member

This script removes a specific user from the members list only — ownership is not affected. It checks if the user is actually a member before attempting removal, so no other members are touched.

Tip: For on-premises synced groups, Exchange Online will throw a permissions error. Those groups must be managed via Active Directory or on-prem Exchange Admin Center.
# ============================================================
# Remove Member from Groups (CSV)
# ============================================================

Set-MgGraphOption -DisableLoginByWAM $true
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

$CsvPath      = "C:\Scripts\groups.csv"
$RemoveMember = "john.doe@contoso.com"

foreach ($row in (Import-Csv $CsvPath)) {
    $GroupEmail = $row.GroupEmail

    Write-Host "`n========== Detecting Group Type: $GroupEmail ==========`n" -ForegroundColor Cyan

    $unifiedGroup = Get-UnifiedGroup      -Identity $GroupEmail -ErrorAction SilentlyContinue
    $distGroup    = Get-DistributionGroup -Identity $GroupEmail -ErrorAction SilentlyContinue

    $groupType = if ($unifiedGroup) { "M365Group" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalDistributionGroup") { "DistributionGroup" }
                 elseif ($distGroup.RecipientTypeDetails -eq "MailUniversalSecurityGroup")     { "SecurityGroup" }
                 else { "Unknown" }

    Write-Host "Detected Type: $groupType" -ForegroundColor Yellow

    # Get owners
    $owners = @()
    if ($groupType -eq "M365Group") {
        $owners = Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners -ResultSize Unlimited |
                  Select-Object DisplayName, PrimarySmtpAddress,
                                @{N="GroupType"; E={"M365Group"}},
                                @{N="GroupEmail"; E={$GroupEmail}}
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $owners = $distGroup.ManagedBy | ForEach-Object {
            $recipient = Get-Recipient $_ -ErrorAction SilentlyContinue
            [PSCustomObject]@{
                DisplayName        = $recipient.DisplayName
                PrimarySmtpAddress = $recipient.PrimarySmtpAddress
                GroupType          = $groupType
                GroupEmail         = $GroupEmail
            }
        }
    }

    if ($owners) {
        Write-Host "`nOwners found:" -ForegroundColor Green
        $owners | Format-Table DisplayName, PrimarySmtpAddress, GroupType, GroupEmail -AutoSize
    } else {
        Write-Host "No owners found or group type is Unknown." -ForegroundColor Red
    }

    # --------------------------------------------------------
    # Remove Member
    # --------------------------------------------------------
    Write-Host "`n========== Removing Member: $RemoveMember ==========`n" -ForegroundColor Cyan

    if ($groupType -eq "M365Group") {
        $isMember = Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Members -ResultSize Unlimited |
                    Where-Object { $_.PrimarySmtpAddress -eq $RemoveMember }

        if ($isMember) {
            try {
                Remove-UnifiedGroupLinks -Identity $GroupEmail -LinkType Members -Links $RemoveMember -Confirm:$false -ErrorAction Stop
                Write-Host "Member removed successfully from M365 Group." -ForegroundColor Green
            } catch {
                Write-Host "ERROR removing member from M365 Group: $_" -ForegroundColor Red
            }
        } else {
            Write-Host "$RemoveMember is not a member of this group. Skipping." -ForegroundColor Yellow
        }
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $isMember = Get-DistributionGroupMember -Identity $GroupEmail -ResultSize Unlimited |
                    Where-Object { $_.PrimarySmtpAddress -eq $RemoveMember }

        if ($isMember) {
            try {
                Remove-DistributionGroupMember -Identity $GroupEmail -Member $RemoveMember -Confirm:$false -ErrorAction Stop
                Write-Host "Member removed successfully from $groupType." -ForegroundColor Green
            } catch {
                Write-Host "ERROR removing member from $groupType : $_" -ForegroundColor Red
            }
        } else {
            Write-Host "$RemoveMember is not a member of this group. Skipping." -ForegroundColor Yellow
        }
    }
    else {
        Write-Host "Cannot remove member - Group type is Unknown." -ForegroundColor Red
    }
}

Key Points to Remember

ScenarioWhat Happens
M365 Group — Remove OwnerUses Remove-UnifiedGroupLinks -LinkType Owners. Member link is kept.
M365 Group — Remove MemberUses Remove-UnifiedGroupLinks -LinkType Members. Owner link is kept.
DG / Security Group — Remove OwnerUses Set-DistributionGroup -ManagedBy @{Remove=...}
DG / Security Group — Remove MemberUses Remove-DistributionGroupMember
Only one owner leftScript blocks removal and shows a red warning
User not in groupScript skips with a yellow message — no error thrown
On-premises synced groupMust be managed via Active Directory, not Exchange Online

Conclusion

Managing Exchange Online group ownership and membership across multiple group types doesn't have to be complex. By detecting the group type dynamically and applying the right cmdlet per type, these scripts handle all three group types reliably from a simple CSV input. The built-in safety checks — solo owner protection, membership validation, and skip-on-not-found logic — make them safe to run in bulk during offboarding or access reviews.

#PowerShell #ExchangeOnline #Microsoft365 #M365Admin #MicrosoftTeams #M365Groups #DistributionGroups #SecurityGroups #ITAdmin #CloudAdmin #Office365 #M365 #PowerShellAutomation #ExchangeAdmin

No comments:

Post a Comment

Featured Post

How to Get, Remove Owner & Remove Member from Exchange Online Groups Using PowerShell

How to Get, Remove Owner & Remove Member from Exchange Online Groups Using PowerShell As an M365 administrator, you often need to audit ...

Popular posts