HomeNewsletterCommunityToolsArchiveBlogToday's NewsAboutServicesQuick Links Subscribe free
← Back to Blog

Local Administrators Group Drift: Finding the Admin Access Nobody Ever Revoked

IA
Imran Awan
22 July 2026

LAPS rotates the local Administrator password on schedule, and if you've read the sibling post on this blog you already know how to prove that rotation is actually happening rather than just configured. But a rotating password answers only half the question. It tells you the built-in account's credential is fresh. It tells you nothing about who else is sitting in that same Administrators group — the contractor who needed "just temporary" elevation eight months ago to install one piece of software, and whose account nobody ever removed. This post is about finding that second, quieter problem: not whether the password rotates, but whether the membership list itself has drifted away from what it should be.

Download the script — GitHub

Get-LocalAdminGroupDrift.ps1 is free and open source. Download it from the Imran76Awan/Daily-Tasks repository on GitHub — no sign-in required. Note: at the time of publishing this script has not yet been pushed to GitHub — the path below is where it will live once it has been tested and confirmed working.

Get-LocalAdminGroupDrift.ps1 View full repo →

The Problem — the contractor who left in January is still an admin in July

Here's the scenario, and if you've been doing endpoint engineering for more than a year, some version of it has already happened in your estate. A contractor was brought in for a six-week project. Their laptop needed a vendor-supplied driver installer that demanded local admin rights to run. Rather than build a proper Win32 app package with the right install context, someone — reasonably, under deadline pressure — added the contractor's personal Entra account to the local Administrators group on their assigned device "just for the install." The project ended. The contractor's badge was returned. Their Entra account may even have been disabled eventually. But nobody ever touched that local Administrators group membership, because nothing prompted anyone to look.

Six months later, that laptop gets reassigned to a new starter. The new starter now has local admin rights on their machine through an account that shouldn't be there at all, inherited silently from a decision nobody remembers making. Multiply this by every "can you just make me admin temporarily" Slack message your helpdesk has fielded over the last two years, across every device those requests touched, and you have a real, unquantified attack surface that nothing in your standard Intune compliance dashboard will ever surface.

Windows PowerShell (Administrator) — checking a device six months after offboarding
PS C:\> Get-LocalGroupMember -Group "Administrators"
 
ObjectClass Name PrincipalSource
----------- ---- ---------------
User WORKSTATION-042\Administrator Local
User CONTOSO\LAPS-Managed-Account ActiveDirectory
User CONTOSO\j.contractor-external ActiveDirectory
Group CONTOSO\Marketing-AllStaff ActiveDirectory
# Two accounts flagged: an external contractor account (disabled since January,
# still a local admin) and an entire department security group that was almost
# certainly added by accident during a scoping error in an old GPO change.

Notice the second finding in that output — a whole department distribution/security group with local admin rights. That one is worse than the individual contractor account, because it means every member of Marketing, present and future, silently inherits local admin on this device the moment they're added to that group in Entra ID or Active Directory. Nobody who added that group meant for that to happen at this scale. Drift compounds.

📋 Note: This is genuinely different from every other "audit this centrally" post on this blog. There is no Microsoft Graph endpoint that returns local Administrators group membership for a device — unlike Conditional Access policies, PIM role assignments, or OAuth app consents, local group membership lives entirely in the device's local SAM database and is never synced up to Entra ID or exposed through Get-MgDeviceManagementManagedDevice or any other Graph call. That's not a gap in this post's research — it's a real architectural fact about how Windows stores this data. Everything from here on is built around that constraint, not around it.

Why It Happens — nothing native ever asks the question

The root cause isn't carelessness, exactly — it's the absence of a natural trigger. Elevation requests get granted through whatever channel is fastest: a helpdesk ticket resolved with net localgroup Administrators CONTOSO\username /add, a quick GPO Restricted Groups edit, or a one-off addition through Computer Management on the device itself. Granting access is a single action with an immediate, visible payoff — the user can now install their software. Reverting access has no equivalent trigger. Nobody's calendar reminds them "check whether Jane still needs local admin on WKS-042." The request that started the grant has an end; the grant itself does not, unless someone deliberately closes the loop.

Compounding that, most organisations' offboarding checklists focus on the things that are centrally visible and therefore feel urgent: disable the Entra ID account, revoke licenses, remove from distribution groups, wipe the Autopilot-enrolled device if it's being returned. Local Administrators group membership on a device that isn't being wiped — because it's being reassigned to someone else, not retired — simply isn't on that checklist, because nobody built tooling that would surface it as a checklist item in the first place.

And unlike almost every other identity or access control surface covered on this blog, that absence of tooling isn't a documentation gap you can fix by reading further. It's structural.

⚠ Gotcha: Every local Administrators group already contains at least one well-known account — the built-in local Administrator account (SID ending in -500), even if it's disabled. If you deploy the detection script below without putting that account (and your LAPS-managed account, if it uses a different name) on your -ExpectedMembers baseline, every single device in your fleet will report a false-positive "unexpected member" on its very first run. Build your baseline list before you deploy at scale, not after the alert flood starts.

How to Verify — run it by hand on one device first

Before you deploy anything to a fleet, confirm the check itself makes sense against a real device you understand. Open an elevated PowerShell session — this needs administrative rights on the local device, same as any command that touches the SAM database — and run the one cmdlet this entire post is built around:

PowerShell (Administrator) — the one command this entire post is built on
PS C:\> Get-LocalGroupMember -Group "Administrators" | Select-Object Name, ObjectClass, PrincipalSource
 
Name ObjectClass PrincipalSource
---- ----------- ---------------
WORKSTATION-042\Administrator User Local
CONTOSO\LAPS-Managed-Account User ActiveDirectory
CONTOSO\it-support-tier2 Group ActiveDirectory

Get-LocalGroupMember is a standard cmdlet in the Microsoft.PowerShell.LocalAccounts module, built into Windows PowerShell 5.1 and PowerShell 7 on every Windows 10/11 device — no module install required, no elevated tenant permissions required, because this is a purely local query against the device's own SAM database. Run it now on a device you already understand, write down the names it returns, and decide which ones genuinely belong there. That list becomes your baseline. If you skip this step and jump straight to deploying the script at scale with a guessed baseline, you'll spend your first week drowning in false positives instead of real findings.

One thing worth checking at the same time: whether either of the two legacy enforcement mechanisms is already configured on this device, because the detection script below is valuable regardless of the answer, but it's worth knowing which situation you're in.

Registry Editor — checking for a GPO Restricted Groups policy already in effect
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History\...\Machine\Microsoft\Windows NT\SecEdit
GptTmpl.inf [Group Membership] section ← present only if Restricted Groups GPO is linked to this device's OU
Easier check: run gpresult /h report.html and search the report for "Restricted Groups" — if it appears, membership is being enforced by GPO on top of (or instead of) whatever local admins add manually.

The Fix — a detection script deployed as an Intune Proactive Remediation

The fix here isn't a policy setting, because — as the blue callout above explained — there is no Graph endpoint and no simple centralized query that answers "who is in the local Administrators group across my fleet." What does exist, and what this blog has already used twice for exactly this class of problem, is a device-side detection script deployed through Intune Proactive Remediations. Two sibling posts on this blog already establish this exact pattern for surfacing device-local state that Graph can't see directly: the WHfB health scripts post, which checks PRT and NGC key state, and the Primary Refresh Token remediation post. Both use the same mechanism this post relies on: a script runs locally on the device, exits with a code Intune understands, and Intune's own reporting surfaces the aggregate result centrally — while the script's own console output, captured per-device, is what actually shows you the detail.

Get-LocalAdminGroupDrift.ps1 runs Get-LocalGroupMember -Group "Administrators", compares the result against an -ExpectedMembers baseline you supply, and reports two categories of drift: accounts present that shouldn't be (unexpected), and accounts on the baseline that are missing entirely (which matters most when the missing account is your LAPS-managed one — see the green tip below). It exits 1 if either condition is found, 0 if the device matches baseline exactly.

Get-LocalAdminGroupDrift.ps1 — Intune detection output on a drifted device
[09:02:11] [INFO ] Local Administrators group drift check starting on WORKSTATION-042
[09:02:11] [INFO ] Expected baseline (2 members): BUILTIN\Administrator, CONTOSO\LAPS-Managed-Account
 
[09:02:11] [INFO ] --- Current Administrators group membership (4 members) ---
[09:02:11] [INFO ] BUILTIN\Administrator [User / Local]
[09:02:11] [INFO ] CONTOSO\LAPS-Managed-Account [User / ActiveDirectory]
[09:02:11] [INFO ] CONTOSO\j.contractor-external [User / ActiveDirectory]
[09:02:11] [INFO ] CONTOSO\Marketing-AllStaff [Group / ActiveDirectory]
 
[09:02:11] [INFO ] --- Drift comparison against expected baseline ---
[09:02:11] [WARN ] UNEXPECTED member present: CONTOSO\j.contractor-external - not on the expected baseline, investigate before removing
[09:02:11] [WARN ] UNEXPECTED member present: CONTOSO\Marketing-AllStaff - not on the expected baseline, investigate before removing
[09:02:11] [PASS ] No expected members are missing
 
[09:02:11] [FAIL ] --- RESULT ---
[09:02:11] [FAIL ] NON-COMPLIANT - drift detected: 2 unexpected, 0 missing
# Exit code: 1 - Intune marks this device "with issues" in the Proactive Remediation report
⚠ Warning: This post deliberately does not ship a paired auto-remediation script that removes unexpected members automatically. Removing someone from local Administrators can break a legitimate business process if you don't know why they were added — a monitoring agent's service account, a backup tool that needs local admin to run, a break-glass account your security team put there on purpose. Treat every UNEXPECTED finding as an investigation task, not an auto-remove candidate, especially for anything that looks like a service account rather than a person.

Deploy the detection script as its own Proactive Remediation policy — detection only, no remediation script attached, which is a fully supported configuration in Intune. Here's the exact path:

Intune Admin Center — Proactive Remediation setup
Devices Scripts and remediations Proactive remediations + Create script package
  1. Name: Local Administrators Group Drift Audit
  2. Detection script: Upload Get-LocalAdminGroupDrift.ps1 — edit the $ExpectedMembers default array in the script itself to match your real baseline before uploading
  3. Remediation script: none — leave this policy detection-only, per the red warning above
  4. Run this script using the logged-on credentials: No (run as SYSTEM — reading the Administrators group doesn't require user context, and SYSTEM has consistent access on every device)
  5. Run script in 64-bit PowerShell: Yes
  6. Schedule: Daily — membership doesn't change hourly, and this keeps the script's footprint negligible
  7. Scope: Assign to All Devices (or your Windows device group) — this is exactly the kind of check that's most valuable run everywhere, not just on devices you already suspect

Two enforcement paths exist for declaring expected local group membership as policy, and it's worth documenting both, because the detection script above catches drift regardless of whether either is in place — that's exactly why it's still worth deploying even if you already use one of them.

Enforcement options — modern CSP vs. legacy GPO (neither is required for detection to work)
Modern — Intune Settings Catalog
Devices › Configuration › Create › Settings catalog › category Local Users and Groups
Backed by the Account Protection CSP / Local Users and Groups CSP — lets you declaratively add or remove specific members from the built-in Administrators group as an Intune-managed configuration
Legacy — Group Policy Restricted Groups
Computer Configuration › Policies › Windows Settings › Security Settings › Restricted Groups
Enforces group membership on every Group Policy refresh — the pre-Intune equivalent, still common in hybrid AD-joined estates

If you'd rather query drift findings across many devices at once in KQL instead of clicking through per-device output in the Intune portal, the natural extension is writing Get-LocalGroupMember results to a custom Log Analytics table via the Azure Monitor Agent's custom log ingestion, then querying it centrally. That's a genuine enhancement worth building once you've validated the baseline approach — but it's an addition on top of this script, not a replacement for the detection-script pattern itself.

Proof It Worked — watching the compliance number fall, then checking one device's own output

After deploying the policy and letting it run against your fleet for the first cycle, the Proactive Remediations report gives you the aggregate view first. This is the "how many devices failed this check" number — not a live per-device membership list, but a genuinely useful signal of scale:

Intune Admin Center — Proactive remediations › Local Administrators Group Drift Audit › Device status
Devices scanned 1,842
Devices with issues found 142 devices
No issues found 1,700 devices

142 out of 1,842 devices with unexpected local admin members is not a small number — roughly 7.7% of the fleet carrying access nobody currently accounts for. That number on its own tells you scale. It doesn't tell you what to do about any individual device. For that, drill into a specific device's detection run and read the captured console output, which is the actual per-device detail this whole approach exists to surface:

Intune Admin Center — Device status › WORKSTATION-042 › Pre-remediation detection output
WORKSTATION-042 With issues

Clicking into this device's row shows the full script output captured at detection time — the same log lines from the ps-block above, including the two flagged accounts, right there in the portal. No Graph query, no export — this per-device console capture is Intune's built-in mechanism for exactly this kind of finding.

After investigating and manually removing the contractor account (confirmed genuinely stale — the account itself had been disabled in Entra ID since January) and correcting the accidental group nesting for Marketing-AllStaff, the next day's detection run on that same device shows compliant, and the fleet-wide number drops accordingly over the following week as the backlog gets worked through — not all 142 at once, since each finding still needs the same investigate-before-remove judgment call the red warning above insists on.

MetricBefore cleanupOne week after
Devices with issues found14231
Devices confirmed compliant1,7001,811
Findings confirmed as legitimate (left in place)19
Findings removed after investigation92

That last row matters as much as the compliance number. Not every UNEXPECTED finding is wrong — some turn out to be legitimate service accounts or support groups that were simply never documented as "expected," and the right fix there is updating your baseline, not touching the device. The script's job is to surface the question. Answering it is still a human judgment call, every time.

✅ Tip: Pair this script with the sibling LAPS rotation post on this blog and treat your LAPS-managed account as the one account that should always be a legitimate exception on every baseline. If a device's drift report shows the LAPS-managed account as MISSING rather than unexpected, that's a more urgent finding than any unexpected member — it likely means LAPS itself isn't correctly configured or the account was manually removed, which also means your password rotation story from that other post may not be as solid as the compliance tile suggests.
💼 Need this done for you?
Not sure who's actually admin across your fleet?

I'll deploy and tune a Proactive Remediation like this one for your environment, help you build an accurate expected-members baseline, and work through the investigation backlog with your team.

💬 See how I can help → 📅 Book a free call

References

Download this script free: Get-LocalAdminGroupDrift.ps1 is a read-detection script — it never modifies the group it audits. Safe to deploy fleet-wide as a detection-only policy while you build up an accurate expected-members baseline for your environment.
Share this post
LinkedIn X / Twitter Reddit Bluesky

More from EndpointWeekly

Security
Is Your LAPS Password Actually Rotating — Or Just Configured?
Windows LAPS can look compliant in Intune and still have a local admin password that hasn't rotated in months…
Scripts & Tools
Deploy Free WHfB Health Scripts to Intune: Six Checks, Five Auto-Repairs
WHfB breaks silently — PRT expires, NGC keys corrupt, services stop. Here is a Proactive Remediation pair that detects…
Technical Guide
Silently Fix a Missing Primary Refresh Token with Intune…
No PRT means no passwordless. The device looks healthy in Intune, compliance shows green, but WHfB provisioning…