Keeping Active Directory secure and tidy with PowerShell: Identifying stale accounts

Maintaining a clean and secure Active Directory (AD) environment is essential for ensuring the safety and efficiency of your organisation’s network. Regularly identifying and managing stale accounts, those that haven’t been used in a long time, helps mitigate security risks, reduce clutter, and streamline user management.

In this article, we’ll walk through a PowerShell script designed to automate the identification of such accounts and discuss how it can help keep your AD environment secure and organised.

We’ll also highlight key considerations, including its behaviour in Office 365 hybrid environments, and other potential issues to watch out for.

Understanding the PowerShell script

The PowerShell script below is specifically designed to search for user accounts in Active Directory that have not been used in the last 180 days. By analysing the LastLogonTimestamp attribute, it identifies potentially stale or unused accounts that may need to be reviewed, disabled, or removed.

PowerShell
# Set the date to 180 days ago from today
$d = [DateTime]::Today.AddDays(-180)

# Retrieve enabled users and filter those with PasswordLastSet or LastLogonTimestamp older than $d
Get-ADUser -Filter "Enabled -eq 'True'" -Properties PasswordLastSet, LastLogonTimestamp |
    Where-Object {
        ($_.LastLogonTimestamp -and ([datetime]::FromFileTime($_.LastLogonTimestamp) -lt $d))
    } |
    Format-Table Name, PasswordLastSet, @{
        Name       = "LastLogonTimestamp"
        Expression = { if ($_.LastLogonTimestamp) { [datetime]::FromFileTime($_.LastLogonTimestamp) } else { "Never" } }
    }

How does this script work?

  1. Define the reference date:
    • The script first defines a reference date set to 180 days prior to today ($d). This date acts as a threshold to determine which accounts are considered inactive.
  2. Retrieve enabled user accounts:
    • It uses the Get-ADUser cmdlet with a filter to only retrieve accounts that are enabled (Enabled -eq 'True') and includes additional properties like PasswordLastSet and LastLogonTimestamp.
  3. Identify stale accounts:
    • The script then checks if the LastLogonTimestamp is older than 180 days. If the condition is met, the account is flagged as a candidate for review.
  4. Format and display the uutput:
    • The results are formatted into a table showing each account’s name, the date the password was last set, and the last logon timestamp. If there is no LastLogonTimestamp (indicating the account has never logged on), the script displays “Never” instead.

Why is this script useful for Active Directory security?

  1. Reduces security risks:
    • Stale accounts are high-risk targets for attackers, as they are often overlooked and may still have valid permissions. These accounts can become entry points for malicious actors, who might exploit them for lateral movement or privilege escalation.
  2. Improves AD hygiene and compliance:
    • Regularly identifying and managing inactive accounts helps maintain a cleaner AD structure. This is beneficial for compliance with regulatory standards, such as GDPR and SOX, which require periodic reviews of access permissions and user activity.
  3. Streamlines management:
    • By removing or disabling unnecessary accounts, the script helps simplify day-to-day management tasks, making it easier for administrators to focus on active and essential users.
  4. Automates routine maintenance:
    • Manually checking for inactive accounts in a large AD environment is impractical. This script automates the process, making it quick, reliable, and easy to repeat on a regular schedule.

Considerations for Office 365 and hybrid environments

While this script works well in traditional on-premises AD environments, there are some important considerations to be aware of if your AD is synchronised with Office 365 or Azure AD.

  1. Office 365 and LastLogonTimestamp:
    • If a user’s account is synchronised with Office 365 and is only used for cloud services (such as accessing Outlook or SharePoint), the LastLogonTimestamp in the on-premises AD will not update. This means that a user might appear inactive when, in reality, they are actively using Office 365 services.
  2. Cross-Referencing Cloud Activity:
    • For hybrid environments, cross-reference the results with Azure AD logs or use tools like Azure AD Connect Health to ensure you have an accurate picture of user activity. You may also consider using Azure AD PowerShell cmdlets to gather last logon information directly from the cloud.

Other things to watch out for

  1. Limitations of the LastLogonTimestamp Attribute:
    • The LastLogonTimestamp attribute is only updated periodically (roughly every 14 days by default), so it might not reflect the most recent logon activity. Consider using the more accurate LastLogon attribute, though it requires querying each domain controller individually.
  2. Service and shared accounts:
    • Many service and shared accounts rarely log on interactively but are still in use. Ensure you identify and exclude these accounts from the script, as disabling them could disrupt services.
  3. Accounts with infrequent usage patterns:
    • Some users, such as contractors or remote staff, may log on infrequently. Double-check these accounts before taking action to avoid unnecessary lockouts or disruptions.
  4. Check PasswordLastSet as an alternative metric:
    • The script includes the PasswordLastSet property, which can be useful in identifying accounts that haven’t changed their passwords in a long time. This is another indicator that an account may be stale, especially if LastLogonTimestamp is unreliable.

Recommendations for safe implementation

  1. Run the script as a guide first:
    • Run the report, and investigate each user first before taking action.
  2. Create a backup of your AD environment:
    • Always back up critical AD data before performing bulk modifications. Use tools like Windows Server Backup or Azure Backup for domain controllers.
  3. Use scheduled reporting:
    • Schedule this script to run monthly or quarterly as part of your AD maintenance routine. Set it to email a report to AD administrators for review, rather than taking automatic action.

Final Thoughts

Maintaining a secure and organised Active Directory environment is a continuous process that requires regular attention and the right tools. This PowerShell script is a powerful addition to your toolkit, enabling you to identify and address stale accounts quickly and efficiently.

However, as with any automated solution, it’s important to understand its limitations and behaviour, especially in hybrid environments with Office 365. Implement this script with caution, cross-check the results, and use it as part of a broader AD security and management strategy.

If you’d like more useful scripts, please comment below.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.