2

When somebody leaves my organization, we remove all AD group memberships apart from the PrimaryGroup which is Domain Users. We often process these in batches, so pull the affected usernames from a CSV file.

I have the following code, and while it does the job of deleting all group memberships, I get an error for each user:

The user cannot be removed from a group because the group is currently the user's primary group

Whilst it does the job, how can I "clean up" the process to avoid this message each time? Is there a way to exclude Domain Users from the groups it removes the user from, or should I do this another way?

$users = Import-Csv "c:\temp\leavers.csv"

foreach ($user in $users) {

Get-ADPrincipalGroupMembership -identity $user.username | foreach {Remove-ADGroupMember $_ -Members $user.username -Confirm:$false}

}
codewario
  • 19,553
  • 20
  • 90
  • 159
  • I don't think it's worthy as an answer for this scenario since you may not always want to swallow a group removal error (and there are better solutions), but you can generally suppress error dialog with [redirection](https://stackoverflow.com/a/56263863/584676) or by [setting the error action](https://stackoverflow.com/a/58828208/584676). – codewario Apr 19 '22 at 16:23

3 Answers3

2

You can use Where-Object for filtering those groups that are not in an array of groups to exclude. In case you only want to filter for 1 specific group, you would use -NE instead of -NotIn in below example.

$groupToExclude = 'Domain Users', 'someOtherGroup'
$users = Import-Csv "c:\temp\leavers.csv"
foreach ($user in $users) {
    try {
        Get-ADPrincipalGroupMembership -Identity $user.username | 
            Where-Object Name -NotIn $groupToExclude |
                Remove-ADGroupMember -Members $user.username -Confirm:$false
    }
    catch {
        Write-Warning $_.Exception.Message
    }
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    An exclusion group is a good suggestion, but does not cover the case when different users have different primary group. It seems the goal here is to remove group membership which are not the principal's primary group. – codewario Apr 19 '22 at 15:39
  • 1
    Whilst I agree with Bender's comment, this solution is fine for my particular scenario where all users in the Domain have the same Primary Group. Thanks! – surloid9000 Apr 19 '22 at 15:47
  • That's why I still said it's a good suggestion. It is very common, particularly in domains which don't include Unix/Linux members, that the `PrimaryGroup` never needs to be changed from the default `Domain Users`. But I wanted to point out that this will still throw errors in environments where the `PrimaryGroup` of all users is not consistent. – codewario Apr 19 '22 at 15:49
  • 1
    @BendertheGreatest agreed, but since OP was only referring to `Domain Users` I thought this was more than enough. – Santiago Squarzon Apr 19 '22 at 16:06
1

If you get the ADUser object before the ADGroup memberships, you can get the PrimaryGroup of the user and ensure that the list of groups to remove from are not its PrimaryGroup:

$users = Import-Csv "c:\temp\leavers.csv"

foreach ($user in $users) {
  $primaryGroup = ( Get-ADUser $user.UserName -Properties PrimaryGroup ).PrimaryGroup
  
  Get-ADPrincipalGroupMembership -Identity $user.UserName | Where-Object {
    $_ -ne $primaryGroup
  } | ForEach-Object {

    Remove-ADGroupMember $_ -Members $user.username -Confirm:$False -WhatIf
  }
}

Since this has the potential to be a very destructive command, I have included a safeguard in the example above. Remove the -WhatIf parameter from Remove-ADGroupMember to actually perform the removal.

codewario
  • 19,553
  • 20
  • 90
  • 159
  • thank you so much for this - as all users have the same primary group I can define $primaryGroup with the absolute value but the code has done what I need. Thanks! – surloid9000 Apr 19 '22 at 15:50
1

I'd propose a slightly different approach - just drop Get-ADPrincipalGroupMembership altogether. For example:

$users = Import-Csv -Path c:\temp\leavers.csv
foreach ($user in $users) {
    # Assuming DN is not in the csv...
    $distinguishedName = (Get-ADUser -Identity $user.UserName).DistinguishedName
    Get-ADGroup -LdapFilter "(member=$distinguishedName)"
    # Alternatively, just pipe memberOf property to Get-ADGroup...
    (Get-ADUser -Identity $user.UserName -Property MemberOf).MemberOf |
        Get-ADGroup
}

That way you don't have to filter out something you insisted on getting (by using above mentioned cmdlet).

BartekB
  • 8,492
  • 32
  • 33