Keep Your Microsoft 365 E5 Developer Tenant Active Automatically
📖 Original Reference: Originally published with security architecture baselines at alexmaina.dev/m365-developer-rinnovo-automatico.
The Microsoft 365 Developer Program provides a free 25-user E5 enterprise sandbox subscription (worth over $1,300/year). However, it comes with a strict condition: it expires every 90 days unless Microsoft detects continuous developer activity.
If your sandbox goes idle, Microsoft terminates the tenant, permanently erasing your users, mailboxes, and configurations. Here is an automated, serverless solution using Microsoft Graph API and GitHub Actions to generate valid developer telemetry and maintain your tenant indefinitely.
1. Register a Daemon App in Microsoft Entra ID
- Sign into the Microsoft Entra Admin Center as tenant admin.
- Go to Identity → Applications → App registrations → New registration.
- Name it
M365-KeepAlive-Automation(Accounts in this organizational directory only). - Save the Application (client) ID and Directory (tenant) ID.
- Under Certificates & secrets, create a new client secret (24-month validity) and copy its value.
- Under API permissions → Add permission → Microsoft Graph → Application permissions, select:
User.Read.AllCalendars.ReadWriteDirectory.Read.All
- Click Grant admin consent for [Your Tenant].
2. Python Telemetry Script (keepalive.py)
Create keepalive.py in a private GitHub repository:
import os
import requests
from datetime import datetime, timedelta
TENANT_ID = os.environ["M365_TENANT_ID"]
CLIENT_ID = os.environ["M365_CLIENT_ID"]
CLIENT_SECRET = os.environ["M365_CLIENT_SECRET"]
# 1. Acquire OAuth2 Token via Client Credentials Flow
token_url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token"
token_data = {
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "https://graph.microsoft.com/.default"
}
res = requests.post(token_url, data=token_data)
res.raise_for_status()
access_token = res.json()["access_token"]
headers = {"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"}
print("✅ Microsoft Graph token successfully acquired.")
# 2. Query tenant user directory
users_res = requests.get("https://graph.microsoft.com/v1.0/users?$top=5", headers=headers)
users = users_res.json().get("value", [])
print(f"📡 Found {len(users)} users in tenant.")
# 3. Create simulated developer calendar event
if users:
target_user_id = users[0]["id"]
now = datetime.utcnow()
event_payload = {
"subject": f"Dev Sprint Sync - {now.strftime('%Y-%m-%d %H:%M')}",
"body": {"contentType": "HTML", "content": "Automated Graph API Developer Telemetry."},
"start": {"dateTime": (now + timedelta(hours=1)).isoformat(), "timeZone": "UTC"},
"end": {"dateTime": (now + timedelta(hours=2)).isoformat(), "timeZone": "UTC"}
}
event_res = requests.post(
f"https://graph.microsoft.com/v1.0/users/{target_user_id}/events",
headers=headers, json=event_payload
)
if event_res.status_code == 201:
print("📅 Developer telemetry event created in calendar.")
3. GitHub Actions Cron Workflow
In .github/workflows/keepalive.yml:
name: M365 E5 KeepAlive Automation
on:
schedule:
# Runs Monday, Wednesday, Friday at 08:30 UTC
- cron: '30 8 * * 1,3,5'
workflow_dispatch:
jobs:
telemetry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install requests
- name: Run Graph Telemetry
env:
M365_TENANT_ID: ${{ secrets.M365_TENANT_ID }}
M365_CLIENT_ID: ${{ secrets.M365_CLIENT_ID }}
M365_CLIENT_SECRET: ${{ secrets.M365_CLIENT_SECRET }}
run: python keepalive.py
Store M365_TENANT_ID, M365_CLIENT_ID, and M365_CLIENT_SECRET under Repository Settings → Secrets and variables → Actions.
Author: Alessandro Mainardi - Software Developer & Computer Engineering Student @ UniBo. Explore cloud identity guides at alexmaina.dev.
Comments
No comments yet. Start the discussion.