Removing Disabled Users from Membership of Groups in Active Directory

Lets discuss about a scenario where one needs to perform housekeeping on the groups inside AD on a routine basis, so that they are free of disbaled or deleted members. In every organisation, after a user is offboarded, its remnants linger as memberships of groups. Hence out of many reasons, the group memberships should be accurate and current.

When was the account last modified?

Now while drafting a strategy, we must keep in mind that some users are offboarded on a temporary basis or some users may be hired back after a brief period of time. So removing memeberships of these users will create an administrative overhead later, hence it is better to not remove their memberships in first place. This can be done to some extent by making user of WhenChanged attribute of a user account object fetched by get-aduser query.

Where are the disabled user accounts kept?

Next we might also have a special OU to hold all the disabled users, which we can use as a searchbase in get-aduser query or filter distinguished names of members of get-adgroupmember query.

Method 1:

The breakdown of the method is explained in points below.

1> We start with groups in AD. And recursively every group member is searched.

2> Now as per our requirement, we match with below requirement set:    

  • The user should be disabled
  • The user account should not have been modified in a certain period from now.
  • The user account should be residing in a certain OU.

3> After the search has been narrowed, we proceed to removal of these users from corresponding all group memberships.

4> A log file can also be generated for reference.

Import-Module ActiveDirectory

$OutFile = "C:\DisabledUserMembership_ $(get-date -f yyyy-MM-dd).csv"

#Recursively searches for all groups in the domain and displays on screen.
foreach ($group in (Get-ADGroup -Filter *)) {
 Write-Host $group.Name -Foreground "green";

#For each group, members are checked recursively if they are member of OU= .
 foreach ($member in (Get-ADGroupMember -Identity $group)) {
 if ($member.objectClass -eq "user" -and ($member.distinguishedName.Contains("OU= ,OU= ,DC= ,DC= "))) {

#Now it will further shortlist only those users which have not been changed in 3 months from today, which can be modified as per need.
 $date = ((get-date).addmonths(-3))
 $user = Get-ADUser -Identity $member.distinguishedName -Properties whenChanged| Where-Object {$_.whenChanged -le $date}

#Now it will check if above shortlisted users are disabled currently and then remove group membership and display user's name too.
 if ($user.enabled -eq $false) {
 Write-Host $user.Name
 Remove-ADGroupMember -Identity $group -Members $user -Confirm:$false
$OutInfo = $user.name + ";" + $group.name

Add-Content -Value $OutInfo -Path $OutFile
   }
  }
 }
}

Method 2:

A different approach than the one expained above and I personally like this one better.

1> We start with all users in AD.

2> Then we refine the users fetched by matching with our three requirements mentioned before.

3> After the search has been narrowed, we proceed to removal of these users from corresponding all group memberships.

4> A log file can also be generated for reference, like before

Import-Module ActiveDirectory
$OutFile = "C:\DisabledUserMembership_ $(get-date -f yyyy-MM-dd).csv"
$date = ((get-date).addmonths(-3))
$SearchBase = "OU= ,OU= ,DC= ,DC= "
$Users = Get-ADUser -filter * -SearchBase $SearchBase -Properties MemberOf,whenChanged| Where-Object {$_.whenChanged -le $date}

Foreach ($User in $Users){
 If ($User.enabled -eq $false){
#Memebrof attribute of user object gives the group names, 
#which the account is member of.
 $Groups = $User.MemberOf
 Foreach ($Group in $Groups){
 $OutInfo = $User.sAMAccountName + ";" + $Group
 #Display the output on screen.
 $OutInfo
 #Append the output to the out file.
 Add-Content -Value $OutInfo -Path $OutFile
 }
 #Remove the user from all groups it is a member of.
 $User.MemberOf | Remove-ADGroupMember -Member $User -Confirm:$false 
 }
}

Now as it can be seen that the second method looks more sleek, hence may prove to be a better solution to our requirement.

Now this script can be scheduled to run on a daily basis in task scheduler to keep the group memberships fresh.

Leave a comment