Back to script library
Entra / Microsoft 365 · Groups

Report Microsoft 365 groups expiration

A script to show how to use the Microsoft Graph PowerShell SDK to report on the expiration of Microsoft 365 groups.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-MgGraph -Scopes Group.Read.All

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

Connect-MgGraph -Scopes Group.Read.All
Write-Host "Looking for Microsoft 365 Groups with an expiration date set"
[array]$Groups = Get-MgGroup -Filter "groupTypes/any(c:c eq 'unified') and ExpirationDateTime ge 2014-01-01T00:00:00Z" `
-All -PageSize 500 -ConsistencyLevel Eventual -CountVariable Var -Property DisplayName, CreatedDateTime, RenewedDateTime, ExpirationDateTime
If (!($Groups)) {
Write-Host "No groups with expiration dates found"
Break
} Else {
Write-Host ("Found {0} groups with expiration dates" -f $Var)
}
$Today = (Get-Date)
$Report = [System.Collections.Generic.List[Object]]::new()
ForEach ($G in $Groups) {
$Days = (New-TimeSpan -Start $G.CreatedDateTime -End $Today).Days # Age of group
$DaysLeft = (New-TimeSpan -Start $Today -End $G.ExpirationDateTime).Days
$ReportLine = [PSCustomObject]@{
Group = $G.DisplayName
Created = Get-Date($G.CreatedDateTime) -format 'dd-MMM-yyyy HH:mm'
"Age in days" = $Days
"Last renewed" = Get-Date($G.RenewedDateTime) -format 'dd-MMM-yyyy'
"Next renewal" = Get-Date($G.ExpirationDateTime) -format 'dd-MMM-yyyy'
"Days before expiration" = $DaysLeft}
$Report.Add($ReportLine)
} # End Foreach
$Report = $Report | Sort-Object "Days before expiration"
Clear-Host
Write-Host ("A total of {0} Microsoft 365 Groups are covered by expiration policy:" -f $Groups.Count)
Write-Host ""
$Report | Format-Table Group, 'Age in Days', Created, 'Last renewed', 'Next renewal', 'Days before expiration' -AutoSize
$Report | Export-CSV -Path "C:\Temp\GroupExpirationReport.csv" -NoTypeInformation -Encoding UTF8
Attribution