en-US/about_IntuneHousekeeper.help.txt
|
TOPIC about_IntuneHousekeeper SHORT DESCRIPTION A read-only inventory of a Windows Intune estate, written to an Excel decision tracker. Issues GET requests only and never changes a tenant. LONG DESCRIPTION The Intune portal has no list view of assignment status. Finding out what is unassigned means opening every object by hand, so nobody does it, and years of test policies and superseded applications quietly accumulate. Intune Housekeeper reads the estate through Microsoft Graph and writes one workbook. The Worklist sheet is the output that matters: every object worth acting on, pre-sorted, each row carrying a plain-language reason and a suggested action, with columns for recording what you decided. Nothing is changed for you. Intune has no recycle bin, and a deleted policy or application is gone permanently, so every change is made by a human in the portal after review. The module only ever issues GET requests, and the project's CI fails the build if any other method appears in the source. COMMANDS Export-IntuneHousekeeperReport Runs the inventory and writes the workbook. The command you will use. Get-IntuneHousekeeperConfig Shows the saved settings and the file they came from. Set-IntuneHousekeeperConfig Saves settings so they do not have to be typed each run. REQUIREMENTS PowerShell 7 on Windows. Windows PowerShell 5.1 is not supported: .NET Framework permits one Microsoft.Identity.Client assembly per process with no isolation, so a workstation carrying several Microsoft.Graph module versions fails at sign-in. The modules Microsoft.Graph.Authentication and ImportExcel, both declared in the manifest and installed automatically. Excel itself is not needed. Your own Entra app registration, public client / native flow. Under Authentication, Add Redirect URI, Mobile and desktop applications, add both ms-appx-web://Microsoft.AAD.BrokerPlugin/<client id> and http://localhost. The first is required for broker sign-in, which any tenant enforcing Conditional Access token protection needs. Delegated permissions, admin-consented: DeviceManagementApps.Read.All applications DeviceManagementConfiguration.Read.All profiles, compliance, baselines DeviceManagementScripts.Read.All remediations and platform scripts Group.Read.All group section only User.Read.All group section only DeviceManagementServiceConfig.Read.All group section only Consenting a permission does not put it in an existing token. After adding one, sign in once with -Scopes to force a fresh authorization: Connect-MgGraph -ClientId '<app id>' -TenantId '<tenant id>' -NoWelcome -Scopes ` 'DeviceManagementApps.Read.All','DeviceManagementConfiguration.Read.All', ` 'DeviceManagementScripts.Read.All' The module itself never passes -Scopes, because with a custom client ID that triggers a consent prompt. Here the prompt is exactly what is wanted, once. GETTING STARTED Save your settings, then run: Set-IntuneHousekeeperConfig -ClientId '<app id>' -TenantId '<tenant id>' Export-IntuneHousekeeperReport Settings live in %APPDATA%\IntuneHousekeeper\settings.json, or wherever -ConfigPath points. Only the values you pass are stored, and an explicit parameter always wins over a saved one for that run. Nothing secret is kept there: sign-in uses a public client flow, which has no secret. THE WORKBOOK Summary totals per category, broken down by priority RunInfo the settings the run used, and whether collection was complete Worklist every actionable object, pre-sorted, with reasons and decision columns the rest read-only inventory per object type Actionable means High plus Medium. Low is "keep or confirm" and Watch is parked, so neither is counted, though Low rows still appear on the Worklist as context. PRIORITY Priority means order of cleanup action, not risk to devices. Only High describes something that can actually affect a device. High Reality differs from intent: a test-named object on All Devices or All Users, or a group both included and excluded within one assignment intent. Correct it, do not delete it. Medium Unassigned or exclusion-only, with nothing referencing it. The cleanup queue. Low Unassigned but referenced, or a test-named object scoped to a group. Watch An unassigned application created recently. Parked, not counted. (blank) Assigned and healthy. FLAGS Unassigned no assignments at all OnlyExclusions exclusion targets only, so deployed to nothing TestNamed display name matches -TestNameRegex TestNamedBroadAssign test-named and assigned to All Devices or All Users DuplicateName name occurs more than once in its type; never raises priority IncludeExcludeOverlap same group included and excluded within one assignment intent SupersededByNewer a newer version supersedes this application SupersededByName unassigned, but a newer version of the same application is assigned; matched by name and version RetainedVersionExpired SupersededByName, but older than -RetainedVersionMonths HasDependents another application depends on this one RecentlyCreated unassigned application created within -NewAppGraceMonths ZeroMembers group has no direct members NoAssignmentFound no assignment referencing the group was found TEST OBJECTS There is no built-in naming convention. -TestNameRegex is empty by default, and without it no object is flagged as a test object. A shipped default such as '-TEST$' would report nothing on a tenant naming things TEST-Wifi or Wifi (test), and an empty result reads as a clean estate rather than as a check that never ran. Anchor the pattern on a word boundary, because a bare 'test' also matches Latest and Attestation: -TestNameRegex '(^|[-_ (\[])TEST([-_ )\]]|$)' The run reports how many names matched, and warns when none did. RETAINED APPLICATION VERSIONS Keeping the previous version of an application for rollback is common, and those copies are unassigned by design. Where Intune supersedence exists they are recognised from it. Where it does not, an unassigned application is recognised as a retained copy when its name carries a version and another application with the same base name has both a higher version and a live inclusion assignment. Rollback copies expire. Past -RetainedVersionMonths a retained copy returns to the cleanup queue flagged RetainedVersionExpired, because nobody rolls back to a build from two years ago. Set the window to suit your environment, or 0 to queue every retained copy. THE GROUP SECTION Supplying -GroupOwnerUpns and -GroupNamePrefix adds a check over Entra assignment groups owned by those accounts whose names match the prefix, reporting those that are empty or that no assignment references. Both filters are required. Owner scoping alone pulls in every Teams and Microsoft 365 group an owner happens to hold, where "not used in Intune" means nothing. Group references are established tenant wide. Reporting is Windows only, but a group used solely by a macOS shell script is still a group in use, so assignments are read from twelve object types outside the report purely to establish references. If any read fails, the section is skipped rather than reported from partial data. Group rows are always Investigate, never Remove. LIMITATIONS Assignments pointing at empty or deleted groups are not detected. They look healthy while deploying to nothing. Assignment filters are not evaluated. An object assigned through a filter matching no device is reported as healthy. The time an object was unassigned is not recoverable: assignment changes do not update lastModifiedDateTime. The audit log would be required. Detection of test objects and of assignment groups depends on naming conventions you supply. Anything that deviates is invisible. A group with no owner is invisible to the group section, and an abandoned group is more likely than most to have lost its owner. macOS, iOS and Android objects are not reported on. All Intune calls use the Graph beta endpoint, which Microsoft can change without notice. SEE ALSO Get-Help Export-IntuneHousekeeperReport -Full Get-Help Set-IntuneHousekeeperConfig -Examples https://github.com/kbentis/IntuneHousekeeper https://kbentis.cloud |