Group lifecycle policies — set group expiration, manage renewal,¶
and enable auto-renewal for Microsoft 365 groups.
M365 group expiration is a core governance feature. Without it, groups accumulate and never get cleaned up. This example shows: - List existing lifecycle policies - Add groups to a policy - Remove groups from a policy - Renew a group (keep alive)
Permissions
Requires delegated permission Group.ReadWrite.All.
Reference¶
from office365.graph_client import GraphClient
from tests import test_client_id, test_client_secret, test_tenant
def main():
client = GraphClient(tenant=test_tenant).with_client_secret(test_client_id, test_client_secret)
# -- Step 1: list existing lifecycle policies --
policies = client.group_lifecycle_policies.get().execute_query()
print(f"Group lifecycle policies: {len(policies)}\n")
for p in policies:
lifetime = p.group_lifetime_in_days or "?"
notification = p.alternate_notification_emails or "(none)"
managed = p.managed_group_types or []
print(f" Lifetime: {lifetime:>3} days notification: {notification:45s} managed types: {managed}")
# -- Step 2: find groups not covered by any policy --
groups = (
client.groups.get()
.filter("resourceProvisioningOptions/Any(x:x eq 'Team') or mailEnabled eq true")
.select(["id", "displayName", "mail"])
.top(999)
.execute_query()
)
covered = set()
for p in policies:
gid = p.properties.get("groupId", "")
if gid:
covered.add(gid)
elif hasattr(p, "properties") and p.properties.get("groupIds"):
for gid in p.properties["groupIds"]:
covered.add(gid)
uncovered = [g for g in groups if g.id not in covered]
print(f"\nM365 groups: {len(groups)}")
print(f"Uncovered by lifecycle policy: {len(uncovered)}")
if uncovered:
print("\nFirst 5 groups without expiration:")
for g in uncovered[:5]:
print(f" {g.display_name:40s} {g.mail or '?'}")
# -- Step 3: create a lifecycle policy (commented) --
# policy = client.group_lifecycle_policies.add(
# groupLifetimeInDays=180,
# managedGroupTypes="All",
# alternateNotificationEmails="admin@contoso.com",
# ).execute_query()
# print(f"\n✓ Lifecycle policy created")
# -- Step 4: add a group to the policy --
if policies and uncovered:
group = uncovered[0]
if group.id:
policy = policies[0]
policy.add_group(group_id=group.id).execute_query()
print(f"\n✓ Added {group.display_name} to lifecycle policy.")
# -- Step 5: renew a group (keep alive another period) --
sample = next((p.properties.get("groupId", "") for p in policies if p.properties.get("groupId")), None)
if sample:
group = client.groups[sample].get().execute_query()
group.renew().execute_query()
print(f"✓ Renewed group {sample[:20]}.")
# -- Cleanup: remove a group from policy --
# policy.remove_group(group_id=group_id).execute_query()
# print("✓ Removed group from policy.")
print("\nDone.")
if __name__ == "__main__":
main()