Finding Users Whose Passwords Are About to Expire

Posted: January 14, 2010 in Active Directory, Networking, Server, System Information
Tags: , ,


Problem

You want to find the users whose passwords are about to expire.

Solution

Using a command-line interface

> dsquery user -stalepwd <NumDaysSinceLastPwdChange>

You can also use the FindExpAcc joeware tool with the following syntax:

> findexpacc -pwd

Using Perl

#!perl

# This code finds the user accounts whose password is about to expire

# —— SCRIPT CONFIGURATION ——

# Domain and container/OU to check for accounts that are about to expire

my $domain   = ‘<DomainDNSName>’;

my $cont     = ”; # set to empty string to query entire domain

# Or set to a relative path in the domain, e.g. cn=Users

# Days since password change

my $days_ago = <NumDaysSinceLastPwdChange> # e.g. 60;

# —— END CONFIGURATION ——–

use strict;

use Win32::OLE;

$Win32::OLE::Warn = 3;

use Math::BigInt;

# Need to convert the number of seconds from $day_ago

# to a large integer for comparison against pwdLastSet

my $past_secs = time – 60*60*24*$days_ago;

my $intObj = Math::BigInt->new($past_secs);

$intObj = Math::BigInt->new($intObj->bmul(’10 000 000′));

my $past_largeint = Math::BigInt->new(

$intObj->badd(‘116 444 736 000 000 000’));

$past_largeint =~ s/^[+-]//;

# Setup the ADO connections

my $connObj                                = Win32::OLE->new(‘ADODB.Connection’);

$connObj->{Provider}                    = “ADsDSOObject”;

# Set these next two if you need to authenticate

# $connObj->Properties->{‘User ID’}    = ‘<User>’;

# $connObj->Properties->{‘Password’}   = ‘<Password>’;

$connObj->Open;

my $commObj                                  = Win32::OLE->new(‘ADODB.Command’);

$commObj->{ActiveConnection}              = $connObj;

$commObj->Properties->{‘Page Size’}    = 1000;

# Grab the default domain naming context

my $rootDSE = Win32::OLE->GetObject(“LDAP://$domain/RootDSE”);

my $rootNC = $rootDSE->Get(“defaultNamingContext”);

# Run ADO query and print results

$cont .= “,” if $cont and not $cont =~ /,$/;

my $query = “<LDAP://$domain/$cont$rootNC>;”;

$query .= “(&(objectclass=user)”;

$query .= “(objectcategory=Person)”;

$query .= “(!useraccountcontrol:1.2.840.113556.1.4.803:=2)”;

$query .= “(pwdLastSet<=$past_largeint)”;

$query .= “(!pwdLastSet=0));”;

$query .= “cn,distinguishedName;”;

$query .= “subtree”;

$commObj->{CommandText} = $query;

my $resObj = $commObj->Execute($query);

die “Could not query $domain: “,$Win32::OLE::LastError,”\n”

unless ref $resObj;

print “\

nUsers who haven’t set their passwd in $days_ago days or longer:\n”;

my $total = 0;

while (!($resObj->EOF)) {

print “\t”,$resObj->Fields(“distinguishedName”)->value,”\n”;

$total++;

$resObj->MoveNext;

}

print “Total: $total\n”;

Discussion

When a Windows-based client logs on to Active Directory, a check is done against the domain password policy and the user’s pwdLastSet attribute to determine if the user’s password has expired. If it has, the user is prompted to change it. In a pure Windows-based environment, this notification process may be adequate, but if you have a lot of nonWindows-based computers that are joined to an Active Directory domain (e.g., Kerberos-enabled Unix clients), or you have a lot of application and service accounts, you’ll need to develop your own user password expiration notification process. Even in a pure Windows environment, cached logins present a problem because when a user logs into the domain with cached credentials (i.e., when the client is not able to reach a domain controller), this password expiration notification check is not done.

The process of finding users whose passwords are about to expire is a little complicated. Fortunately, the new dsquery user command helps by providing an option for searching for users that haven’t changed their password for a number of days (-stalepwd).The downside to the dsquery user command is that it will not only find users whose password is about to expire, but also users that must change their password at next logon (i.e., pwdLastSet = 0).The Perl solution does not suffer from this limitation.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s