How to Check Distribution Lists for Activity Over the Last 90 Days

Looking for Inactive Distribution Lists

In November 2018, I discussed how to use message trace data to find inactive distribution lists. The code used the old Get-MessageTrace cmdlet from the Exchange Online management module. The old cmdlet was replaced by the Get-MessageTraceV2 cmdlet in June 2025, and ceased working in September 2025.

It takes time to get around to updating scripts, especially when no one asks you why code doesn’t work. Or, as in our case, the technical edit review for the 2027 edition of the Office 365 for IT Pros eBook (to be renamed as Microsoft 365 for IT Pros), finds an error in text which must be fixed. Time to crack open Visual Studio Code.

Fetching 90 Days of Message Trace Data

The older script fetched ten days of message trace data and checked the primary SMTP address of each distribution list against the message trace data to establish if the distribution list is active. The ten-day window of information limits the usefulness of the check, but it was set by the amount of “warm” (accessible) message trace data held online by Exchange Online. Historical message trace data going back for 90 days is available and can be retrieved using background jobs launched by the Start-HistoricalSearch cmdlet.

Like its predecessor, the Get-MessageTraceV2 cmdlet operates with a ten-day window. However, the new cmdlet can go back up to 90 days in the past, so long as you retrieve data in ten-day “chunks.”

Checking for Inactive Distribution Lists Over the Last 90 Days

This new capability opens up the possibility to check for inactive distribution lists over the last 90 days rather than ten. To do this, we need to:

  • Divide the 90-day range into nine chunks, each spanning ten days.
  • Fetch the message trace data for each chunk.
  • Combine the data together to form one set of message trace information.
  • Check each distribution list against the combined message trace information.

The first piece of code shows how to create the nine date ranges:

$iterations = 9
[int]$i = 0

[array]$DateRanges = $null

For ($i=0; $i -lt $iterations; $i++) {
    $RangeStart = $StartDate.AddDays($i * 10)
    $RangeEnd = $StartDate.AddDays(($i + 1) * 10)
    If ($RangeEnd -gt $EndDate) {
        $RangeEnd = $EndDate
    }
    $DateRanges += @{Start=$RangeStart; End=$RangeEnd}
}

Fetching the message trace data for a chunk is done with a function to find records for “expanded” events. These events occur when the Exchange transport service expands the membership of a distribution list and bifurcates the message into separate copies for each recipient. You can see that the function retrieves data in pages of 2000 records and that any system messages are removed from the set before the function returns.

function Get-DateRangeData {
    param (
        [datetime]$StartDate,
        [datetime]$EndDate
    )
    
    # Function to fetch message trace data for expanded events over a 10-day period.
    [array]$Messages = $null
    Write-Host ("Collecting message trace data between {0} and {1}..." -f $StartDate, $EndDate)
    [int]$BatchSizeForMessages = 2000
    Try {
        # The warning action is suppressed here because we don't want to see warnings when more data is available
        [array]$MessagePage = Get-MessageTraceV2 -StartDate $StartDate -EndDate $EndDate -ResultSize $BatchSizeForMessages -Status "Expanded" -ErrorAction Stop -WarningAction SilentlyContinue
        $Messages += $MessagePage
    } Catch {
        Write-Host ("Error fetching message trace data: {0}" -f $_.Exception.Message)
        Break
    }
    If ($MessagePage.count -eq $BatchSizeForMessages) {
        Do {
            Write-Host ("Fetched {0} messages so far" -f $Messages.count)
            $LastMessageFetched = $MessagePage[-1]
            $LastMessageFetchedDate = $LastMessageFetched.Received.ToString("O")
            $LastMessageFetchedRecipient = $LastMessageFetched.RecipientAddress
            # Fetch the next page of messages
            [array]$MessagePage = Get-MessageTraceV2 -StartDate $StartDate -EndDate $LastMessageFetchedDate  -StartingRecipientAddress $LastMessageFetchedRecipient -ResultSize $BatchSizeForMessages -Status "Expanded" -ErrorAction Stop -WarningAction SilentlyContinue
            If ($MessagePage) {
                $Messages += $MessagePage
            }
        } While ($MessagePage.count -eq $BatchSizeForMessages)
}

    # Remove Exchange Online public folder hierarchy synchronization messages
    $Messages = $Messages | Where-Object {$_.Subject -NotLike "*HierarchySync*"}
    return $Messages
}

After fetching the nine chunks of message trace data, the script sorts the data by received date in descending order and creates a table from the message trace data based on unique SMTP addresses. The resulting table has one record for each distribution list with an expanded event during the 90-day period. The received date for the record is the date and time when the distribution list was last active.

To complete the process, it’s a matter of looping through the distribution lists and checking if a record exists for each list in the table. If a record exists, the distribution list has been active at least once within the last 90 days. If not, we conclude that we have an inactive distribution list. The script also checks how many expansion events for the distribution list in the message trace data and notes that number. That number is a better indicator of overall distribution list activity.

Checking for inactive distribution lists.
Figure 1: Checking distribution lists for activity

Distribution Lists Are Still Important

You can download the updated script from the Microsoft 365 for IT Pros GitHub repository. The script isn’t very complicated and I’m sure that others will have ideas to add. Use GitHub to share those ideas so that we all benefit from tools to automate the management of the still-used and still-important Exchange Online distribution lists.


We published the original edition of the Microsoft 365 for IT Pros eBook in May 2015. At that point, the book was 500 pages long, focused mostly on Exchange Online, and cost $49.95, or the equivalent of 25 cups of black coffee. Now the 13th version is 980 pages, covers the core components of Microsoft 365, and includes the 430-page Automating Microsoft 365 with PowerShell eBook plus new eBooks covering Power Platform and Microsoft Purview, and costs $59.95, or less than 10 cups of black coffee. Your favorite beverage has gotten way more expensive since 2015 while our book continues to add value at a great price. Who doesn’t like a book that is updated monthly to make sure that its text keeps pace with everything that happens inside Microsoft 365? https://gum.co/O365IT/

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.