Link to home
Start Free TrialLog in
Avatar of samiam41
samiam41Flag for United States of America

asked on

Add delete function into existing stale account PowerShell script

Greeting Experts!  I'm including the existing script that I'm using to clean up my AD environment and now need to tweak it to include the ability to delete accounts that haven't logged in for at least 120 days.  The first part of the script audits the users accounts and if they haven't logged in for 60 days, disables them and moves them to the "Inactive OU".  I need the new portion of the script to just check the "Inactive OU" for accounts to be deleted.  When the account is deleted, I need to have the date logged when the last time the account logged in.  

Thank you for your help Experts!

# Stale user accounts 

Import-Module ActiveDirectory

$logPath = "C:\Tools\Scripts\Stale_Accounts\Logs\Stale_Users_"  #directory to log output
$Date = Get-Date
$TodaysLog = $logPath + $Date.ToString('yyyy_MM-dd_HHmm') + ".log"
$FilterDate = $Date.AddDays(-49)

Function WriteLog($message) {
    $message = (Get-Date).ToShortTimeString() + " - " + $message
    Add-Content -Path $TodaysLog -Value $message
}

$disabledOU = "OU=Users,OU=Inactive,DC=local"

$StaleUsers = Get-ADUser -SearchBase "OU=Depts,DC=local" -Filter * -Properties SAMAccountName, lastLogonTimeStamp |
    Where-Object {[DateTime]::FromFileTime($_.lastLogonTimeStamp) -lt $FilterDate} 

If ($StaleUsers) {
    ForEach ($User in $StaleUsers) {
        try {
            Disable-ADAccount -Identity $User.DistinguishedName -ErrorAction Stop
            WriteLog -Message "Disabled $($User.SAMAccountName)"
        } catch {
            WriteLog -Message "Failed to disable $($User.SAMAccountName): $($_.Exception.Message)"
        }
    
        try {
            Move-ADObject -Identity $User.DistinguishedName -TargetPath $disabledOU -ErrorAction Stop
            WriteLog -Message "Moved $($User.SAMAccountName) from $($User.DistinguishedName)"
        } catch {
            WriteLog -Message "Failed to move $($User.SAMAccountName) to $($disabledOU): $($_.Exception.Message)"
        }
    }
} Else {
	WriteLog -Message "No stale user accounts found."
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Dustin Saunders
Dustin Saunders
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
*Just a note, i edited the above block so please refresh to up to date version.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of samiam41

ASKER

I appreciate the suggestions experts.  With both scripts, I wasn't able to get a user account that I know is very stale to be deleted.  I'm trying to check the lastlogon date now of that user account so I know if it is just my bad memory of the accounts age or if I need to troubleshoot the script.
Much like the "no stale user accounts found" entry added to the log file, can I add a "no accounts to delete" entry?  @Jason Crawford, how can I do this?  @Dustin Saunders, I got it to work for your script.
LastLogonDate for the two accounts:

UserA- 11/1/2012 2:20:44 PM
UserB- 11/16/2016 3:01:05 PM

Neither account is being deleted (which should be).
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Like this? >> Remove-ADUser -Identity $user.DistinguishedName  -Confirm:$false -ErrorAction Stop

I added that line and get (no accounts to delete) in the log file with neither of those accounts deleted.

if ($deleteUsers){
    foreach($user in $deleteUsers){
        try {
            Remove-ADUser -Identity $user.DistinguishedName -Confirm:$false -ErrorAction Stop 
            WriteLog -Message "Deleted user $($user.SAMAccountName), last logon date was $($user.lastLogonTimeStamp)"
        } catch {
            WriteLog -Message "Failed to delete $($User.SAMAccountName): $($_.Exception.Message)"
        }
    }
} Else {
	WriteLog -Message "No accounts to delete."
}

Open in new window

Figured it out.  Line #42 of Dustin Sanders script
 Where-Object {[DateTime]::FromFileTime($_.lastLogonTimeStamp) -lt $DeleteFilter}

Open in new window

, I had to change the $DeleteFilter to $FilterDate.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Dustin for the help, time and guidance on this one!  This script ended up being a pretty useful and power resource for my environment.  I'm sure others will find it equally beneficial as well.
Good morning Experts.  I closed this question out without giving enough thought to the new user concern brought up by Jason Crawford.  Well, as soon as I took this script out of the testing world and ran it in the prod world, I wiped out two new user accounts the helpdesk had just created.  With that lesson learned just 10 minutes in, I immediately modified the script.  Thus, Jason deserves some credit in the end product.  I've asked the mods to modify the points so that Jason gets 200 and Dustin gets 800.  I believe that to be only fair.  Thanks again Experts.
Sorry for the confusion experts but I wanted to make sure everyone received credit for the contribution to the final, solid product.  Your time and input was much appreciated and I look forward to working with you all again.
@Dustin, in line 9 in the script of the answer I accepted, $DelteFilter is spelled wrong which is why I had to take it out to make the script work.  Took me awhile to figure it out but that's the reason if anyone else can't make it work.  Happy Holidays!
Thanks for circling back around and posting an update.
I figured you took the time and energy to work with me and find a solution that I (and all those after me) could use.  It's a solid solution and I'm sure others will find it equally helpful.  I didn't want them to bail on it because of that one part.