Skip to main content

Expiring Assignments Detection

Configure early warning for PIM assignments approaching expiration.

What It Does​

PIM Monitor periodically scans for assignments expiring within a configurable window. When found, they're flagged as Medium severity changes in the scan report.

Example:

  • Window: 14 days
  • Current date: 2026-04-27
  • Assignment expires: 2026-05-10 (13 days from now)
  • Result: Flagged as expiring

Configuration​

Set the Expiring Window​

Set EXPIRING_WINDOW_DAYS in your pipeline variables:

Azure DevOps:

  1. Pipelines → PIM Monitor → Edit → Variables
  2. Add: EXPIRING_WINDOW_DAYS = 14

GitHub Actions:

  1. Settings → Secrets and variables → Actions → Variables
  2. Add: EXPIRING_WINDOW_DAYS = 14

Window Values​

WindowUse caseWarning level
7 daysWeekly reviewsAggressive (short notice)
14 daysDefault; bi-weekly planningBalanced
30 daysMonthly batch renewalsConservative (long notice)
90 daysQuarterly planningVery early notice

Default: 14 days (2 weeks)

How Expiring Assignments Work​

Detection Logic​

For each PIM assignment (Directory Roles and PIM Groups):

  1. Check if assignment has expiration date: assignments without an end date are skipped
  2. Compare expiration against today + window: if expiring within window, flag it
  3. Classify as Medium severity: expiring assignments warrant review before they lapse
  4. Include in scan report: listed under Medium changes

Types of Assignments Checked​

  • Directory Roles:

    • Eligible role assignments (expiration date = activation timeout + current policy duration)
    • Active role assignments (expiration date = next review date)
  • PIM Groups:

    • Eligible member/owner assignments
    • Active member/owner assignments

What Gets Reported​

Expiring assignments appear in the scan report as Medium severity changes:

Medium (3)
▼ Directory Roles > Global Administrator > assignments
- Assignment expiring in 13 days (eligible): Jane Doe
- Assignment expiring in 8 days (active): John Smith
▼ PIM Groups > Tier-0-Admins > assignments
- Assignment expiring in 5 days (eligible): Alice Chen

Notification Behavior​

Included in Notifications?​

Expiring assignments are classified as Medium severity, so they are included at the default threshold:

SettingInclude expiring?Example output
HighNoOnly critical changes
MediumYes (default)Security + config changes, including expiring
LowYesAll changes except metadata
InformationalYesAll changes including metadata

Expiring assignment notifications are on by default, so you do not need to change the threshold.

Separate Reports​

Even if notifications are disabled, expiring assignments appear in:

  • inventory/ files (committed to git)
  • HTML scan report (if REPORT_ARTIFACT=true)
  • Pipeline logs

Best Practices​

Window Size Selection​

Too small (7 days): Too many false alarms, insufficient lead time for renewals Optimal (14 days): Enough notice to plan renewals, not too noisy Too large (90 days): Most assignments appear expiring; loses signal-to-noise

Recommendation: Start with 14, adjust based on your renewal SLA.

Combining with Expected Changes​

If you intentionally expire assignments and don't want notifications:

  1. Create expected-changes.json entry:

    {
    "workload": "directory-roles",
    "entity": "global-administrator",
    "fileType": "assignments",
    "reason": "Planned rotation per security review",
    "expiresUtc": "2026-05-10T17:00:00Z"
    }
  2. Set window to 14 days (normal)

  3. Matching expiring assignments won't trigger notifications

  4. Entry auto-deletes after expiration

Regular Review Cycle​

Set up a schedule to review expiring assignments:

Set up a review cadence that matches your renewal SLA. With a 14-day window, a weekly check is enough. With 30 days, monthly is fine.

Customizing Expiration Detection​

Change Assignment Severity​

Edit the Find-ExpiringAssignments function in src/diff.ps1 to change expiring assignments from Medium to a different severity:

Current:

$changes += @{
severity = "Medium"
...
}

Change to:

$changes += @{
severity = "Low" # Or "High" / "Informational"
...
}

Change Detection Window in Code​

The window is controlled by the EXPIRING_WINDOW_DAYS variable at runtime. To hardcode a different default, edit src/Scan-PimState.ps1:

$windowDays = if ([int]::TryParse($env:EXPIRING_WINDOW_DAYS, [ref]$parsed)) {
$parsed
} else {
14 # Default if variable unset
}

Add Additional Criteria​

To skip assignments from certain roles or groups:

Edit Find-ExpiringAssignments in src/diff.ps1:

function Find-ExpiringAssignments {
param($Assignments, $WindowDays)

# Add filter:
if ($slug -match "^(break-glass|emergency)") {
continue # Skip break-glass accounts
}

# ... rest of logic
}

Troubleshooting​

No expiring assignments detected​

Check:

  1. Are there any assignments with expiration dates? Permanent assignments ignored
  2. Are expiration dates actually within the window? Check inventory files
  3. Is window size appropriate? If set to 7 days, only finds assignments expiring within week

Too many expiring assignments reported​

Check:

  1. Is window too large? (90 days captures ~3 months of expirations)
  2. Do policies have short max durations? (e.g., 30-day assignments = 30 updates per month)
  3. Reduce window: EXPIRING_WINDOW_DAYS = 7

Expiring assignments not in notifications​

Check:

  1. Is NOTIFICATION_MIN_SEVERITY set to Medium or lower? (expiring assignments are Medium severity)
  2. Check notifications are enabled (NOTIFICATION_EMAIL or NOTIFICATION_WEBHOOK_URL set)
  3. Review inventory/ files to confirm expiring assignments exist