Active Directory Objects

How to detect stale/orphaned service accounts

Detecting stale or orphaned service accounts: a modern playbook for AD & Entra

Service accounts are the quietest identities in your estate—and the most dangerous when forgotten. They run backups, talk to databases, deploy code, and glue systems together. When those identities become stale (unused) or orphaned (no clear owner), you inherit invisible risk: standing permissions with no sponsor, credentials that never rotate, and endpoints that still trust them by habit. That is precisely the attack surface modern adversaries love.

Offense keeps getting easier: credential dumps, basic auth fallbacks, and evergreen Kerberos paths mean an old account can still open a lot of doors. Defense must be faster and more disciplined. The goal of this guide is to help you build a repeatable detection pipeline that finds, proves, and retires these identities without causing outages.

What people mean by stale and orphaned—and why that isn’t enough

Definitions you can use in policy and audits:

  • Stale service account: an enabled non-human identity with no recent legitimate usage within a defined window (for example, 90–180 days depending on workload cadence).
  • Orphaned service account: an identity with no accountable owner (person or team) on record.
  • Zombie identity: credentials still accepted by something, despite no declared need or recorded ownership.

These states overlap but are not identical. A service account may appear inactive in the directory yet still be used by a third-party system via cached tickets. Conversely, it may have recent sign-ins but nobody who will vouch for its continued existence. Your detection model must evaluate both usage and ownership, not just one.

A common anti-pattern is to pick a 30-day inactivity window and purge. That misses workloads with monthly, quarterly, or seasonal cadence. It also ignores ownerlessness, expiring secrets, and unmanaged SPNs—three drivers of breach risk that often hide behind “looks quiet.”

First principles: four axes of service identity health

Every non-human identity can be evaluated across four irreducible facets. If any facet is missing or stale, risk increases sharply:

  1. Owner: a person or team that attests the identity is needed now.
  2. Purpose: a plain-English description you can read back: “Runs SQL Agent jobs for the data warehouse nightly.”
  3. Path: where the credential is accepted—SPNs, app registrations, scopes, roles, and trust paths.
  4. Proof: objective recent activity tied to that path—sign-ins, tickets, API calls, and process logs.

Design your detection pipeline to score each account across these axes. “Inactive” is only one axis (proof). Ownerless is primarily the owner axis. High-privilege with broad delegation strikes the path axis. A password last set five years ago with DONT_EXPIRE_PASSWORD is a hygiene smell that cuts across all four.

Two consequences fall out of these principles:

  • Managed beats managed-by-hand. Group Managed Service Accounts (gMSA) eliminate human-managed passwords and standardize SPN lifecycle. Where gMSA is feasible, drift and detection complexity both fall.
  • Telemetry must match the plane. AD logons, Entra service principal sign-ins, and application telemetry are different planes. Align your evidence to the plane where the identity actually authenticates.

Practical primers you may find helpful as you apply these principles:

The hands-on core: build a detection pipeline you can run this week

This section is the technical “hero” content: step-by-step, copy-pastable building blocks for a robust stale/orphaned service account program across AD and Microsoft Entra. Adapt names and thresholds to your environment.

```

1) Build a trustworthy inventory in Active Directory

Heuristics that reliably surface service accounts:

  • User objects with one or more SPNs (servicePrincipalName attribute).
  • Accounts configured to run Windows services, IIS app pools, tasks, or agents.
  • userAccountControl flags: DONT_EXPIRE_PASSWORD, PASSWORD_NOT_REQUIRED, TRUSTED_FOR_DELEGATION, ACCOUNTDISABLE.
  • Explicit gMSA objects (msDS-ManagedServiceAccount class).
  • Naming conventions (svc_, sa_) and OU placement.
# Likely service accounts by SPN or password policy hints
```

Get-ADUser -LDAPFilter "(&(objectClass=user)(|(servicePrincipalName=*))(userAccountControl:1.2.840.113556.1.4.803:=65536))" `
-Properties servicePrincipalName, userAccountControl, lastLogonTimestamp, pwdLastSet, whenCreated, memberOf |
Select-Object SamAccountName, Enabled,
@{n='HasSPN';e={([bool]($_.servicePrincipalName))}},
@{n='PwdNeverExpires';e={($*.userAccountControl -band 0x10000) -ne 0}},
@{n='LastLogonTS';e={$*.lastLogonTimestamp}},
@{n='PwdLastSet';e={$_.pwdLastSet}},
whenCreated, memberOf

# All SPN-bearing principals (users & computers)

Get-ADObject -LDAPFilter "(servicePrincipalName=*)" -Properties servicePrincipalName |
Select-Object Name, ObjectClass, servicePrincipalName

# All gMSA objects

Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword,ServicePrincipalNames

Tip: lastLogonTimestamp is replicated and updates coarsely; use it for staleness screening, not precise forensics. For precision, aggregate per-DC lastLogon or rely on KDC logs and SIEM evidence.

```

2) Attach owners—and expose the ownerless

Every service identity should have a current owner and purpose. If your directory lacks a dedicated attribute for ownership, start simple: use managedBy or a dedicated mail field pointing to an accountable distribution list. Anything enabled without an owner is high risk by default.

$svc = Get-ADUser -LDAPFilter "(&(objectClass=user)(servicePrincipalName=*))" -Properties mail,description,managedBy
```

$ownerless = $svc | Where-Object { -not $*.managedBy -and -not $*.mail -and $_.Enabled }
$ownerless | Select SamAccountName,Description | Export-Csv .\ownerless-service-accounts.csv -NoType

Run a lightweight access-certification round with application owners using this export. If nobody claims an identity, move it to a decommissioning queue with a staged disable and observation window.

```

3) Prove recent activity on the AD plane

Don’t rely on logon timestamps alone. Cross-check multiple signals:

  • KDC issuance of tickets to the account.
  • Server event logs where the service should run (Service Control Manager, application logs).
  • Network telemetry for SPN-targeted connections.
  • SIEM queries (for example, Windows Security 4624 logons by the account).
# 90 days stale by replicated lastLogonTimestamp
```

$days = 90
Search-ADAccount -UsersOnly -AccountInactive -TimeSpan "$days.00:00:00" |
Where-Object { $*.Enabled -and $*.servicePrincipalName } |
Select-Object Name,SamAccountName,LastLogonDate |
Export-Csv .\suspect-stale-service-accounts.csv -NoType
```

4) Prove recent activity on the Entra plane (service principals)

For Microsoft Entra service principals and app registrations, track four things: sign-in activity, credential expiry, ownership, and “unused app” signals. Export audit data to your SIEM; tenant retention may be short for service principal sign-ins.

# Requires: Install-Module Microsoft.Graph -Scope CurrentUser
```

Import-Module Microsoft.Graph -MinimumVersion 2.0
Connect-MgGraph -Scopes "AuditLog.Read.All","Application.Read.All","Policy.Read.All","Directory.Read.All"

# Ownerless service principals

$allSp = Get-MgServicePrincipal -All
$ownerless = foreach ($sp in $allSp) {
$owners = Get-MgServicePrincipalOwner -ServicePrincipalId $sp.Id -ErrorAction SilentlyContinue
if (-not $owners) { $sp }
}
$ownerless | Select DisplayName, AppId, Id | Export-Csv .\ownerless-serviceprincipals.csv -NoType

# Expiring secrets/certs in next 30 days

$soon = (Get-Date).AddDays(30)
$expiring = $allSp | ForEach-Object {
$*.PasswordCredentials + $*.KeyCredentials |
Where-Object { $*.EndDateTime -and $*.EndDateTime -lt $soon } |
Select-Object @{n='ServicePrincipal';e={$*.AdditionalProperties['displayName']}},
@{n='ObjectId';e={$*.AdditionalProperties['id']}},
EndDateTime
}
$expiring | Export-Csv .\expiring-sp-credentials.csv -NoType

# Recent sign-ins by appId (last 30 days)

$appId = ""
Get-MgAuditLogSignIn -Filter "appId eq '$appId'" -All |
Sort-Object CreatedDateTime -Descending |
Select-Object AppDisplayName, CreatedDateTime, IPAddress, ResourceDisplayName |
Export-Csv .\sp-signins-$appId.csv -NoType
```

5) Prefer gMSA where possible, document exceptions

If a Windows service, IIS app pool, or scheduled task can run under gMSA, switch it. Password rotation becomes automatic, SPN management simplifies, and your detection code shrinks. Keep a register of approved exceptions with justification and review them quarterly.

Helpful primer: configure gMSA for Defender for Identity.

6) Compute a risk score and triage queue

Not all stale accounts are equal. Compute a weighted score and sort descending. Suggested dimensions:

  • Privilege: domain or local admin, high-impact roles, sensitive group membership.
  • Delegation: unconstrained or broad constrained delegation; presence of sensitive SPNs.
  • Password posture: DONT_EXPIRE_PASSWORD set; pwdLastSet older than one year.
  • Usage: no sign-ins, tickets, or app logs within your calibrated window.
  • Ownerlessness: no managedBy, no ticket, no sponsor.
  • Surface: reachable from outside; used by critical apps or in cross-forest trusts.

7) Certify and decommission safely

  1. Notify owners (or candidate owners) with evidence: last activity, where used, privileges.
  2. Stage disable: remove high privileges; deny interactive logon; disable delegation; leave enabled a few days.
  3. Observe: SIEM for failures; app teams confirm no impact.
  4. Disable the account.
  5. Retire: delete after retention window; archive attributes and notes.

Entra access reviews provide a first-class analog for human users and guests. Mirror the same cadence for non-human identities using your exports and ticketing system.

Field-tested patterns you’ll actually use

# Accounts with SPN but no logon in 120 days
```

$cut = (Get-Date).AddDays(-120)
Get-ADUser -LDAPFilter "(servicePrincipalName=*)" -Properties lastLogonTimestamp, userAccountControl |
Where-Object {
$*.Enabled -and
([DateTime]::FromFileTime($*.lastLogonTimestamp)) -lt $cut
} |
Select SamAccountName,
@{n='LastLogonAgeDays';e={ [int]((Get-Date) - [DateTime]::FromFileTime($*.lastLogonTimestamp)).TotalDays }},
@{n='PwdNeverExpires';e={($*.userAccountControl -band 0x10000) -ne 0}}

# Non-gMSA service accounts with PasswordNeverExpires

Get-ADUser -LDAPFilter "(&(objectClass=user)(servicePrincipalName=*)(!(objectClass=msDS-GroupManagedServiceAccount)))" `
-Properties userAccountControl |
Where-Object { $*.Enabled -and (($*.userAccountControl -band 0x10000) -ne 0) } |
Select SamAccountName

# Unconstrained or risky delegation

Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User))" -Properties userAccountControl, msDS-AllowedToDelegateTo |
Where-Object {
(($*.userAccountControl -band 0x80000) -ne 0) -or
$*.msDS_AllowedToDelegateTo
} |
Select SamAccountName, msDS_AllowedToDelegateTo
```
# Entra: ownerless, expiring, unused
```

$spAll = Get-MgServicePrincipal -All

# Ownerless

$ownerless = $spAll | Where-Object {
(Get-MgServicePrincipalOwner -ServicePrincipalId $_.Id -ErrorAction SilentlyContinue).Count -eq 0
}
$ownerless | Select DisplayName,AppId,Id | Export-Csv .\ownerless.csv -NoType

# Expiring secrets/certs in < 45 days

$soon = (Get-Date).AddDays(45)
$expiring = foreach ($sp in $spAll) {
foreach ($c in @($sp.PasswordCredentials + $sp.KeyCredentials)) {
if ($c.EndDateTime -and $c.EndDateTime -lt $soon) {
[pscustomobject]@{SP=$sp.DisplayName; Type=($c.GetType().Name); Ends=$c.EndDateTime; SPId=$sp.Id}
}
}
}
$expiring | Sort Ends | Format-Table -Auto

# Sign-ins grouped by resource (quick activity shape)

Get-MgAuditLogSignIn -Filter "appDisplayName eq 'MyAutomationApp'" -All |
Group-Object ResourceDisplayName |
Select Name,Count

Inherent tendencies you must design around

  • Privilege drifts upward. Emergency fixes grant extra rights that rarely get revoked. Penalize stale privileges in your score.
  • Ownership decays. Turnover and vendor churn make owner mappings stale. Add ownership attestation to quarterly reviews.
  • Batch jobs lie low. Scheduled services can run without interactive sign-ins. Look for service tickets and app logs, not just user sign-ins.
  • Legacy protocols persist. NTLM and basic auth paths can keep accepting old credentials. Enforce Kerberos and modern app auth; deprecate basic auth.
  • Audit data ages out. Export service principal sign-ins to SIEM daily so audits and cleanups have evidence.

Mental models experts use

  1. Four-axis health. Owner × Purpose × Path × Proof. Any zero multiplies risk.
  2. Replace human memory with machine schedules. Password rotation, access reviews, and audit exports must be automated, not remembered.
  3. Managed-by-default. If gMSA or workload identities aren’t the default for new services, drift is guaranteed.
  4. Evidence-first decommissioning. No breakage when you show proof of non-use from multiple planes (AD, Entra, app).

Subtle pitfalls, risks, and correctives

  • Mistaking “no user sign-in” for “no service use.” Cross-check KDC tickets and app logs; correlate with SPNs.
  • Purging before owners can react. Always stage disable with a short observation window.
  • Ignoring expiring secrets. Query Graph for PasswordCredentials/KeyCredentials end dates and renew ahead of time.
  • Over-trusting lastLogonTimestamp. Treat it as a hint; understand replication cadence; augment with per-DC metrics.
  • Letting audit data expire. Export service principal sign-ins to SIEM nightly.
```

Expert essentials checklist

  • [ ] Every service identity has a current owner and purpose.
  • [ ] gMSA or workload identities used wherever possible; exceptions documented.
  • [ ] AD & Entra activity proofs exported to SIEM (tickets and sign-ins).
  • [ ] Expiring credentials caught and rotated ahead of time.
  • [ ] Quarterly access reviews mirrored for non-human identities.
  • [ ] Staged decommissioning with rollback window and evidence pack.
```

Applications, consequences, and what’s next

Compliance without the drama. Auditors are now laser-focused on identity governance for non-human identities. Demonstrating owner mapping, review cadence, and expiring-credential coverage closes entire finding categories.

Operational clarity. Regular ownerless/stale discovery accelerates modernization. Teams refactor toward managed identities, gMSA, and fewer shared secrets. Start with the most sensitive services; the value compounds.

Threat-led tuning. Treat the top 10% risk-scored identities as hunt leads. Look for anomalous source IPs, outdated basic auth, unexpected SPNs, and surprise delegation edges.

Cloud-first future. Expect stronger native signals in Entra (unused apps, expiring credentials, over-privileged roles) and tighter integrations across ITDR and PAM. Keep folding these into your score.

Key takeaways and next steps

  • “Stale” and “orphaned” are different failure modes. Measure both.
  • Trust multiple planes of evidence: directory timestamps, tickets/sign-ins, and application logs.
  • Prefer managed identities (gMSA/workload identities) to reduce drift and false positives.
  • Use Entra recommendations and access reviews as built-in signals for non-human identity health.
  • Automate ownership attestation and staged decommissioning to avoid outages.

Call to action: Want a jump-start? Grab our Service Accounts Management Tool and run the ownerless + expiring + inactive triad this week. Subscribe to our deep-dive series for the reference pack with scripts, KQL, and report templates—or reach out if you want this converted into a printable checklist or an Elementor-ready HTML block.

Related:

Related posts
Active Directory FundamentalsActive Directory Objects

Recovering deleted users and groups in Entra

Active Directory FundamentalsActive Directory Objects

Site replication tuning and SRV record importance

Active Directory FundamentalsActive Directory Objects

Global catalog placement for large enterprise sites

Active Directory ObjectsActive Directory PoliciesUncategorized

Understanding group nesting limits and token size

×

There are over 8,500 people who are getting towards perfection in Active Directory, IT Management & Cyber security through our insights from Identitude.

Wanna be a part of our bimonthly curation of IAM knowledge?

  • -Select-
  • By clicking 'Become an insider', you agree to processing of personal data according to the Privacy Policy.