Get-StaleDevices
Identifies devices inactive for a configurable threshold across Intune, Entra ID, and on-premises Active Directory. Outputs CSV and HTML reports with remediation actions.
Overview
Get-StaleDevices identifies devices that have not checked in within a configurable threshold across Intune, Microsoft Entra ID, and on-premises Active Directory. Output includes CSV and HTML reports with per-device remediation recommendations.
Stale device cleanup is an underappreciated security hygiene task. Inactive device records create noise in compliance reports, consume Intune licences, and can be used by attackers who recover old hardware with a valid certificate or token cache.
This script is read-only. It queries data sources and produces reports. It does not delete, disable, or modify any device records. Remediation actions shown in the report require separate deliberate steps.
Tested environment: Windows 11 24H2 management workstation, Microsoft Graph PowerShell SDK 2.x, Intune and Entra ID tenants on April 2026 service release.
Prerequisites
The script requires the following before running:
- Microsoft Graph PowerShell SDK — install if not present:
Install-Module Microsoft.Graph -Scope CurrentUser -Repository PSGallery -Force-
Entra ID app registration with the following Application (not Delegated) permissions:
Device.Read.AllDeviceManagementManagedDevices.Read.All
Grant admin consent for both permissions after creating the registration.
-
RSAT Active Directory module — for on-premises AD queries:
# Windows 11 / Windows 10 2004+
Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0- The account running the script needs read access to Active Directory. Domain User is sufficient for AD queries.
Parameters
| Parameter | Type | Description |
|---|---|---|
-StaleThresholdDays | [int] | Days since last check-in to classify as stale. Default: 90 |
-Sources | [string[]] | Sources to query: Intune, EntraID, ActiveDirectory. Default: all three |
-OutputPath | [string] | Directory for CSV and HTML report output. Created if it does not exist |
-GraphCredential | [PSCredential] | Service principal credentials for unattended Graph API access |
-IncludeRemediation | [switch] | Add recommended action column to the report |
Usage Examples
Basic interactive run — 90-day threshold, prompt for Graph credentials:
Get-StaleDevices -StaleThresholdDays 90 -OutputPath C:\Reports\StaleDevicesQuery Intune and Entra ID only (no on-premises AD required):
Get-StaleDevices -Sources @('Intune', 'EntraID') -StaleThresholdDays 60 -OutputPath C:\ReportsUnattended run with service principal — for scheduled task or pipeline use:
$appId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$appSecret = ConvertTo-SecureString 'YOUR_SECRET' -AsPlainText -Force
$cred = New-Object PSCredential($appId, $appSecret)
Get-StaleDevices -GraphCredential $cred -StaleThresholdDays 90 -IncludeRemediation -OutputPath C:\ReportsOutput
The script writes two files per run to the specified -OutputPath:
| File | Format | Use |
|---|---|---|
StaleDevices-YYYYMMDD.csv | CSV | Power BI import, pipeline processing, ticket creation |
StaleDevices-YYYYMMDD.html | HTML | Human review, management reporting |
Remediation recommendations
When -IncludeRemediation is specified, each device row includes a RecommendedAction column:
| Condition | Recommended Action |
|---|---|
| Stale in all sources (>180 days) | Delete from all directories; revoke certificates and tokens |
| Stale in Intune only, active in AD | Investigate — device may have been re-imaged without re-enrolling in Intune |
| Active in Intune, stale in Entra ID | Sync Entra ID device record; check hybrid join connector health |
| Active in Intune, missing from AD | Likely cloud-only device; verify Autopilot registration is current |
| Stale in AD only | Check if device was decommissioned but AD record not cleaned up |
Do not bulk-delete devices based solely on this report without a manual review pass. Active devices with clock drift, offline periods, or VPN-only connectivity can appear stale with a 60–90 day threshold.
Validation
After running, verify the report looks complete:
# Count devices in the CSV
(Import-Csv C:\Reports\StaleDevices\StaleDevices-$(Get-Date -Format yyyyMMdd).csv).Count
# Spot-check a known stale device name — confirm it appears in the report
Import-Csv C:\Reports\StaleDevices\StaleDevices-$(Get-Date -Format yyyyMMdd).csv |
Where-Object { $_.DeviceName -eq 'LAPTOP-OLD-01' }Cross-reference the total device count in the CSV against the device count visible in the Intune portal (Devices > All devices) to confirm the Graph query returned a full result set and was not truncated.
Common Errors
Connect-MgGraph : Insufficient privileges
The app registration is missing the required Graph permissions, or admin consent has not been granted. Navigate to Entra admin centre → App registrations → [your app] → API permissions and confirm both permissions show "Granted for [tenant]".
Get-ADComputer : The server is not operational
The script cannot reach a domain controller. Ensure the management workstation is domain-joined, or run from a machine with line of sight to an AD DC. Use -Sources @('Intune', 'EntraID') to skip the AD query if on-premises AD is not accessible.
Invoke-MgGraphRequest : Response status code does not indicate success: 429 (Too Many Requests)
The Graph API is throttling the request. The script should retry automatically, but for large tenants (50,000+ devices) add a -ThrottleDelay value or break the run into source-specific queries to reduce concurrent request volume.
Report contains 0 devices
Verify the -StaleThresholdDays value. A threshold of 7 days in an active fleet may return 0 stale devices legitimately. Confirm the app registration has Device.Read.All with admin consent, not just Delegated permissions.
Security Notes
- The script is read-only across all data sources.
- When using a service principal (
-GraphCredential), store the client secret in a secrets vault (Azure Key Vault, Windows Credential Manager) rather than hardcoding it in scripts or scheduled task arguments. - The output CSV and HTML files contain device names, last check-in dates, and compliance states. Treat them as internal data — do not share publicly or store in unprotected locations.
- Do not automate device deletion based on this report without a human review step. Automated deletion of devices that are merely inactive can remove valid hardware from management.
Related Resources
Jack
LinkedInSenior Enterprise Sysadmin · 12+ Years Windows & Intune
I've spent 12+ years managing Windows fleets, Intune tenants, and Active Directory environments for enterprise clients across finance, logistics, and professional services. AdminSignal exists because I got tired of docs that stop at "click Apply." Everything here is tested in production before it goes on the page.
AdminSignal content is produced independently. Editorial policy