# User Lifecycle Agent

> Automated user onboarding, offboarding, and mailbox maintenance across any number of Microsoft Entra ID tenants.

## What It Does

| Operation | Description |
|---|---|
| **Onboarding** | Create user → assign license → add to groups → assign enterprise apps → grant SharePoint access |
| **Offboarding** | Disable account → revoke sessions → email forwarding → auto-reply → mailbox delegation → OneDrive transfer → remove groups/apps/licenses |
| **Leave of Absence** | Auto-reply scheduling with optional delegation and optional account disable |
| **Maintenance** | Shared mailbox conversion and delegate access management |

## Architecture

```
GitHub Actions
    |
    v
OIDC Token Exchange (Azure AD)
    |
    v
Per-Tenant App Registration
    |
    v
Microsoft Graph + Exchange Online
```

**Zero secrets.** Uses OIDC federated credentials — no client secrets in GitHub, nothing to rotate.

## Quick Start

```bash
# 1. Configure your tenant
cp config/tenants/example.json config/tenants/my-tenant.json
# Edit with your real Entra ID values

# 2. Install modules
Install-Module Microsoft.Graph -Force -AllowClobber
Install-Module ExchangeOnlineManagement -Force -AllowClobber

# 3. Run a dry-run offboard
pwsh scripts/offboarding/Invoke-FullOffboard.ps1 `
  -TenantAlias "my-tenant" `
  -UserPrincipalName "leavers@company.com" `
  -DelegateUpn "manager@company.com" `
  -AutoReplyMessage "I have left the company. Please contact my manager." `
  -DryRun
```

## Project Structure

```
services/user-lifecycle/
├── scripts/
│   ├── core/
│   │   ├── Connect-Tenant.ps1          # OIDC auth to Graph + Exchange
│   │   ├── Resolve-TenantConfig.ps1    # Load tenant JSON config
│   │   └── Write-AuditLog.ps1          # Structured audit logging
│   ├── onboarding/
│   │   ├── New-UserAccount.ps1         # Create Entra user
│   │   ├── Set-UserLicense.ps1        # Assign M365 license
│   │   ├── Add-UserToGroups.ps1       # Add to security groups
│   │   └── Add-UserToApps.ps1         # Assign enterprise apps
│   ├── offboarding/
│   │   ├── Invoke-FullOffboard.ps1    # Main orchestrator
│   │   ├── Disable-UserAccount.ps1    # Block sign-in
│   │   ├── Revoke-UserSessions.ps1    # Kill active sessions
│   │   ├── Set-EmailForwarding.ps1    # Forward mailbox
│   │   ├── Set-AutoReply.ps1          # Out-of-office
│   │   ├── Set-MailboxDelegation.ps1 # Grant delegate access
│   │   ├── Remove-UserFromGroups.ps1  # Remove from groups
│   │   ├── Remove-UserFromApps.ps1    # Remove app assignments
│   │   ├── Remove-UserLicense.ps1     # Reclaim license
│   │   └── Reset-UserPassword.ps1     # Lock out account
│   └── maintenance/
│       └── Convert-ToSharedMailbox.ps1
├── config/tenants/
│   └── example.json                   # Template — copy and customize
├── modules/
│   ├── catalogs/
│   │   └── equipment-software.json    # Vendor catalog
│   └── role-templates/
│       └── default.json               # Role-based group mappings
└── tests/
    └── Invoke-Pester.ps1
```

## Tenant Configuration

Each tenant is a JSON file in `config/tenants/`:

```json
{
  "alias": "ACME",
  "tenantId": "your-tenant-id",
  "appRegistration": {
    "clientId": "your-app-id"
  },
  "licenses": {
    "defaultSkuPartNumber": "O365_BUSINESS_PREMIUM"
  }
}
```

## Authentication

**OIDC Federated Credentials** (recommended):

```
Issuer:   https://token.actions.githubusercontent.com
Subject:  repo:YOUR_ORG/YOUR_REPO:ref:refs/heads/main
Audience: api://AzureADTokenExchange
```

**Interactive** (local dev):

```powershell
Connect-Tenant.ps1 -TenantAlias "ACME" -Interactive
```

## Audit Logging

Every action is logged to:
- Console (color-coded)
- `logs/audit-YYYY-MM-DD.jsonl` (JSONL format)
- GitHub Actions step summary (if running in Actions)

## Contributing

See [CONTRIBUTING.md](../../CONTRIBUTING.md).
