Sup pshhomies? A colleague of mine Martijn Monshouwer was getting his PowerShell on when he ran into a little snag. A little birdie told him to run his script by me, which he did! “Dear PowerShell…” You had me at PowerShell… 🙂 Incidentally starting any email with PowerShell is a good way to get my attention.

The script is suppose to:

  • find user account(s) past expiration date
  • disable the user account(s)
  • move account(s) to a specific OU
  • clear the user group membership, all but three groups

Martijn did the grunt work. All that was missing was the remove group membership. I learned my lesson not to overwhelm but assist, so no rewriting entire scripts! At that time I was right in the middle of a migration, but hey, it’s PowerShell and Martijn was clever enough to appease my ego… Now how could I say no eh? 😉

I did a quick scan… “Read-Host… Yeah… let’s make that a parameter”. “Write-Host… Better change that to Write-Verbose lest we incur the wrath of Don Jones…” Ok Urv remember, no rewriting… (Well maybe just a little… old habits die hard…)

So here’s the end result:

<#

Author: M. Monshouwer / I. Strachan
Version: 1.0
Version History: N/A

Purpose:  Get expired AD accounts that are not disabled and move to disabled OU

          .\Move-ExpiredDisabledUserToDisableOU –Verbose

#>

[CmdletBinding()]
param(
    [string]$ChangeNumber='12345',

    [string]$Initials='I.S'
)

# Import Active Directory module
Import-Module ActiveDirectory -Verbose:$false

#region: Define variables
#Get expired AD accounts that are not disabled
Write-Verbose 'Searching for accounts that are enabled but expired...'
$ExpiredAccountsNotDisabled = Search-ADAccount -AccountExpired | Where-Object { $_.Enabled -eq $true }
Write-Verbose "Found $(@($ExpiredAccountsNotDisabled).count) that meet criteria"

#Define groups that will NOT be removed, Use the DistinguishedName
$ExcludedGroups = @(
'CN=GroupX,OU=Groups,OU=Resources,DC=pshirwin,DC=local'
'CN=GroupY,OU=Groups,OU=Resources,DC=pshirwin,DC=local'
)

#Define OU for Disabled Accounts. Change to reflect your OU
$DisabledAccountsOU = 'OU=Disabled,OU=Users,OU=IPI,DC=pshirwin,DC=local'

#Get current date
$Date = Get-Date -Format g
#endregion

#Loop through Expired Users
ForEach($User in $ExpiredAccountsNotDisabled) {
  Write-Verbose "Processing user $($user.SamAccountName) group membership"
  #Get User Group Membership
  $userMembership = Get-ADUser $user.SamAccountName -Properties MemberOf | Select-Object -ExpandProperty memberof
  Write-Verbose "User membership count: $(@($userMembership.Count))"

  foreach($member in $userMembership) {
    # Remove User Group membership
    if (!$ExcludedGroups.Contains($member)){
      try{
        Write-Verbose "Removing user $($User.SamAccountName) from $($member)"
        Get-ADGroup $member | Remove-ADGroupMember -Members $user.SamAccountName -Confirm:$false
      }
      catch{
        Write-Error "Something went wrong removing $($User.Name) from `'$member`'"
      }
    }
  }

  #Process user further
  try{
    # Write Description & Disable Account
    Write-Verbose "Setting user's Description to: `"Disabled $Date; $ChangeNumber; $Initials`""
    Set-ADUser -Identity $User.SamAccountName -Description "Disabled $Date; $ChangeNumber; $Initials" -Enabled $false
    # Move user to OU for Disabled Accounts
    Write-Verbose 'Moving user to Disabled OU'
    Get-ADUser -identity $User.SamAccountName | Move-ADobject -targetpath $DisabledAccountsOU
  }
  catch{
    Write-Error "Something went wrong processing `'$($User.DistinguishedName)`'"
  }
}

Martijn was quite happy with his script! Welcome to the club! 😉

While at the gym ( my other favorite past time) I had an epiphany (Sounds more dramatic eh?)
What if you needed to reinstate a user? The user would have to be moved back to the original OU, ReEnabled and be made member of all the groups removed from. Of Course this could be done manually but what’s the fun in that? Oh and some logging would be nice…

So Martijn…

Mission Impossible

Try making your script more resilient. Level up! Learning PowerShell is fun!!!

Ttyl,

Urv

3 thoughts on “Move and disable AD users past expiration date

  1. Jerome Tanberg

    I love this script and wanted to thank you. I was hoping that you could add to it just a little. I do not want to search all of AD for expired accounts. I would like to only search a specific OU for expired accounts. How can I achieve that with this current script?

    Like

    Reply
  2. Jerome Tanberg

    Thank you Irwin! I ended up figuring that part out. Now working on grabbing a log of employees and the groups they were part of in case we need to enable them. This really got me started off well. Thank you so much!

    Liked by 1 person

    Reply

Leave a comment