Automating Azure Entra ID & Office 365 Identity Lifecycle

PowerShellMicrosoft Graph APIAzure Entra ID

Overview

Managing user identities manually in Azure Entra ID and Microsoft 365 is time-consuming, error-prone, and introduces security risks. This project demonstrates how the Joiner–Mover–Leaver (JML) lifecycle can be fully automated using PowerShell with Microsoft Graph REST API.

The solution is designed to be API-first, secure, scalable, and aligned with Microsoft's current best practices.

Why Identity Lifecycle Automation Matters

High-Level Architecture

[User Data / HR Input]
      ↓
[PowerShell Script (Invoke-RestMethod)]
      ↓
[Azure Entra ID App Registration]
      ↓
[Microsoft Graph REST API]
      ↓
[Users • Groups • Licenses • Audit Logs]

Secure Authentication Design (API-First)

This automation uses Azure Entra ID App Registration with application permissions. All actions are non-interactive and fully auditable.

Required Graph Permissions (Application)

Permission Purpose
User.ReadWrite.All Manage users
Group.ReadWrite.All Manage groups and memberships
Directory.Read.All Query directory objects
AuditLog.Read.All Read audit logs
🔒 Admin consent is required for application permissions.

PowerShell Automation – REST API Examples

Authentication – Acquire Token

$TenantId = "<TenantId>"
$ClientId = "<AppRegistrationClientId>"
$ClientSecret = "<ClientSecret>"

$Body = @{
    grant_type    = "client_credentials"
    scope         = "https://graph.microsoft.com/.default"
    client_id     = $ClientId
    client_secret = $ClientSecret
}

$TokenResponse = Invoke-RestMethod -Method Post `
    -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" `
    -Body $Body

$AccessToken = $TokenResponse.access_token
$Headers = @{
    Authorization = "Bearer $AccessToken"
    "Content-Type" = "application/json"
}

Joiner – Create User via REST

$UserBody = @{
    accountEnabled = $true
    displayName    = "John Doe"
    mailNickname   = "johndoe"
    userPrincipalName = "johndoe@domain.com"
    passwordProfile = @{
        forceChangePasswordNextSignIn = $true
        password = "TempP@ssw0rd!"
    }
} | ConvertTo-Json -Depth 4

Invoke-RestMethod -Method Post `
    -Uri "https://graph.microsoft.com/v1.0/users" `
    -Headers $Headers -Body $UserBody

Add User to Group

$GroupId = "<GroupObjectId>"
$UserId  = "<UserId>"

$GroupBody = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$UserId"
} | ConvertTo-Json

Invoke-RestMethod -Method Post `
    -Uri "https://graph.microsoft.com/v1.0/groups/$GroupId/members/`$ref" `
    -Headers $Headers -Body $GroupBody
💡 Licenses are assigned via group-based licensing – users automatically receive licenses when added to groups with assigned licenses.

Mover – Update User on Role Change

# Update user attributes
$UpdateBody = @{
    department = "Engineering"
    jobTitle   = "Senior Engineer"
} | ConvertTo-Json

Invoke-RestMethod -Method Patch `
    -Uri "https://graph.microsoft.com/v1.0/users/$UserId" `
    -Headers $Headers -Body $UpdateBody

# Remove from old group
Invoke-RestMethod -Method Delete `
    -Uri "https://graph.microsoft.com/v1.0/groups/$OldGroupId/members/$UserId/`$ref" `
    -Headers $Headers

# Add to new group
$NewGroupBody = @{
    "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$UserId"
} | ConvertTo-Json

Invoke-RestMethod -Method Post `
    -Uri "https://graph.microsoft.com/v1.0/groups/$NewGroupId/members/`$ref" `
    -Headers $Headers -Body $NewGroupBody

Leaver – Disable User (Offboarding)

# Disable account
$DisableBody = @{
    accountEnabled = $false
} | ConvertTo-Json

Invoke-RestMethod -Method Patch `
    -Uri "https://graph.microsoft.com/v1.0/users/$UserId" `
    -Headers $Headers -Body $DisableBody

# Revoke all sessions
Invoke-RestMethod -Method Post `
    -Uri "https://graph.microsoft.com/v1.0/users/$UserId/revokeSignInSessions" `
    -Headers $Headers

Logging & Auditability

All operations can be logged:

Repository

GitHub: Azure Entra Office 365 Automation

Key Takeaways

Conclusion

This project demonstrates a production-ready, Graph API–first identity lifecycle automation approach using PowerShell REST calls, suitable for enterprise Azure environments. It is fully aligned with security, scalability, and compliance best practices, making it a strong portfolio example.