Remove-Entra-Group-Assignments.ps1
|
<#PSScriptInfo .VERSION 1.0 .GUID d1f762a9-ad9d-47da-9f0c-8ec98b7ea1f6 .AUTHOR Alexander Marrero .COMPANYNAME .COPYRIGHT .TAGS Intune EntraID MicrosoftGraph DeviceManagement Automation .LICENSEURI https://opensource.org/licenses/MIT .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES Microsoft.Graph.Authentication,Microsoft.Graph.Groups .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES Version 1.0: - Initial release - Removes direct group memberships from Entra ID device objects - Skips dynamic groups and non-group directory objects .PRIVATEDATA #> <# .SYNOPSIS Removes all direct Entra ID group memberships from a device object. .DESCRIPTION This script connects to Microsoft Graph and removes a specified device object (from Entra ID / Azure AD) from all directly assigned group memberships. The script performs the following operations: - Retrieves all directory objects the device is a member of - Filters results to only include Entra ID groups - Identifies and skips dynamic membership groups (cannot be modified) - Removes the device from all eligible (static) group memberships - Skips non-group objects such as directory roles or administrative units This is useful for: - Device offboarding - Cleanup of legacy or incorrect group assignments - Preparing devices for reassignment or re-enrollment workflows - Maintenance window orchestration scenarios (e.g., kiosk devices) .PARAMETER ObjectID The Entra ID (Azure AD) Object ID of the device. This value is required and must be the GUID of the device object in Entra ID. .EXAMPLE .\Remove-EntraDeviceGroupAssignments.ps1 -ObjectID "381379cd-5c0e-403c-9af7-abbbd90214d9" Removes the specified device from all directly assigned Entra ID groups. .EXAMPLE .\Remove-EntraDeviceGroupAssignments.ps1 -ObjectID (Get-MgDevice -Filter "displayName eq 'KIOSK-01'").Id Resolves a device by name and removes all direct group memberships. .NOTES - Requires Microsoft Graph PowerShell SDK - Requires the following permissions: • Device.ReadWrite.All • Group.ReadWrite.All - Does NOT modify dynamic group memberships - Safe to run multiple times (idempotent behavior) - Intended for administrative and automation use cases .LINK https://learn.microsoft.com/en-us/graph/api/device-list-memberof #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$ObjectID ) Begin { # Ensure required modules if (-not (Get-Module Microsoft.Graph.Authentication -ListAvailable)) { Write-Host "Installing Microsoft.Graph.Authentication" Install-Module Microsoft.Graph.Authentication -Scope CurrentUser -Force } if (-not (Get-Module Microsoft.Graph.Groups -ListAvailable)) { Write-Host "Installing Microsoft.Graph.Groups" Install-Module Microsoft.Graph.Groups -Scope CurrentUser -Force } Import-Module Microsoft.Graph.Authentication Import-Module Microsoft.Graph.Groups # Connect to Graph Connect-MgGraph -Scopes "Device.ReadWrite.All","Group.ReadWrite.All" $context = Get-MgContext Write-Host "Connected to Tenant: $($context.TenantId)" } Process { if ([string]::IsNullOrWhiteSpace($ObjectID)) { Write-Host "ERROR: ObjectID is empty" return } try { $memberships = Get-MgDeviceMemberOf -DeviceId $ObjectID -All } catch { Write-Host "ERROR: Failed to retrieve memberships - $_" return } if (-not $memberships) { Write-Host "No group memberships found for device $ObjectID" return } foreach ($entry in $memberships) { # Only process Entra groups if ($entry.AdditionalProperties['@odata.type'] -ne '#microsoft.graph.group') { Write-Host "Skipping non-group object: $($entry.Id)" continue } # Get group details (to check if dynamic) try { $group = Get-MgGroup -GroupId $entry.Id -Property MembershipRule } catch { Write-Host "Skipping group (unable to retrieve details): $($entry.Id)" continue } # Skip dynamic groups if ($group.MembershipRule) { Write-Host "Skipping dynamic group: $($entry.Id)" continue } Write-Host -ForegroundColor Yellow "Removing device from group: $($entry.Id)" try { Remove-MgGroupMemberByRef ` -GroupId $entry.Id ` -DirectoryObjectId $ObjectID ` -ErrorAction Stop Write-Host -ForegroundColor Green "SUCCESS: Removed from $($entry.Id)" } catch { Write-Host -ForegroundColor Red "FAILED: $($entry.Id) - $_" } } } End { Write-Host "Completed processing for device: $ObjectID" Disconnect-MgGraph } |