Overview
Orphan devices are a specific kind of cloud directory waste: devices whose owner is no longer a valid identity. A laptop assigned to a former employee whose account was disabled six months ago. A phone whose registered user was deleted from Entra ID after a contract ended. A kiosk that was never linked to any user account in the first place. These records inflate license counts, distort compliance reporting, and create gaps in your audit trail — but they are invisible to time-based scans like Obsolete Device Management because the devices may still be active.
Orphan Device Cleaner (ODC) detects them by cross-checking every device against the live Entra ID user directory and against the recently-deleted-users list. Each detected orphan is classified into one of four colour-coded categories so you can review and clean by category. Detection is fast even on large tenants — owner resolution runs 15 calls in parallel, with built-in 429 throttling and retry.
Four orphan categories
No user assigned (🔴), Disabled user account (🟠), Deleted user / not found (⚫), and Shared / kiosk device (🟡). Each category has its own colour-coded row and a live counter at the bottom of the screen.
Cross-checks against the user directory
Loads every device, every active user, and every recently-deleted user, then resolves the registered owner for each device. Classification is done on the workstation after all data has arrived.
Parallel owner resolution
Up to 15 concurrent calls to /devices/{id}/registeredOwners, with automatic retry-after handling on HTTP 429. A tenant of 2000 devices typically resolves in about 15 seconds.
CSV export and bulk delete
Export the current view to CSV with configurable separator, or select rows and delete in bulk — destructive operations are gated by an explicit confirmation prompt and per-device CMTrace logging.
The four orphan categories
ODC does not treat all orphans the same. Each detected device is placed in one of four categories that imply different remediation priorities — a device whose owner was disabled yesterday is a very different problem from a kiosk that was never user-bound.
| Category | Definition | Typical remediation |
|---|---|---|
| 🔴 No user assigned | No registered owner found via /devices/{id}/registeredOwners (Entra), or the assigned userPrincipalName is empty or the Intune null-user GUID (00000000-0000-0000-0000-000000000000). | Investigate provenance, then delete or reassign. |
| 🟠 Disabled user | The owner exists in the live user directory but has accountEnabled = false. Typically a former employee whose account was disabled but whose devices were not collected. | Confirm the offboarding is complete, then delete. |
| ⚫ Deleted / not found | The owner's UPN is not in the live user directory and is either confirmed in /directory/deletedItems (recently deleted), or completely absent. The account is gone. | Safe to delete in most policies. |
| 🟡 Shared / kiosk device | No registered owner, but the enrollment profile name or join type identifies the device as a kiosk or shared device. Distinguished from "No user assigned" because these devices are legitimately owner-less. | Keep — these are by design. |
How "shared / kiosk" is detected
Without this distinction, every kiosk in your fleet would be flagged as a 🔴 No user device, which would be noise. ODC applies a heuristic to identify the legitimate owner-less devices: a device is classified as 🟡 Shared if any of the following is true:
- EnrollmentProfileName contains "kiosk", "shared", or "kioskMode" (case-insensitive)
- ProfileType contains "shared" (case-insensitive)
- JoinType equals "azureadregistered" (typical of BYOD bring-your-own-device registrations and kiosks)
The 4-step detection workflow
ODC's detection is more involved than a single Graph query because it must correlate three data sources (devices, active users, deleted users) and then resolve registered owners per device. The four steps are:
- 1
Load all devices from the selected source
Either GET /v1.0/devices (Entra ID) or GET /beta/deviceManagement/managedDevices (Intune), with $top=999 per page and full pagination via @odata.nextLink.
- 2
Load the active user directory
GET /v1.0/users with $select on the fields needed for classification (id, userPrincipalName, displayName, accountEnabled, department, jobTitle). Paginated. Builds an in-memory Dictionary<UPN, UserInfo> on the workstation.
- 3
Best-effort enrichment with deleted users
GET /v1.0/directory/deletedItems/microsoft.graph.user with the same field selection. Merged into the same dictionary, flagged as IsDeleted = true. If the call fails (permission denied or other), it is logged as a warning and detection continues — see "Permissions" below for what you lose.
- 4
Resolve owners and classify
For Entra devices, resolve /devices/{id}/registeredOwners in parallel (15 concurrent calls, automatic retry on HTTP 429). For Intune devices, use the userPrincipalName already present on the device record (with normalization of the null GUID). Look up each owner UPN in the user dictionary, classify into one of the four categories, and emit the orphan list.
All classification logic runs on the workstation after all data has arrived. No streaming, no progressive results — the orphan list appears in one batch when steps 1 through 4 complete.
Where ODC fits — the cleanup triptych
ODC is one of three TontonTools hygiene tools for Microsoft cloud directories. Each answers a different question, and they are designed to compose: running all three in sequence as a monthly routine catches each category of waste at its right layer.
| Tool | Question answered | Detection axis | Tier |
|---|---|---|---|
| Duplicate Device Management | Which devices are registered more than once? | Duplication (same name) | Pro |
| Orphan Device Cleaner | Which devices belong to dead or missing accounts? | Identity (owner state) | Pro |
| Obsolete Device Management | Which devices have been silent for too long? | Time (inactivity) | Enterprise |
Prerequisites
| Requirement | Minimum |
|---|---|
| Operating system | Windows 10 22H2 or Windows 11 (administrator workstation only) |
| .NET Framework | 4.7.2 or later |
| Microsoft Graph | An App Registration in your tenant with the required permissions (see below) |
| Network | Outbound HTTPS to graph.microsoft.com (TLS 1.2+) |
| License tier | Pro or Enterprise subscription, or active 14-day trial |
Microsoft Graph permissions
ODC needs broader Graph permissions than the rest of the suite because classification requires reading the user directory in addition to devices. Grant admin consent after assigning all permissions below.
| Permission | Required for | Type |
|---|---|---|
| Device.Read.All | Search Entra ID devices | Application |
| Device.ReadWrite.All | Delete Entra ID devices + resolve registered owners | Application |
| User.Read.All | Load active user directory and resolve owner UPN to user identity | Application |
| DeviceManagementManagedDevices.Read.All | Search Intune managed devices | Application |
| DeviceManagementManagedDevices.PrivilegedOperations.All | Delete Intune managed devices | Application |
Best-effort deleted-users enrichment — what you lose without it
ODC attempts to enrich its user dictionary with recently-deleted users via /v1.0/directory/deletedItems/microsoft.graph.user. This call requires User.Read.All. Microsoft retains deleted users in this endpoint for 30 days after deletion, so this enrichment is what lets ODC positively identify a device as "⚫ Deleted user" rather than "⚫ Not found in directory".
If the call fails — permission not granted, throttled, transient network issue — ODC logs a warning and continues detection without the deleted-users enrichment. The behavior degrades gracefully:
- With successful enrichment Devices whose owner is in /deletedItems appear as "⚫ Deleted user" with a richer owner display (department, job title, last known display name). Devices whose UPN is in neither list appear as "⚫ Deleted / not found".
- With failed enrichment Both cases collapse into "⚫ Deleted / not found — owner UPN absent from active directory". The device is still flagged correctly as an orphan, you just lose the distinction between "deleted last week" and "deleted long ago / never existed". Detection still completes successfully.
Initial configuration
On first launch, ODC verifies the license, then asks for Microsoft Graph credentials via the standard TontonTools credentials dialog. Credentials are shared across the suite — if already configured for another tool on the same workstation and user profile, ODC picks them up automatically.
ODC supports the three standard TontonTools Graph authentication modes: Client Secret (App-only), Certificate (App-only, JWT client assertion — recommended for production), and Interactive (Delegated, with PKCE). For the full mode-by-mode setup including App Registration prerequisites, see the Delete Device Everywhere documentation.
Main features
Source selection: Entra ID or Intune
The Source drop-down switches between two data sources. Entra ID uses /devices and resolves registered owners via parallel /registeredOwners calls. Intune uses /managedDevices and reads the userPrincipalName already present on the device record. The data grid columns adapt automatically to the source.
ODC scans one source at a time. Run two passes (Entra ID first, then Intune) for a complete hygiene cycle.
Category filter
After detection completes, you can narrow the view to a single category with the Category drop-down: 🔴 No user assigned, 🟠 Disabled user, ⚫ Deleted / not found, or 🟡 Shared device. The default is "(all categories)". The live counters at the bottom show how many devices fall into each category even when the filter is applied.
Other filters
- Operating System Windows, Android, AndroidEnterprise, AndroidForWork, iOS, Unknown. Useful when a specific platform is over-represented in your orphan list.
- Ownership company, personal, unknown. Personal devices often produce orphans after offboarding even though the corporate fleet itself is clean.
- Last Activity Inactive ≥ 30 / 60 / 90 / 180 / 365 days, or "Never active" (no recorded sign-in or sync at all). Useful to surface the most defensibly-deletable orphans first — a device whose owner is disabled AND that has been silent for a year is an easy decision.
- Free-text filter Matches device name, OS, user, model, IDs. Case-insensitive substring search.
Detect Orphans (the main button)
Clicking 🔍 Detect Orphans runs the four-step workflow described above. Progress is reported step by step in the status bar — "Step 1/4 - Loading all Entra ID devices...", "Step 2/4 - Loading active user directory...", and so on, including the running count during owner resolution ("Resolving owners... 745/2000"). The full detection on a 2000-device tenant typically completes in well under a minute.
Stats bar
Below the data grid, a dark stats bar shows live counters per category: 🔴 No user, 🟠 Disabled, ⚫ Deleted, 🟡 Shared, and the total. These counters reflect the entire detection — they do not change when you apply the Category filter. They are designed as the headline numbers of your hygiene campaign.
Resolve Owners (Entra ID, optional re-run)
For Entra ID rows, the 👤 Resolve Owners button re-runs the parallel owner resolution on the currently selected rows. This is mostly useful when you want to refresh data after a back-end change — owner resolution is already part of the main Detect Orphans workflow, so you do not need to click this button after every detection. Like the main detection, it issues parallel /devices/{id}/registeredOwners calls with throttling protection.
Delete Selected (final destructive action)
Select rows individually or use the header checkbox to select all visible rows, then click 🗑 Delete Selected. The confirmation prompt shows the count, lists up to 15 device names tagged with their category for visual scan, and ends with an explicit "IRREVERSIBLE. Confirm?" prompt.
Deletions are sequential, one device per Graph DELETE call, with per-device CMTrace logging including the HTTP status code and response body on failure. Aggregated success and failure counts are summarised at the end. The Activity Log captures the full sequence for audit.
CSV export
The Export CSV button writes the current grid view to a CSV file — including the orphan category and the resolved owner status — with configurable separator (semicolon, comma, or pipe), UTF-8 with BOM for Excel, and a meaningful default file name. The export is the recommended pre-deletion audit trail: review it, share it with your governance committee, then come back to do the actual deletes.
Device details dialog (double-click a row)
Double-clicking any row opens a detail window with four tabs: Orphan Info (category, owner UPN, owner display name, owner account status, department, job title), Device (OS, manufacturer, model, compliance, management), Dates (last sign-in, last sync, enrolled, registration, on-prem sync, days inactive), and All Properties (a plain-text dump suitable for copy-pasting into a ticket). The top of the window shows a coloured banner that matches the device's orphan category, and the days-inactive count is colour-coded (green under 90 days, yellow at 90+, orange at 180+, red at 365+).
CMTrace logging
ODC writes a daily CMTrace-compatible log to C:\TEMP\OrphanDeviceCleaner_yyyyMMdd.log. Every entry includes the operator (DOMAIN\User), the auth mode, the tenant, and timestamp with millisecond precision. The four-step workflow logs progress, the orphan classification logs counts, and the deletion logs per-device HTTP results. Open with CMTrace.exe (shipped with SCCM) for coloured real-time viewing.
License & read-only mode
ODC follows the TontonTools licensing model: 7-day cache + 7-day offline grace, then read-only mode. In read-only mode, Detect Orphans, Delete Selected, and Resolve Owners are disabled (these are the Graph-intensive write paths). Export CSV remains active so existing detections can still be exported for audit. The Credentials dialog remains accessible. A persistent banner offers to enter a license key or contact support.
For the full licensing model — Trial mechanics, machine and tenant binding, moving a license between workstations, subscription cancellation behavior — see the Licensing reference.
Typical workflow — a quarterly orphan cleanup
- 1
Configure credentials once
Click ⚙ Credentials, fill in Tenant ID, Client ID, and the auth mode of your choice. If already configured for another TontonTools product, ODC picks them up automatically.
- 2
Pick a source — start with Intune
Intune typically produces more orphans than Entra ID (BYOD enrollments by former employees, lost-and-recovered devices). Start there.
- 3
Click Detect Orphans
Wait for the four steps to complete. The stats bar populates with the four category counts when detection finishes.
- 4
Review by category
Use the Category filter to focus on one bucket at a time. Start with ⚫ Deleted users (easiest decision — the owner is gone), then 🟠 Disabled users (confirm offboarding is complete), then 🔴 No user devices (investigate provenance). Ignore the 🟡 Shared rows.
- 5
Export CSV before any destructive action
Even for an obvious cleanup, save a CSV first. This is your record once the deletes complete.
- 6
Select and delete by category
For each category you are ready to clean, filter the view, click Select All in the header, then Delete Selected. Confirm carefully.
- 7
Repeat for the second source
Switch the Source drop-down to Entra ID and repeat the process. Many of the same identities will reappear because the same employee account often owns devices in both Entra and Intune.
- 8
Keep the CMTrace log
The daily log file under C:\TEMP captures every per-device decision. Attach it to your audit record if your governance process requires it.
Limitations and design choices
- Owner-state-based detection only ODC does not detect duplicates (use Duplicate Device Management) or inactivity-based orphans (use Obsolete Device Management). The "orphan" concept here is specifically about the relationship to a user identity.
- One source at a time ODC scans Entra ID or Intune, not both at once. Entra registered owners are resolved via dedicated Graph calls; Intune already exposes the userPrincipalName on each managed device record. The two paths are kept separate to keep the orchestration explicit.
- Kiosk detection is heuristic The 🟡 Shared classification relies on profile name and join type. If your kiosk naming convention differs from "kiosk" / "shared" / "kioskMode" or your kiosks are not azureadregistered, they will land in 🔴 No user. Spot-check on first use.
- Deleted-users window is 30 days Microsoft retains deleted users in /directory/deletedItems for 30 days. Beyond that, ODC cannot distinguish "deleted recently" from "never existed" — both end up as ⚫ Deleted / not found.
- No rollback snapshot Unlike Delete Device Everywhere, ODC does not capture a JSON snapshot before deletion. Use CSV export as the pre-deletion audit trail.
- No Active Directory or SCCM coverage ODC is a cloud-directory cleanup tool. On-premises orphans (computer objects in AD without a corresponding identity) are not covered by this product.
Technical notes
- Graph API versions Entra device search uses /v1.0/devices. Intune device search uses /beta/deviceManagement/managedDevices (needed to retrieve enrollmentProfileName for the kiosk heuristic). User directory uses /v1.0/users and /v1.0/directory/deletedItems/microsoft.graph.user. Deletions use /v1.0/devices for Entra and /beta/deviceManagement/managedDevices for Intune.
- Owner resolution parallelism SemaphoreSlim(15, 15) caps concurrent /registeredOwners calls at 15. On HTTP 429 (throttling), the response Retry-After header is honored and up to 3 retries are attempted before the device is left without a resolved owner (it would be classified as 🔴 No user in that case, but the run completes).
- Intune null user Intune represents "no user assigned" with the GUID 00000000-0000-0000-0000-000000000000 in userPrincipalName. ODC normalizes this value to an empty string before classification, ensuring these devices land cleanly in 🔴 No user (or 🟡 Shared if the kiosk heuristic matches).
- Page size ODC requests $top=999 per page and follows @odata.nextLink until exhaustion. There is no client-imposed cap on the total number of records returned. Classification runs after all pages and the user dictionary have been fully loaded, so results are consistent.
- Credential storage DPAPI-encrypted under the current Windows user profile at %AppData%\TontonTools\credentials.dat — shared across all TontonTools products on the same user account on the same workstation.
- No telemetry, no agent ODC runs entirely from the administrator workstation. The only outbound connections are to graph.microsoft.com (for the scans and deletes) and to api.lemonsqueezy.com (for license validation, at most weekly).