diff --git a/Remove-InactiveEntraDevice.ps1 b/Remove-InactiveEntraDevice.ps1 index 3aab4af..2088a2e 100644 --- a/Remove-InactiveEntraDevice.ps1 +++ b/Remove-InactiveEntraDevice.ps1 @@ -4,80 +4,10 @@ longer than a given number of days. .DESCRIPTION - Connects to Microsoft Graph and evaluates staleness in two passes: - - 1. Entra ID devices, cross-referenced with their matching Intune managed - device (if any), matched via the device's Azure AD device ID. "Last - activity" is the more recent of the Intune managed device's - LastSyncDateTime (last MDM check-in) and the Entra ID device's - ApproximateLastSignInDateTime (last sign-in with the device identity). A - device is considered stale only when BOTH available signals are older than - the -InactiveDays threshold, to minimize the risk of removing a device that - is active under one signal but temporarily quiet under the other. When - stale, the script removes the Intune managed device object (if any) and - then the Entra ID device object itself. - - 2. Intune managed devices that have NO matching Entra ID device object at all - (e.g. the Entra ID device was already deleted manually, or sync between - Intune and Entra ID is broken). These are invisible to pass 1, since it is - driven from the Entra ID device list. For these, staleness is judged purely - by LastSyncDateTime, and only the Intune managed device object is removed - (there is no Entra ID device object to remove). - - Devices with no usable activity signal at all cannot be judged reliably and are - reported as 'Unknown' rather than removed. Every row in the output has a 'Source' - column ('EntraID' or 'Intune') so it's clear which pass found it and what was - actually evaluated/removed. When a removal attempt fails, the 'ErrorDetail' column - holds the underlying error message(s) so the cause is visible directly in the - report, without needing to correlate back to the -Warning output. The 'TrustType' - column (Entra ID rows only - 'AzureAd' cloud joined, 'ServerAd' hybrid joined, - 'Workplace' registered/BYOD) helps explain permission-related removal failures, - since deleting a Workplace-registered device can require different rights than - deleting a joined one. The 'AutopilotRegistered' column is purely informational - - it flags devices that still have an active Windows Autopilot device identity, in - case that turns out to be relevant to a removal failure, but it does not change - whether removal is attempted. This lookup is best-effort: the Autopilot/Intune - enrollment backend can return transient errors (e.g. HTTP 500) independently of - the rest of the script; if it fails, the column shows 'Unknown' for every device - instead of aborting the whole run. - - The output only lists devices that were removed, attempted-but-failed, skipped - (e.g. under -WhatIf), or flagged as 'Unknown' for manual review - healthy, still - active devices are deliberately left out of the report to keep it focused on what - needs attention. Use -Verbose to see how many active devices were excluded. - - This script reads Windows Autopilot device identities only to populate the - 'AutopilotRegistered' column above - it never modifies or removes an Autopilot - registration. The hardware hash entry is always left in place, so a device can - always be re-provisioned via Autopilot later, even after its Entra ID / Intune - objects have been cleaned up (when that succeeds). - - Hybrid Azure AD joined devices (TrustType 'ServerAd') are never removed - their - Entra ID device object is synced from on-premises Active Directory, and Entra ID - rejects deleting it directly, so removal must happen by deleting/disabling the - on-prem computer object and letting Entra Connect sync the deletion. A hybrid - device is only mentioned (via -Verbose, not in the output) when it would - otherwise have been flagged stale and removed - active hybrid devices are not - called out at all, same as any other active device. - - Because these deletions are effectively irreversible, run with -WhatIf first to - preview exactly what would be removed - each candidate device is still reported - individually. For a real run, instead of prompting once per device/operation, the - script asks for a single upfront confirmation ("This will permanently remove ... - Continue?") before touching anything; declining aborts the entire run with nothing - removed. Pass -Confirm:$false to skip even that single prompt (e.g. for unattended/ - scheduled execution). - - Requires an account with sufficient Entra ID / Intune role assignments (e.g. Cloud - Device Administrator + Intune Administrator, or Global Administrator) and the - following Microsoft Graph delegated scopes: - Device.Read.All - Directory.ReadWrite.All - DeviceManagementManagedDevices.ReadWrite.All - DeviceManagementServiceConfig.ReadWrite.All (read-only use: listing Autopilot - device identities for the 'AutopilotRegistered' column; no Graph permission - model exists for read-only access to this resource, so ReadWrite.All is the - minimum available scope even though this script never writes to it) + Connects to Microsoft Graph, finds stale Entra ID and Intune-managed devices, + and removes the matching device records after checking their last sign-in and + last sync activity. It also reports devices that cannot be deleted, devices with + no reliable activity signal, and whether an Autopilot registration still exists. .PARAMETER InactiveDays Number of days of inactivity after which a device is considered stale. Defaults to