Powershell Query to automate Disabling AD accounts not logged for 40 days

Hi Guys,

I am trying to automate the following task in DC server via Task Scheduler.

  1. Find the ad users who have not logged in for more than 40 days before 2023, disable them and move to the Disabled User OU. The Service Accounts filtered by the Description are excluded from the query. (Currently I manually check the Service Accounts from the csv file and exclude)

Currently I use a manual process with 3 queries as shown below:

i) Found AD account users via Powershell and get the list to a csv file.

 $inactivity = New-TimeSpan -Days 40
Search-ADAccount -UsersOnly -AccountInactive -TimeSpan $inactivity | Export-Csv C:\Disable.csv

ii) Import that file to Powershell and disable those accounts

Import-Module ActiveDirectory 
Import-Csv "C:\Disable.csv" | ForEach-Object { $samAccountName = $_."samAccountName" Get-ADUser -Identity $samAccountName | Disable-ADAccount}

iii) Find those disable users and move them to the Disabled OU.

Search-ADAccount -AccountDisabled | Where {$_.DistinguishedName -notlike “*OU=Disabled Users*”} | Move-DObject -TargetPath “OU=Disabled Users,OU=User Accounts,OU=Microsoft,DC=ms,DC=com”

Could you please help to form a single powershell query that I can add to Task Scheduler? Many thanks in advance.

I have developed a query but it does not work, can someone point me out where I am wrong?

Import-Module ActiveDirectory

$OU         = "OU=Test,OU=User Accounts,OU=Google,DC=google,DC=com"
$inactivity = New-TimeSpan -Days 40
$DirPath     = "C:\Temp\ADAM"
$LogFile     = $DirPath + "\" + "Disable_and_Move_User_Accounts.log"

$userlist=Search-ADAccount -UsersOnly -AccountInactive -TimeSpan $inactivity |Where-Object ($_.description -Notlike "*Service Account*")

Start-Transcript -path $LogFile

ForEach ($users in $userlist){
        If ($users.distinguishedName -like "*$OU=Test,OU=User Accounts,OU=Goole,DC=carbonrev,DC=com*"){
            $desc="Disabled on $(Get-Date) for being inactive - $($users.Description)"
            Set-ADUser $users -Description $desc -Enabled $false
            Move-ADObject $users -TargetPath $OU=Disabled Users,OU=User Accounts,OU=Google,DC=google,DC=com
            }

else {
     
        echo "All users are active"
                                                                                                                 
}

}
Stop-Transcript

Dark Night,
G’day to the forum. :wave:t3:

It looks like you’ve spend a little effort to create your profile. You even uploaded a profile picture. :+1:t3: Please spend a little more effort and fix the formatting of your code. Like it is now it is hard to distinguish between text and code.

When you post code, sample data, console output or error messages please format it as code using the preformatted text button ( </> ). Simply place your cursor on an empty line, click the button and paste your code.

Thanks in advance

How to format code in PowerShell.org 1 <---- Click :point_up_2:t4: :wink:

(Sometimes the preformatted text button hides behind the setting gear :point_up_2:t4: :wink: )

Hi @Olaf,

Thank you for the warm welcome and appreciation. I have just formatted the query as per the guidance you provided, which is really helpful.

Could you please help me correct the script for me to add it to Windows Task Scheduler?

Thank you.

There were a couple of things

  • Checking a users OU location with a if, the query has a SearchBase to only search a specific OU, not all of AD.

  • The TargetPath for Move-ADUser had a $ in it, should just be a path as a string.

  • When you do a loop, keep it singular (e.g. $user). The loop is looping against a collection, which would be plural. When someone sees $users in the loop, it’s confusing since your changing a single item with that token.

  • Another option for searching is Get-AdUser as it can filter for the description criteria as well. Do as much filtering in AD (general terms, it’s called filtering Left) so the script is not pulling 1000 records and then filtering client side to get to 10 records. For this, it’s fine as I’m sure there will not be too many Service Accounts, but in an ideal world $userList would only contain users that are required in the script.

Here is a cleaned up and untested script for reference. Note that -WhatIf is placed on the Set and Move command to make sure the script does what you want before you take action on any accounts by mistake:

Import-Module ActiveDirectory

$LogFile     = "C:\Temp\ADAM\Disable_and_Move_User_Accounts.log"
$DisabledOU  = 'OU=Disabled Users,OU=User Accounts,OU=Google,DC=google,DC=com'

$searchAdParams = @{
    SearchBase      = "OU=Test,OU=User Accounts,OU=Google,DC=google,DC=com"
    UsersOnly       = $true
    AccountInactive = $true
    TimeSpan        = New-TimeSpan -Days 40
}

$userlist = Search-ADAccount @searchAdParams | 
                Where-Object ($_.description -Notlike "*Service Account*")

Start-Transcript -path $LogFile

if ($userList) {
    ForEach ($user in $userlist){
        $desc = "Disabled on $(Get-Date) for being inactive - $($user.Description)"

        try {
            Set-ADUser -Identity $user -Description $desc -Enabled $false -ErrorAction Stop -Whatif
            Move-ADObject -Identity $user -TargetPath $DisabledOU -ErrorAction Stop -WhatIf
        }
        catch {
            'Error occured updating account {0}.  {1}' -f $user.SamAccountName, $_
        }

    }
}
else {
    "No users met the search criteria."
}


Stop-Transcript
1 Like

Hi @rob-simmers ,

Thank you for the refined transcript. It is mostly what I wanted. However, it does not capture users. It says “No users met the search criteria”. I think the searchAdParams not working.

I took your query, modified and inserted the “$userlist=…” with my own created part. It worked except for capturing the accounts that are inactive for more than 40 days. Instead, it disabled all the enabled users whose description is not set to “Service Accounts” Because I don’t know how to pass multiple parameters in that section.

Could you please help me to fix this section?

I want to make this section capture the Ad user accounts that are inactive for more than 40 days.

$userlist = Get-ADUser -SearchBase "OU=Test,OU=User Accounts,OU=Google,DC=google,DC=com" -Filter 'enabled -eq $true' -Properties * |Where-Object {($_.description -Notlike "*Service Account*")}

Thank you for your help.

The query is a pretty common ask, so there should be many results with examples:

How to Find Inactive Users in Active Directory using PowerShell (netwrix.com)

Before putting Set or Move or Remove cmdlets, best practice is to make sure the query is only returning what you want to change. Even the query is adjusted, I would add -WhatIf and only run the query section to validate the query is working without running the entire script.

1 Like