Managing guest users in Entra ID can quickly become a compliance headache. Stale accounts, forgotten access, and manual cleanup are a recipe for risk. But what if you could automate the entire lifecycle — from detection to deletion — without shelling out for premium identity governance licenses?
That’s exactly what this solution delivers: a lightweight, scalable guest user lifecycle management system built entirely with Azure Logic Apps, Managed Identity, and the Microsoft Graph API.
🧩 Architecture Overview
This setup uses two independent Logic Apps, each with a clear purpose:
- Mark inactive guests for removal
- Delete marked guests after a grace period
Each app runs on a weekly schedule, emits detailed JSON reports, and supports a report-only mode for safe testing.
💤 Logic App 1 — Mark Guests Eligible for Removal
This app identifies inactive guest users based on sign-in activity and marks them for removal.
⏱️ Schedule: Weekly (e.g., Sunday 01:00)
🔍 Evaluation:
- Checks all members of a dynamic group (
All Guests) - Flags users who never signed in or haven’t signed in for a configurable number of days
🏷️ Actions:
- Sets
extensionAttribute14 = "MarkedEligibleforRemoval" - Sets
extensionAttribute15 = <UTC timestamp> - Disables the account if
ReportOnly = false
📤 Output:
- JSON report with evaluated, marked, and disabled users
⚙️ Parameters:
Threshold: Days since last sign-in (default: 180)ReportOnly: true/falseBatchSize: Users per run (default: 20)
🧹 Logic App 2 — Delete Guests After Grace Period
This app deletes guest users who were previously marked and have exceeded the grace period.
⏱️ Schedule: Weekly (e.g., Sunday 03:00)
🔍 Evaluation:
- Checks members of the
Eligible For Removalgroup - Deletes users if:
extensionAttribute14 = "MarkedEligibleforRemoval"extensionAttribute15is older than the deletion thresholdaccountEnabled = false
🗑️ Action:
- Deletes user when
ReportOnly = false
📤 Output:
- JSON report with evaluated, deleted, and failed users
⚙️ Parameters:
DeletionThresholdDays: Days since marking (default: 30)ReportOnly: true/falseBatchSize: Users per run (default: 20)
👥 Dynamic Group Setup
Two dynamic security groups help scope and monitor the lifecycle:
- All Guests
(user.userType -eq "Guest") and (user.extensionAttribute15 -ne "ExcludeFromLCM") and (user.accountEnabled -eq true) - Eligible For Removal
(user.extensionAttribute14 -eq "MarkedEligibleforRemoval") and (user.accountEnabled -eq false)
💡 Exclude VIPs or service accounts by setting extensionAttribute15 = "ExcludeFromLCM"
🔐 Prerequisites
- Azure subscription with Logic App deployment permissions
- Entra ID tenant with guest users
- Two free extension attributes (e.g., 14 & 15)
- Microsoft Graph API permissions for:
- Sign-in logs (
AuditLog.Read.All) - User read/write (
User.ReadWrite.All) - Group read (
Group.Read.All)
- Sign-in logs (
🆔 Enable System-assigned Managed Identity for each Logic App
📦 Deployment & Templates
Ready to roll this out in your tenant?
The full solution — including templates, CLI scripts, and setup instructions — is available on Github.
Just import, configure, and automate.
🧪 Testing & Verification
Start with ReportOnly = true to validate logic and outputs.
Check group memberships and run outputs to confirm correct behavior.
Once verified, switch to ReportOnly = false to activate lifecycle actions.
📊 Auditable Reports
Each Logic App emits a structured JSON report for every run.
Example (Mark app):
{
"totalEvaluated": 120,
"totalMarked": 18,
"totalDisabled": 18,
"details": [
{
"userPrincipalName": "guest1@contoso.com",
"reason": "No sign-in activity in the last 180 days"
}
]
}
Example (Delete app):
{
"totalEvaluated": 42,
"totalDeleted": 12,
"totalFailed": 0,
"details": [
{
"userPrincipalName": "guest1@contoso.com",
"markedOn": "2025-01-01T00:00:00Z",
"action": "Deleted"
}
]
}
🛡️ Safety Tips
- Always start in report-only mode
- Exclude critical guests with
ExcludeFromLCM - Monitor Graph API throttling
- Export reports to Storage or Log Analytics for auditing
- Restrict Logic App modification permissions
🧰 Troubleshooting
❓ No users marked?
- Check group membership and sign-in data
- Validate Graph permissions
🗂️ Users not deleted?
- Confirm attribute values and timestamps
- Ensure
accountEnabled = false
🔑 Permission errors?
- Re-run CLI scripts with correct Managed Identity ID
- Verify Graph App Role assignments
✨ Final Thoughts
This solution brings clarity, control, and compliance to guest user lifecycle management — all without premium licensing. Whether you’re cleaning up stale accounts or enforcing tighter access hygiene, this setup gives you the tools to do it safely, scalably, and audibly.
Ready to automate your guest cleanup? You’re just two Logic Apps away.


Leave a Reply