- Home
- Repositories
- datadog-adfs-integration
datadog-adfs-integration
README documentation for datadog-adfs-integration
Source: ZoosGlobal/datadog-adfs-integration Visibility: Private This page is automatically synchronized from the repository README. Do not edit this generated file directly.
Zoos Global ADFS Monitor
Section titled “Zoos Global ADFS Monitor”
PowerShell → Windows ADFS Server → DogStatsD → Datadog Metrics → Dashboards & Alerts
Monitors SSO certificate expiry across all Relying Party Trusts, ADFS service health,
Windows Internal Database, and service account lockout — via a single lightweight
PowerShell script submitted every 5 minutes to Datadog.
❓ The Problem — Why This Exists
Section titled “❓ The Problem — Why This Exists”Microsoft Active Directory Federation Services (ADFS) underpins Single Sign-On (SSO) access to business-critical applications, cloud services, and federated identity providers — but its health was scattered across Windows Services, IIS, Active Directory, certificates, and event logs with no centralized way to monitor it:
- No unified visibility — ADFS health depends on multiple independent subsystems (the
adfssrvservice, IIS application pools, Windows Internal Database, AD service accounts, and a web of federation trust certificates), and none of these were monitored together in one place. - Certificate expiry is a silent, high-impact failure mode — Token-signing, token-decrypting, service communication, and SSL/HTTPS binding certificates — plus every Relying Party Trust’s own encryption and request-signing certificates — can expire without warning, breaking authentication for every application relying on that trust the moment it happens.
- Service account lockouts halt token issuance instantly — A locked, disabled, or expired-password service account can stop ADFS from issuing tokens fleet-wide, but without active monitoring this was only discovered after authentication started failing.
- Dependency failures are easy to miss — IIS ADFSAppPool crashes or Windows Internal Database outages can quietly disrupt authentication without an obvious top-level signal pointing back to the root cause.
- Reactive, not proactive, troubleshooting — Without consolidated monitoring, authentication incidents were typically discovered only after users started reporting login failures — by which point the business impact had already occurred.
- Scale of the trust relationships involved — With 100+ certificate objects across dozens of Relying Party and Claims Provider Trusts, manually tracking expiry dates and trust health was operationally infeasible.
✅ The Solution — What We Built
Section titled “✅ The Solution — What We Built”We built a lightweight, self-contained PowerShell monitoring framework that runs directly on the ADFS server and submits service health, certificate, trust, and account security metrics to Datadog via DogStatsD every 5 minutes — giving identity, infrastructure, and security teams a single pane of glass over the entire ADFS ecosystem.
Architecture
Section titled “Architecture”ADFS Server (adfssrv, IIS, WID, AD, certificate stores, RPTs/CPTs) ↓ Invoke-ADFSMonitor.ps1 (runs every 5 minutes) ↓ DogStatsD (UDP 127.0.0.1:8125) ↓ Datadog Agent ↓ Datadog Metrics (adfs.service.*, adfs.cert.scan.*, adfs.rpt.*, adfs.cpt.*, adfs.account.*) ↓ Dashboards & MonitorsKey Design Decisions
Section titled “Key Design Decisions”| Decision | Rationale |
|---|---|
| Single script covering service, certs, trusts, and accounts | ADFS health is multi-dimensional by nature; consolidating all KPIs into one collector gives one consistent execution cadence and one place to maintain monitoring logic |
| DogStatsD over UDP, not a custom Agent check | Keeps the integration entirely self-contained in a single PowerShell script — no separate check package to build, version, or deploy |
| Full certificate scan across every cert type and trust | Token-signing, token-decrypting, service-communication, HTTPS binding, and every Relying Party/Claims Provider Trust’s encryption and request-signing certs are scanned in one pass, so no certificate category is left blind |
| Per-cert tagging instead of one metric per cert | trust_name, cert_label, cert_status, thumbprint, and expiry_date are carried as tags on a small set of metrics, keeping custom-metric cardinality manageable even with 100+ certs in scope |
Dedicated summary counters (expired_count, critical_count, warning_count) |
Gives an at-a-glance fleet-wide certificate health number, separate from the per-cert detail used for drill-down |
| AD service account lockout detection with event-source tracing | Surfaces not just that an account is locked, but contributing signals (bad logon count, password age) and the lockout event source, so the root cause can be chased down immediately |
Graceful skip on missing dependencies (-1 values) |
Backend ADFS nodes without IIS, or deployments using SQL Server instead of WID, report -1 rather than a false failure — avoiding noisy, incorrect alerts |
One-click setup.ps1 with dry-run validation |
Installs prerequisites, validates the Datadog Agent and ADFS service, runs a dry-run before sending live data, and registers the 5-minute scheduled task — turning a multi-step setup into a single guided run |
| Pre-built monitors for the highest-impact failure modes | Service down, certificate expiry (warning/critical), account lockout, bad logon spikes, and password age are all alertable out of the box, not left for someone to configure later |
Outcome
Section titled “Outcome”- ADFS service health, certificate lifecycle, trust inventory, and service account security are all visible in Datadog as a single, correlated view — no more switching between Windows Services, IIS Manager, AD Users & Computers, and the certificate store.
- Certificate expiry — previously discovered only after authentication broke — is now flagged 30 days and 14 days out, giving teams time to renew before impact.
- Service account lockouts trigger an immediate alert instead of being discovered through a wave of failed logins.
- The entire integration runs on the existing ADFS server with no new infrastructure, completing a full health/cert/account scan every 5 minutes (288 runs/day).
📁 Directory Structure
Section titled “📁 Directory Structure”C:\Scripts\ADFSMonitor\└── Invoke-ADFSMonitor.ps1 # Main metric collection & DogStatsD submission script
setup.ps1 # One-click setup: copies script + creates scheduled taskREADME.md # This file📊 Metrics Reference
Section titled “📊 Metrics Reference”adfs.service.* — ADFS Service Health
Section titled “adfs.service.* — ADFS Service Health”Tags:
env,role:adfs-server,host
| Metric | Description |
|---|---|
adfs.service.is_running |
ADFS service running status 1=up 0=down |
adfs.service.start_auto |
StartType is Automatic 1=yes 0=no |
adfs.service.uptime_hours |
Hours since adfssrv last started |
adfs.service.wid_running |
Windows Internal Database running 1=up 0=down -1=N/A |
adfs.service.apppool_running |
IIS ADFSAppPool running 1=up 0=down -1=N/A |
adfs.cert.scan.* — Certificate Scan
Section titled “adfs.cert.scan.* — Certificate Scan”Tags:
trust_name,trust_type,cert_label,cert_status,thumbprint,subject_cn,issuer_cn,expiry_date
| Metric | Description |
|---|---|
adfs.cert.scan.days_remaining |
Days until expiry — negative = already expired 🔴 |
adfs.cert.scan.expiry_epoch |
Expiry as Unix epoch timestamp |
adfs.cert.scan.is_valid |
Certificate valid flag 1=valid 0=expired |
adfs.cert.scan.total_count |
Total cert objects scanned per run |
adfs.cert.scan.expired_count |
Total expired certs right now 🔴 |
adfs.cert.scan.critical_count |
Certs expiring within 14 days ⚠️ |
adfs.cert.scan.warning_count |
Certs expiring within 30 days ⚠️ |
adfs.cert.auto_rollover_enabled |
Auto certificate rollover enabled 1=yes 0=no |
cert_label values:
| Label | Source |
|---|---|
token-signing |
ADFS token-signing certificate |
token-decrypting |
ADFS token-decrypting certificate |
service-communications |
ADFS service communication certificate |
https-binding |
SSL certificate on ADFS HTTPS binding |
encryption |
Relying Party Trust encryption certificate |
request-signing |
Relying Party Trust request-signing certificate |
adfs.rpt.* — Relying Party Trusts
Section titled “adfs.rpt.* — Relying Party Trusts”Tags:
env,role,host,rpt_name
| Metric | Description |
|---|---|
adfs.rpt.total_count |
Total Relying Party Trusts configured |
adfs.rpt.is_enabled |
RPT enabled flag per trust 1=enabled 0=disabled |
adfs.cpt.* — Claims Provider Trusts
Section titled “adfs.cpt.* — Claims Provider Trusts”| Metric | Description |
|---|---|
adfs.cpt.total_count |
Total Claims Provider Trusts configured |
adfs.account.* — Service Account Lockout
Section titled “adfs.account.* — Service Account Lockout”Tags:
env,role,host,account
| Metric | Description |
|---|---|
adfs.account.is_locked |
Account locked status 1=locked 0=ok 🔴 |
adfs.account.is_enabled |
Account enabled status 1=enabled 0=disabled |
adfs.account.bad_logon_count |
Bad logon attempts — high = stale credentials ⚠️ |
adfs.account.password_age_days |
Days since password was last changed |
adfs.account.password_expired |
Password expired flag 1=expired 0=ok |
adfs.account.lockout_event |
Lockout event detected 1=lockout found (with source tag) |
⚙️ System Requirements
Section titled “⚙️ System Requirements”| Requirement | Version |
|---|---|
| Windows Server | 2016 / 2019 / 2022 / 2025 |
| ADFS Role | Installed & Running (adfssrv) |
| Datadog Agent | v7+ (DogStatsD on 127.0.0.1:8125) |
| PowerShell | 5.1+ |
| RSAT — AD Module | For account lockout metrics |
| Privileges | Administrator / SYSTEM |
1️⃣ Install Datadog Agent
Section titled “1️⃣ Install Datadog Agent”# Download installerInvoke-WebRequest ` -Uri "https://s3.amazonaws.com/ddagent-windows-stable/datadog-agent-7-latest.amd64.msi" ` -OutFile "C:\ddagent.msi"
# Install with your API keyStart-Process -Wait msiexec ` -ArgumentList '/qn /i C:\ddagent.msi APIKEY="<your_api_key>"'Verify Agent is running:
Get-Service -Name "datadogagent"# Expected: Status = RunningVerify DogStatsD is listening:
netstat -an | findstr 8125# Expected: UDP 127.0.0.1:8125 *:*2️⃣ One-Click Setup (Recommended)
Section titled “2️⃣ One-Click Setup (Recommended)”Run as Administrator from the folder containing both files.
PowerShell.exe -ExecutionPolicy Bypass -File .\setup.ps1With custom parameters:
# Custom service account and intervalPowerShell.exe -ExecutionPolicy Bypass -File .\setup.ps1 ` -Account "YourServiceAccount" ` -Interval 5
# Custom DogStatsD hostPowerShell.exe -ExecutionPolicy Bypass -File .\setup.ps1 ` -DDHost "10.0.0.1" ` -DDPort 8125setup.ps1 performs 10 steps automatically:
[1/10] Validate Datadog Agent is running[2/10] Verify DogStatsD on UDP :8125[3/10] Validate ADFS service (adfssrv)[4/10] Validate ActiveDirectory RSAT module[5/10] Create C:\Scripts\ADFSMonitor directory[6/10] Copy Invoke-ADFSMonitor.ps1 to destination[7/10] Unblock scripts (remove Zone.Identifier)[8/10] Dry-run validation (no metrics sent)[9/10] Live run — push metrics to Datadog now[10/10] Create Windows Scheduled Task (every 5 min, SYSTEM)3️⃣ Manual Validation
Section titled “3️⃣ Manual Validation”Always test manually before scheduling.
# Dry run — prints metrics without sendingPowerShell.exe -ExecutionPolicy Bypass -File ` "C:\Scripts\ADFSMonitor\Invoke-ADFSMonitor.ps1" -DryRun
# Live run — sends metrics to DatadogPowerShell.exe -ExecutionPolicy Bypass -File ` "C:\Scripts\ADFSMonitor\Invoke-ADFSMonitor.ps1" ` -Account "EXLAdminsvc"Expected output:
╔══════════════════════════════════════════════════════════╗║ KPI 0 — ADFS Service Health ║╚══════════════════════════════════════════════════════════╝ adfssrv Status : Running adfssrv StartType : Automatic adfssrv Uptime : 239h (since 2026-04-04 17:17) WID (ADFS DB) : Running
╔══════════════════════════════════════════════════════════╗║ KPI 1 — Full ADFS Certificate Scan ║╚══════════════════════════════════════════════════════════╝ [server] [ADFS-Server] [token-signing ] 345d OK exp:2027-03-25 [ssl ] [ADFS-SSL ] [https-binding ] 184d OK exp:2026-10-16 [rpt ] [Druva-Phoenix] [request-signing ] -2887d EXPIRED exp:2018-05-20 ... │ Total certs scanned : 101 │ │ Expired : 33 │ │ Critical (< 14 days): 0 │ │ Warning (< 30 days): 0 │
╔══════════════════════════════════════════════════════════╗║ KPI 2 — Service Account Lockout ║╚══════════════════════════════════════════════════════════╝ Locked : False Enabled : True Bad Logons : 1 Password Age : 324d Pwd Expired : False
Done.Verify in Datadog:
Metrics → Explorer → search adfs.service.is_running
4️⃣ Windows Task Scheduler (Manual)
Section titled “4️⃣ Windows Task Scheduler (Manual)”Click to expand — PowerShell method
$action = New-ScheduledTaskAction ` -Execute 'PowerShell.exe' ` -Argument '-NonInteractive -ExecutionPolicy Bypass -File "C:\Scripts\ADFSMonitor\Invoke-ADFSMonitor.ps1" -Account "EXLAdminsvc"'
$trigger = New-ScheduledTaskTrigger ` -Once ` -At (Get-Date) ` -RepetitionInterval (New-TimeSpan -Minutes 5) ` -RepetitionDuration (New-TimeSpan -Days 3650)
$settings = New-ScheduledTaskSettingsSet ` -ExecutionTimeLimit (New-TimeSpan -Minutes 4) ` -MultipleInstances IgnoreNew ` -StartWhenAvailable
$principal = New-ScheduledTaskPrincipal ` -UserId 'NT AUTHORITY\SYSTEM' ` -RunLevel Highest ` -LogonType ServiceAccount
Register-ScheduledTask ` -TaskName 'ZoosGlobal-ADFS-Monitor' ` -Action $action ` -Trigger $trigger ` -Settings $settings ` -Principal $principal ` -Force5️⃣ Execution Timeline
Section titled “5️⃣ Execution Timeline”00:00 → Invoke-ADFSMonitor.ps1 runs ├── KPI 0 — Service Health │ ├── adfssrv status + uptime → 3 metrics │ ├── WID database status → 1 metric │ └── IIS ADFSAppPool status → 1 metric │ ├── KPI 1 — Certificate Scan │ ├── ADFS server certs (3 certs) → 9 metrics │ ├── SSL / HTTPS cert → 3 metrics │ ├── All RPT certs (139 trusts) → ~270 metrics │ └── Summary counters → 4 metrics │ └── KPI 2 — Account Lockout └── EXLAdminsvc AD check → 5 metrics
00:05 → Repeats00:10 → Repeats...288 runs/day6️⃣ Pre-built Datadog Monitors
Section titled “6️⃣ Pre-built Datadog Monitors”🔴 Service Down — Immediate Alert
Section titled “🔴 Service Down — Immediate Alert”Query : max(last_2m):max:adfs.service.is_running{*} by {host} < 1Alert : < 1Message : 🔴 adfssrv is DOWN on {{host.name}} — SSO logins will FAIL immediately.⚠️ Certificate Expiry — Warning / Critical
Section titled “⚠️ Certificate Expiry — Warning / Critical”Query : min(last_5m):min:adfs.cert.scan.days_remaining{*} by {trust_name,cert_label,expiry_date,host} < 30Warning : < 30 daysCritical : < 14 daysMessage : ⚠️ Cert expiring: {{trust_name.name}} / {{cert_label.name}} — {{value}} days left (exp: {{expiry_date.name}})🔴 Account Locked — Immediate Alert
Section titled “🔴 Account Locked — Immediate Alert”Query : max(last_1m):max:adfs.account.is_locked{*} by {account,host} > 0Alert : > 0Message : 🔴 Service account {{account.name}} is LOCKED on {{host.name}} — token issuance will fail.⚠️ Bad Logon Spike — Warning
Section titled “⚠️ Bad Logon Spike — Warning”Query : max(last_5m):max:adfs.account.bad_logon_count{*} by {account,host} > 10Alert : > 10Message : ⚠️ High bad logon count on {{account.name}} — check for stale credentials in scheduled tasks or services.⚠️ Password Age — Warning
Section titled “⚠️ Password Age — Warning”Query : max(last_1h):max:adfs.account.password_age_days{*} by {account} > 90Alert : > 90 daysMessage : ⚠️ Service account {{account.name}} password is {{value}} days old — rotation recommended.7️⃣ Datadog Dashboard Queries
Section titled “7️⃣ Datadog Dashboard Queries”| Widget | Query |
|---|---|
| ADFS service up/down | avg:adfs.service.is_running{*} by {host} |
| Service uptime (hours) | avg:adfs.service.uptime_hours{*} by {host} |
| Total expired certs | avg:adfs.cert.scan.expired_count{*} |
| Total certs scanned | avg:adfs.cert.scan.total_count{*} |
| Days remaining per cert | min:adfs.cert.scan.days_remaining{*} by {trust_name,cert_label} |
| Expired certs table | min:adfs.cert.scan.days_remaining{cert_status:expired} by {trust_name,cert_label,expiry_date} |
| RPT total count | avg:adfs.rpt.total_count{*} |
| Account locked | max:adfs.account.is_locked{*} by {account} |
| Bad logon count | max:adfs.account.bad_logon_count{*} by {account} |
| Password age (days) | max:adfs.account.password_age_days{*} by {account} |
🛡️ Production Features
Section titled “🛡️ Production Features”| Feature | Status |
|---|---|
| ADFS server cert scan (token-signing, token-decrypting, service-comms) | ✅ |
| SSL / HTTPS binding cert scan | ✅ |
| Full Relying Party Trust cert scan (encryption + request-signing) | ✅ |
| Claims Provider Trust cert scan | ✅ |
| Auto certificate rollover status | ✅ |
| Per-cert tags (trust_name, label, status, thumbprint, expiry_date) | ✅ |
| ADFS service uptime via WMI Win32_Process | ✅ |
| Windows Internal Database (WID) check | ✅ |
| IIS ADFSAppPool check | ✅ |
| AD service account lockout detection | ✅ |
| Event ID 4740 lockout source tracing | ✅ |
| Bad logon count + password age tracking | ✅ |
Dry-run mode (-DryRun) |
✅ |
| SYSTEM scheduler compatible | ✅ |
| DogStatsD UDP submission | ✅ |
| Graceful skip when ADFS / AD unavailable | ✅ |
✅ Production Checklist
Section titled “✅ Production Checklist”- Datadog Agent installed and running
- DogStatsD listening on
127.0.0.1:8125 -
setup.ps1run as Administrator - Dry-run output validated
- Live metrics visible in Datadog Metrics Explorer
-
adfs.service.is_running=1 -
adfs.cert.scan.expired_countvalue reviewed with team -
adfs.account.is_locked=0 - Scheduled Task
ZoosGlobal-ADFS-Monitorcreated and running - Monitor created for service down
- Monitor created for cert expiry
- Monitor created for account lockout
🚨 Troubleshooting
Section titled “🚨 Troubleshooting”| Issue | Fix |
|---|---|
| Metrics not appearing in Datadog | Run netstat -an | findstr 8125 — verify DogStatsD is listening |
[SKIP] Cert scan failed |
Confirm adfssrv is running and user is ADFS Admin |
[SKIP] AD unavailable |
Install RSAT: Add-WindowsFeature RSAT-AD-PowerShell |
ADFSAppPool showing -1 |
IIS not on this ADFS server — expected for backend nodes |
WID showing -1 |
ADFS is using SQL Server backend — expected |
| Same cert scanned twice | RPT has both singular and plural signing cert properties — both scanned by design |
ExecutionPolicy error |
Run: Set-ExecutionPolicy -Scope LocalMachine RemoteSigned |
| Scheduled task not running | Check: schtasks /query /tn "ZoosGlobal-ADFS-Monitor" /fo LIST /v |
👤 Author
Section titled “👤 Author”| Name | Shivam Anand |
| Title | Sr. DevOps Engineer | Engineering |
| Organisation | Zoos Global |
| [email protected] | |
| Web | www.zoosglobal.com |
| Address | Violena, Pali Hill, Bandra West, Mumbai - 400050 |
Version 1.0.0 · Last Updated: April 14, 2026
© 2026 Zoos Global · MIT License
Zoos Global is a Datadog Premium Partner

