The script creates a CSV-formatted report on licenses assigned to members of a dynamic distribution list.
To generate such a report on request, you can create a custom command that runs the script on Ms-Exch-Dynamic-Distribution-List objects. For this purpose, on Step 2 of the Create Custom Command wizard, select Show all object types and Ms-Exch-Dynamic-Distribution-List.
Parameters:
- $exchangeServer - Specifies the fully qualified domain name (FQDN) of your Exchange Server.
- $csvFilePath - Specifies a full path to the CSV file containing the report.
- $propertiesToExport - Specifies LDAP names of properties of the members to to include in the report.
PowerShell
$exchangeServer = "exchangeserver.domain.com" # TODO: modify me
$csvFilePath = "\\SERVER\share\members.csv" # TODO: modify me
$propertiesToExport = @("Name", "Description", "Department", "mail") # TODO: modify me
try
{
# Create a remote PowerShell session to the Exchange Server
$session = New-PSSession -configurationname Microsoft.Exchange -connectionURI http://$exchangeServer/PowerShell
Import-PSSession $session -DisableNameChecking -AllowClobber
# Get Dynamic Distribution Group
$group = Get-DynamicDistributionGroup -Identity "%distinguishedName%"
# Get members
$members = Get-Recipient -RecipientPreviewFilter $group.RecipientFilter -OrganizationalUnit $group.RecipientContainer
# Build search filter to find all members in AD
$filter = New-Object "System.Text.StringBuilder"
[void]$filter.Append("(|")
foreach ($member in $members)
{
$guid = [Guid]$member.Guid
[void]$filter.Append([Softerra.Adaxes.Ldap.FilterBuilder]::Create("objectGuid", $guid))
}
[void]$filter.Append(")")
}
finally
{
# Release resources
if ($session) { Remove-PSSession $session }
}
# Find members in AD
$domainName = $Context.GetObjectDomain("%distinguishedName%")
$searcher = $Context.BindToObject("Adaxes://$domainName/RootDSE")
$searcher.SearchFilter = $filter.ToString()
$searcher.PageSize = 500
$searcher.SetPropertiesToLoad($propertiesToExport)
try
{
$searchResultIterator = $searcher.ExecuteSearch()
$searchResults = $searchResultIterator.FetchAll()
$records = @()
foreach ($searchResult in $searchResults)
{
$record = New-Object PSObject
foreach ($propertyName in $propertiesToExport)
{
$record | Add-Member -Name $propertyName -Value $searchResult.Properties[$propertyName].Value -MemberType NoteProperty
}
$record | Add-Member -Name "IsLicensed" -Value $NULL -MemberType NoteProperty
# Bind to member
$member = $Context.BindToObject($searchResult.AdsPath)
if ($member.Class -eq "User")
{
$isLicensed = $False
try
{
# Get Microsoft 365 properties
$microsoft365Properties = $member.GetMicrosoft365Properties()
}
catch
{
$microsoft365Properties = $NULL # No Microsoft 365 account
}
if ($microsoft365Properties -ne $NULL)
{
# Check assigned licenses
$licenses = $microsoft365Properties.Licenses
foreach ($license in $licenses)
{
if ($license.Assigned)
{
$isLicensed = $True
break
}
}
}
$record.IsLicensed = $isLicensed
}
$records += $record
}
# Export members
$records | Export-Csv -NoTypeInformation -Path $csvFilePath
}
finally
{
# Release resources used by search
if ($searchResultIterator) { $searchResultIterator.Dispose() }
}