Skip to content

Cleanup candidates: teams with no channels, and teams with channels but no messages.

An empty team is either a failed provisioning attempt or a workspace that was never used. Distinguishing "no channels" from "channels but silent" matters: the first is safe to delete, the second may just be seasonal.

Permissions

Requires the application permissions Team.ReadBasic.All, Channel.ReadBasic.All and ChannelMessage.Read.All.

Reference

View source

from __future__ import annotations

import argparse

from office365.graph_client import GraphClient
from tests.settings import client_id, client_secret, tenant


def _has_messages(channels) -> bool:
    """True as soon as any channel holds at least one message."""
    for channel in channels:
        if channel.messages.top(1).get().execute_query():
            return True
    return False


def main():
    parser = argparse.ArgumentParser(description="Find teams with no channels or no messages")
    parser.add_argument("--limit", type=int, default=0, help="scan at most N teams (0 = all)")
    args = parser.parse_args()

    client = GraphClient(tenant=tenant).with_client_secret(client_id, client_secret)
    teams = list(client.teams.get_all().select(["id", "displayName"]).execute_query())
    if args.limit:
        teams = teams[: args.limit]
    print(f"Scanning {len(teams)} team(s)…\n")

    empty = silent = 0
    for team in teams:
        channels = team.channels.get().execute_query()
        if not channels:
            empty += 1
            print(f"  NO CHANNELS  {team.display_name}")
        elif not _has_messages(channels):
            silent += 1
            print(f"  NO MESSAGES  {team.display_name}  ({len(channels)} channel(s))")

    print(f"\nSummary: {empty} team(s) without channels, {silent} silent team(s).")


if __name__ == "__main__":
    main()

← Back to Audit