Wednesday, April 8, 2026

How to Check User Membership & Ownership Across All Exchange Online Group Types Using PowerShell

How to Check User Membership & Ownership Across All Exchange Online Group Types Using PowerShell

Introduction

As an M365 administrator, one of the recurring tasks is auditing user membership and ownership across various group types in Exchange Online. The challenge? Microsoft 365 has three distinct group types, each managed by different cmdlets — and a one-size-fits-all script simply won't work.

In this post, I'll walk you through a PowerShell script that:

  • Detects group type automatically (M365 Group, Distribution Group, or Mail-enabled Security Group)
  • Checks whether a user is an Owner, Member, Both, or None
  • Reads groups from a CSV file for bulk processing
  • Writes results to a timestamped CSV dynamically (row-by-row, not at the end)

The Three Group Types in Exchange Online

Before diving into the script, it's important to understand what we're dealing with:

Group Type RecipientTypeDetails Managed By Cmdlet
Microsoft 365 Group GroupMailbox Get-UnifiedGroup
Distribution Group MailUniversalDistributionGroup Get-DistributionGroup
Mail-enabled Security Group MailUniversalSecurityGroup Get-DistributionGroup

Each type stores ownership and membership differently, which is why a single cmdlet can't cover all scenarios.


Prerequisites

  • Exchange Online Management module installed:
    Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber
    
  • Connected to Exchange Online:
    Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
    

Input: groups.csv

Create a simple CSV with one column — the group email addresses you want to audit:

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

The Script

# ─────────────────────────────────────────────
# Config
# ─────────────────────────────────────────────
$CsvPath   = "C:\Scripts\groups.csv"
$UserEmail = "john.doe@contoso.com"

# Dynamic timestamped output file
$timestamp  = Get-Date -Format "yyyyMMdd_HHmmss"
$OutputPath = "C:\Scripts\output_$timestamp.csv"

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

# ─────────────────────────────────────────────
# Clear output file if it exists from a prior run
# ─────────────────────────────────────────────
if (Test-Path $OutputPath) { Remove-Item $OutputPath }

# ─────────────────────────────────────────────
# Process each group
# ─────────────────────────────────────────────
$results = foreach ($row in (Import-Csv $CsvPath)) {
    $GroupEmail = $row.GroupEmail
    $isOwner = $isMember = $false

    # 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 "[$GroupEmail] Detected Type: $groupType" -ForegroundColor Cyan

    # Check ownership & membership based on group type
    if ($groupType -eq "M365Group") {
        $isOwner  = [bool](Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Owners  -ResultSize Unlimited |
                           Where-Object { $_.PrimarySmtpAddress -eq $UserEmail })
        $isMember = [bool](Get-UnifiedGroupLinks -Identity $GroupEmail -LinkType Members -ResultSize Unlimited |
                           Where-Object { $_.PrimarySmtpAddress -eq $UserEmail })
    }
    elseif ($groupType -in "DistributionGroup", "SecurityGroup") {
        $isMember = [bool](Get-DistributionGroupMember -Identity $GroupEmail -ResultSize Unlimited |
                           Where-Object { $_.PrimarySmtpAddress -eq $UserEmail })
        $isOwner  = [bool]($distGroup.ManagedBy |
                           Where-Object { $_ -like "*$($UserEmail.Split('@')[0])*" })
    }

    # Determine role
    $role = switch ($true) {
        ($isOwner -and $isMember) { "Owner & Member" }
        ($isOwner)                { "Owner only"     }
        ($isMember)               { "Member only"    }
        default                   { "None"           }
    }

    # Build result object
    $record = [PSCustomObject]@{
        GroupEmail = $GroupEmail
        User       = $UserEmail
        GroupType  = $groupType
        IsOwner    = $isOwner
        IsMember   = $isMember
        Role       = $role
    }

    # Write to CSV immediately (not at the end)
    $record | Export-Csv $OutputPath -Append -NoTypeInformation
    Write-Host "  → Role: $role" -ForegroundColor Green

    $record  # Feed into $results for Format-Table
}

# ─────────────────────────────────────────────
# Console summary
# ─────────────────────────────────────────────
Write-Host "`n=== Summary ===" -ForegroundColor Yellow
$results | Format-Table -AutoSize

Write-Host "`nOutput saved to: $OutputPath" -ForegroundColor Green

Sample Output

GroupEmail               User                    GroupType          IsOwner  IsMember  Role
---------                ----                    ---------          -------  --------  ----
hr-team@contoso.com      john.doe@contoso.com    M365Group          True     True      Owner & Member
all-staff@contoso.com    john.doe@contoso.com    DistributionGroup  False    True      Member only
it-security@contoso.com  john.doe@contoso.com    SecurityGroup      False    False     None

Conclusion

Exchange Online group auditing doesn't need to be painful. By detecting group type dynamically and merging the overlapping DG/SG logic, this script stays concise while covering all three group types reliably. The dynamic CSV write and timestamped output make it production-ready for bulk audits.

No comments:

Post a Comment

Featured Post

How to Check User Membership & Ownership Across All Exchange Online Group Types Using PowerShell

How to Check User Membership & Ownership Across All Exchange Online Group Types Using PowerShell Introduction As an M365 administrato...

Popular posts