Skip to main content

How to List All Inactive Users (Stale Accounts) in Batch Script

Identifying accounts that haven't been used for a long period, often called "Stale" or "Abandoned" accounts, is an essential security best practice. These accounts represent a significant "Attack Surface," as they can be compromised without the owner ever noticing. For IT administrators, being able to "List" all users who haven't logged in for a specific number of weeks or days is a mandatory step for regular cleanup and compliance audits.

This guide explains how to use the dsquery utility and the PowerShell bridge to find inactive Active Directory users via Batch.

Why Identify Inactive Users?

  • Security Hardening: Reducing the risk of unauthorized access by identifying and disabling credentials that are no longer in active use.
  • License Optimization: Identifying employees who have left the company or changed roles so their software licenses can be reclaimed.
  • Directory Cleanliness: Maintaining a "Lean" Active Directory that is easy to navigate and audit for security groups.
Tool Availability

The dsquery command is part of the Remote Server Administration Tools (RSAT). It must be installed on your workstation to perform this audit across your domain.

Method 1: Using DSQUERY (The Fastest Way)

The dsquery user command has a built-in -inactive flag. Note that this tool measures time in Weeks, not days.

@echo off
setlocal

:: Check for RSAT tools
where dsquery >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] dsquery.exe not found. Install RSAT tools first.
echo [HELP] Settings ^> Apps ^> Optional Features ^> Add RSAT
pause
exit /b 1
)

set "WEEKS=4"

echo [PROCESS] Searching for users inactive for %WEEKS% weeks or more...
echo.

dsquery user -inactive %WEEKS%

echo.
echo [DONE] Any Distinguished Names listed above are inactive accounts.
echo [NOTE] If no output appeared, all users are active within the threshold.
pause

Method 2: Detailed "Days" Audit via PowerShell

If you need a more precise audit (e.g., exactly 90 days), the PowerShell bridge is the most reliable tool. You can call it directly from your Batch script.

@echo off
setlocal

set "DAYS=90"

echo [PROCESS] Querying Active Directory for accounts inactive for %DAYS% days...
echo.

:: We use Search-ADAccount for the most accurate 'inactive' check
:: It uses the replicated LastLogonTimestamp attribute
powershell -NoProfile -Command ^
"$inactive = Search-ADAccount -AccountInactive -TimeSpan '%DAYS%.00:00:00' -UsersOnly -ErrorAction SilentlyContinue;" ^
"if ($inactive) {" ^
" $inactive | Select-Object Name, SamAccountName, LastLogonDate, Enabled |" ^
" Sort-Object LastLogonDate |" ^
" Format-Table -AutoSize;" ^
" Write-Host ('Total inactive accounts: ' + $inactive.Count)" ^
"} else {" ^
" Write-Host '[INFO] No inactive accounts found (or AD module not available).';" ^
" Write-Host '[HELP] Ensure RSAT Active Directory module is installed.'" ^
"}" 2>nul

pause

Creating a Professional Cleanup Auditor

This script generates a timestamped report of every user who hasn't logged in for a specified period, perfect for a monthly security review.

@echo off
setlocal EnableDelayedExpansion

echo ============================================================
echo Active Directory Inactivity Auditor
echo ============================================================

:: 1. Verify RSAT tools
where dsquery >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] RSAT tools not found.
pause
exit /b 1
)

:: 2. Verify Administrative Rights
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [CRITICAL] Admin rights REQUIRED for domain-wide audit.
pause
exit /b 1
)

set "INACTIVE_WEEKS=12"
set "REPORT_DIR=%~dp0StaleAccountAudits"
if not exist "!REPORT_DIR!" mkdir "!REPORT_DIR!"
set "REPORT_FILE=!REPORT_DIR!\Stale_Users_%COMPUTERNAME%_%date:~-4%%date:~-10,2%%date:~-7,2%.txt"

:: 3. Execute Audit
echo.
echo [PROCESS] Scanning for users inactive for %INACTIVE_WEEKS% weeks...

:: Generate report header
(
echo === STALE ACCOUNT REPORT ===
echo Generated: %DATE% %TIME%
echo Computer: %COMPUTERNAME%
echo Threshold: %INACTIVE_WEEKS% weeks of inactivity
echo.
echo === INACTIVE USER ACCOUNTS ===
) > "!REPORT_FILE!"

:: Run the query and capture results
set "FOUND=0"
for /f "tokens=*" %%a in ('dsquery user -inactive %INACTIVE_WEEKS% 2^>nul') do (
echo %%a >> "!REPORT_FILE!"
set /a "FOUND+=1"
)

:: Add summary
(
echo.
echo === SUMMARY ===
echo Inactive accounts found: !FOUND!
echo.
echo === RECOMMENDED ACTIONS ===
echo 1. Review each account with the department manager.
echo 2. Disable confirmed stale accounts (do NOT delete immediately^).
echo 3. Delete disabled accounts after a 30-day grace period.
) >> "!REPORT_FILE!"

:: 4. Display results
echo.
if !FOUND! equ 0 (
echo [SUCCESS] No inactive accounts found. Directory is clean.
) else (
echo [WARNING] Found !FOUND! inactive account(s^).
echo [ACTION] Review the report and consider disabling stale accounts.
)

echo [INFO] Report saved to: !REPORT_FILE!
echo ============================================================
pause

Common Pitfalls and How to Avoid Them

Domain Controller Replication

The "Last Logon" date is not replicated between Domain Controllers. One DC might think a user hasn't logged in for months, while another DC sees them daily.

SEO and UX Tip

Advise your users that for a truly accurate result, they should use the Search-ADAccount cmdlet (Method 2). It checks the LastLogonTimestamp attribute, which is replicated across all servers and is designed specifically for this type of stale-account auditing.

Service Accounts

Some service accounts log in via specific protocols that might not trigger the "Logon" timestamp update in the same way a desktop login does.

Wrong Way:

:: Automatically deleting every 'inactive' user found by the script.

Correct Way: Always Disable the accounts first (dsmod user <DN> -disabled yes) for 30 days. If nobody complains, it is safe to delete them. This provides a "Safety Net" for critical service accounts.

Best Practices for Inactivity Management

  1. Exclude Protected Accounts: Use a naming convention or a specific OU to store accounts (like "Project Admins") that should never be deleted, even if they appear inactive.
  2. Audit the "Never" Logins: Alongside the inactive check, search for accounts that were created but never used. These are often forgotten test or placeholder accounts.
  3. Scheduled Maintenance: Run your audit script as a scheduled task every month and have it email the result to the security team.
User Migration

If your company recently migrated to a new domain, every user will appear "Inactive" on the old domain. Ensure you are targeting the correct, current directory.

Conclusion

Listing inactive users via Batch script is a critical competency for any security-conscious IT professional. By leveraging tools like dsquery and the PowerShell bridge to programmatically identify stale credentials, you can significantly reduce your organization's digital footprint and improve overall system hygiene. This professional approach to system monitoring transforms complex directory data into clear, actionable reports, allowing you to maintain a lean and secure Active Directory across your entire workstation and server fleet.