2022-12-13 14:27:10 +05:30
<#
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Name : Get distribution group members report
2025-01-27 14:39:21 +05:30
Version : 4.0
2022-12-13 14:27:10 +05:30
Website : o365reports . com
2023-10-06 17:54:52 +05:30
Script Highlights :
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
1 . The script uses modern authentication to connect to Exchange Online .
2 . Allows you to filter the report result based on group size ( i . e . , Members count ) .
3 . The script can be executed with MFA enabled account too .
4 . You can choose to either “ Export Members of all Distribution Lists ” or pass an input file to “ Export Members of Specific Distribution List ” .
5 . You can filter the output based on whether the group accepts message from external senders or not .
6 . Exports the list of allowed senders to a Distribution List .
7 . Output can be filter ed to list Empty group . i . e . , Distribution Group without members
8 . Exports the report result to CSV .
9 . You can get members count based on Member Type such as User mailbox , Group mailbox , Shared mailbox , Contact , etc .
10 . Automatically installs the EXO V2 ( if not installed already ) upon your confirmation .
11 . The script is scheduler friendly . i . e . , credentials can be passed as parameter instead of saving inside the script .
12 . Above all , script exports output in nicely formatted 2 CSV files . One with detailed information and another with summary information .
2025-01-27 14:39:21 +05:30
Change Log :
V1 . 0 ( Nov 01 , 2019 ) - Script created
V2 . 0 ( Dec 13 , 2022 ) - Upgraded EXO module . Now , you can connect to Exchange Online PowerShell using modern authentication
V3 . 0 ( Oct 06 , 2023 ) - Usability improvements
V4 . 0 ( Jan 27 , 2025 ) - Due to MS update , ManagedBy and Member Names are shown as ID . Handled code for showing user-identifiable name instead of Ids .
Added support for certificate-based authentication ( CBA )
2022-12-13 14:27:10 +05:30
For detailed script execution : https : / / o365reports . com / 2019 / 05 / 23 / export-office - 365 -distribution -group -members -csv /
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
#>
Param
2019-11-01 14:47:22 +05:30
(
[ Parameter ( Mandatory = $false ) ]
[ string ] $GroupNamesFile ,
[ switch ] $IsEmpty ,
[ int ] $MinGroupMembersCount ,
[ Nullable[boolean] ] $ExternalSendersBlocked = $null ,
[ string ] $UserName ,
2025-01-27 14:39:21 +05:30
[ string ] $Password ,
[ string ] $Organization ,
[ string ] $ClientId ,
[ string ] $CertificateThumbprint
2019-11-01 14:47:22 +05:30
)
Function Get_members
{
$DisplayName = $_ . DisplayName
Write-Progress -Activity " `n Processed Group count: $Count " ` n " Getting members of: $DisplayName "
$Alias = $_ . Alias
$EmailAddress = $_ . PrimarySmtpAddress
$GroupType = $_ . GroupType
$ManagedBy = $_ . ManagedBy
$ExternalSendersAllowed = $_ . RequireSenderAuthenticationEnabled
if ( ( $ExternalSendersBlocked -ne $null ) -and ( $ExternalSendersBlocked -ne $ExternalSendersAllowed ) )
{
$Print = 0
}
#Get Distribution Group Authorized Senders
$AcceptMessagesOnlyFrom = $_ . AcceptMessagesOnlyFromSendersOrMembers
$AuthorizedSenders = " "
if ( $AcceptMessagesOnlyFrom . Count -gt 0 )
{
foreach ( $item in $AcceptMessagesOnlyFrom )
{
$AuthorizedSenders = $AuthorizedSenders + $item
if ( $AcceptMessagesOnlyFrom . indexof ( $item ) -lt ( ( $AcceptMessagesOnlyFrom . count ) -1 ) )
{
$AuthorizedSenders = $AuthorizedSenders + " , "
}
}
}
elseif ( $ExternalSendersAllowed -eq " True " )
{
$AuthorizedSenders = " Only Senders in Your Organization "
}
else
{
$AuthorizedSenders = " Senders inside & Outside of Your Organization "
}
2025-01-27 14:39:21 +05:30
$Manager = @ ( )
2019-11-01 14:47:22 +05:30
if ( $_ . ManagedBy . Count -gt 0 )
{
foreach ( $ManageBy in $ManagedBy )
2025-01-27 14:39:21 +05:30
{ #Verify if manager property returned as ID and convert it to user-identifiable name
if ( $ManageBy -match '(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$' )
2019-11-01 14:47:22 +05:30
{
2025-01-27 14:39:21 +05:30
if ( $ManagerHash . ContainsKey ( $ManageBy ) )
{
$ManagerName = $ManagerHash [ $ManageBy ]
}
# Retrieve the display name for the ID
else
{
$ManagerName = ( Get-EXORecipient -Identity $ManageBy ) . DisplayName
$ManagerHash [ $ManageBy ] = $ManagerName
}
$ManageBy = $ManagerName
2019-11-01 14:47:22 +05:30
}
2025-01-27 14:39:21 +05:30
$Manager + = $ManageBy
2019-11-01 14:47:22 +05:30
}
2025-01-27 14:39:21 +05:30
$Manager = $Manager -join " , "
2019-11-01 14:47:22 +05:30
}
$Recipient = " "
$RecipientHash = @ { }
for ( $KeyIndex = 0 ; $KeyIndex -lt $RecipientTypeArray . Length ; $KeyIndex + = 2 )
{
$key = $RecipientTypeArray [ $KeyIndex ]
$Value = $RecipientTypeArray [ $KeyIndex + 1 ]
$RecipientHash . Add ( $key , $Value )
}
$Members = Get-DistributionGroupMember -ResultSize Unlimited -Identity $DisplayName
$MembersCount = ( $Members . name ) . Count
#GroupSize Filter
if ( ( [ int ] $MinGroupMembersCount -ne " " ) -and ( $MembersCount -lt [ int ] $MinGroupMembersCount ) )
{
$Print = 0
}
#Check for Empty Group
elseif ( $MembersCount -eq 0 )
{
$Member = " No Members "
$MemberEmail = " - "
$RecipientTypeDetail = " - "
Print_Output
}
#Loop through each member in a group
else
{
foreach ( $Member in $Members )
{
if ( $IsEmpty . IsPresent )
{
$Print = 0
break
}
$RecipientTypeDetail = $Member . RecipientTypeDetails
$MemberEmail = $Member . PrimarySMTPAddress
2025-01-27 14:39:21 +05:30
$MemberName = $Member . DisplayName
2019-11-01 14:47:22 +05:30
if ( $MemberEmail -eq " " )
{
$MemberEmail = " - "
}
#Get Counts by RecipientTypeDetail
foreach ( $key in [ object[] ] $Recipienthash . Keys )
{
if ( ( $RecipientTypeDetail -eq $key ) -eq " true " )
{
[ int ] $RecipientHash [ $key ] + = 1
}
}
Print_Output
}
}
#Print Summary report
if ( $Print -eq 1 )
{
#Order RecipientTypeDetail based on count
$Hash = @ { }
$Hash = $RecipientHash . GetEnumerator ( ) | Sort-Object -Property value -Descending | foreach {
if ( [ int ] $ ( $_ . Value ) -gt 0 )
{
if ( $Recipient -ne " " )
{ $Recipient + = " ; " }
$Recipient + = @ ( " $( $_ . Key ) - $( $_ . Value ) " )
}
if ( $Recipient -eq " " )
{ $Recipient = " - " }
}
$Result = @ { 'DisplayName' = $DisplayName ; 'PrimarySmtpAddress' = $EmailAddress ; 'Alias' = $Alias ; 'GroupType' = $GroupType ; 'Manager' = $Manager ; 'GroupMembersCount' = $MembersCount ; 'MembersCountByType' = $Recipient ; 'AuthorizedSenders' = $AuthorizedSenders ; 'ExternalSendersBlocked' = $ExternalSendersAllowed <# ;'HiddenFromAddressList'=$_ . HiddenFromAddressListsEnabled;
'Description' = $_ . Description ; 'CreationTime' = $_ . WhenCreated ; 'DirSyncEnabled' = $_ . IsDirSynced ; 'JoinGroupWithoutApproval' = $_ . MemberJoinRestriction ; 'LeaveGroupWithoutApproval' = $_ . MemberDepartRestriction #>} #Uncomment to print additional attributes in output
$Results = New-Object PSObject -Property $Result
$Results | Select-Object DisplayName , PrimarySmtpAddress , Alias , GroupType , Manager , GroupMembersCount , AuthorizedSenders , ExternalSendersBlocked , MembersCountByType <# ,HiddenFromAddressList,Description,CreationTime,DirSyncEnabled,JoinGroupWithoutApproval,LeaveGroupWithoutApproval #> | Export-Csv -Path $ExportSummaryCSV -Notype -Append
}
}
#Print Detailed Output
Function Print_Output
{
if ( $Print -eq 1 )
{
2025-01-27 14:39:21 +05:30
$Result = @ { 'DisplayName' = $DisplayName ; 'PrimarySmtpAddress' = $EmailAddress ; 'Alias' = $Alias ; 'Members' = $MemberName ; 'MemberEmail' = $MemberEmail ; 'MemberType' = $RecipientTypeDetail }
2019-11-01 14:47:22 +05:30
$Results = New-Object PSObject -Property $Result
$Results | Select-Object DisplayName , PrimarySmtpAddress , Alias , Members , MemberEmail , MemberType | Export-Csv -Path $ExportCSV -Notype -Append
}
}
Function main ( )
{
2025-01-27 14:39:21 +05:30
#Check for EXO module inatallation
2022-12-13 14:27:10 +05:30
$Module = Get-Module ExchangeOnlineManagement -ListAvailable
if ( $Module . count -eq 0 )
{
2025-01-27 14:39:21 +05:30
Write-Host Exchange Online PowerShell module is not available -ForegroundColor yellow
2022-12-13 14:27:10 +05:30
$Confirm = Read-Host Are you sure you want to install module ? [ Y] Yes [N ] No
if ( $Confirm -match " [yY] " )
{
Write-host " Installing Exchange Online PowerShell module "
Install-Module ExchangeOnlineManagement -Repository PSGallery -AllowClobber -Force
}
else
{
2025-01-27 14:39:21 +05:30
Write-Host EXO module is required to connect Exchange Online . Please install module using Install-Module ExchangeOnlineManagement cmdlet .
2022-12-13 14:27:10 +05:30
Exit
}
}
Write-Host Connecting to Exchange Online . . .
#Storing credential in script for scheduling purpose/ Passing credential as parameter - Authentication using non-MFA account
if ( ( $UserName -ne " " ) -and ( $Password -ne " " ) )
2019-11-01 14:47:22 +05:30
{
2022-12-13 14:27:10 +05:30
$SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force
$Credential = New-Object System . Management . Automation . PSCredential $UserName , $SecuredPassword
2025-01-27 14:39:21 +05:30
Connect-ExchangeOnline -Credential $Credential -ShowBanner: $false
}
elseif ( $Organization -ne " " -and $ClientId -ne " " -and $CertificateThumbprint -ne " " )
{
Connect-ExchangeOnline -AppId $ClientId -CertificateThumbprint $CertificateThumbprint -Organization $Organization -ShowBanner: $false
2019-11-01 14:47:22 +05:30
}
else
{
2025-01-27 14:39:21 +05:30
Connect-ExchangeOnline -ShowBanner: $false
2019-11-01 14:47:22 +05:30
}
2025-01-27 14:39:21 +05:30
2019-11-01 14:47:22 +05:30
#Set output file
$ExportCSV = " .\DistributionGroup-DetailedMembersReport_ $( ( Get-Date -format yyyy-MMM -dd -ddd ` hh-mm ` tt ) . ToString ( ) ) .csv " #Detailed report
$ExportSummaryCSV = " .\DistributionGroup-SummaryReport_ $( ( Get-Date -format yyyy-MMM -dd -ddd ` hh-mm ` tt ) . ToString ( ) ) .csv " #Summary report
#Get a list of RecipientTypeDetail
$RecipientTypeArray = Get-Content -Path . \ RecipientTypeDetails . txt -ErrorAction Stop
$Result = " "
$Results = @ ( )
2025-01-27 14:39:21 +05:30
$ManagerHash = @ { }
2019-11-01 14:47:22 +05:30
#Check for input file
if ( [ string ] $GroupNamesFile -ne " " )
{
#We have an input file, read it into memory
$DG = @ ( )
$DG = Import-Csv -Header " DisplayName " $GroupNamesFile
foreach ( $item in $DG )
{
Get-DistributionGroup -Identity $item . displayname | Foreach {
$Print = 1
Get_Members }
$Count + +
}
}
else
{
#Get all distribution group
Get-DistributionGroup -ResultSize Unlimited | Foreach {
$Print = 1
Get_Members
$Count + + }
}
#Open output file after execution
Write-Host ` nScript executed successfully
if ( ( Test-Path -Path $ExportCSV ) -eq " True " )
{
2023-10-06 17:54:52 +05:30
Write-Host ` n " Detailed report available in: " -NoNewline -ForegroundColor Yellow
Write-Host $ExportCSV ` n
Write-host " Summary report available in: " -NoNewline -ForegroundColor Yellow
Write-Host $ExportSummaryCSV
Write-Host ` n ~ ~ Script prepared by AdminDroid Community ~ ~ ` n -ForegroundColor Green
Write-Host " ~~ Check out " -NoNewline -ForegroundColor Green ; Write-Host " admindroid.com " -ForegroundColor Yellow -NoNewline ; Write-Host " to get access to 1800+ Microsoft 365 reports. ~~ " -ForegroundColor Green ` n ` n
2019-11-01 14:47:22 +05:30
$Prompt = New-Object -ComObject wscript . shell
$UserInput = $Prompt . popup ( " Do you want to open output file? " , `
0 , " Open Output File " , 4 )
If ( $UserInput -eq 6 )
{
Invoke-Item " $ExportCSV "
Invoke-Item " $ExportSummaryCSV "
}
}
Else
{
Write-Host No DistributionGroup found
}
2022-12-13 14:27:10 +05:30
#Disconnect Exchange Online session
Disconnect-ExchangeOnline -Confirm: $false -InformationAction Ignore -ErrorAction SilentlyContinue
2019-11-01 14:47:22 +05:30
}
. main