Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Click here to return to the 'Show days left until Active Directory password expires' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Show days left until Active Directory password expires
Authored by: timdaman on Oct 03, '06 06:02:44PM

I created this script a couple years ago to do this sort of thing for a group in our domain. We had users who used the domain only for email and they needed warnings to tell them to find a computer to reset their password on. I have blanked out information that may identify the site for security reasons. Enjoy.

#!/usr/bin/perl -w
# This program is designed to run via cron job. It emails users to notify them that password will expire soon.
# This is import because some uses wouldn't otherwise find out until their password expired (such as mail users on the road)
# 7/26/2004 Revision 1.0 By Tim Laurence
# Initial release

use Net::LDAP;
use Mail::Send;

# OK so what do all these vars mean?
# AD stores time as 10 millionth of seconds since Jan 1st, 12:00AM, 1601AD. Why?!?
# Unix stores time as seconds since Jan 1st, 12:00 AM, 1970.
# Thus heavy conversion is needed to get the current time on the local computer and put it into AD time.
# fudge is the number of 10 millionths of a second between 1/1/1601 and 1/1/1970 (this was gathered by
# experimentation and not perfectly accurate. I think there years are aprox 365.25 days long but there may
# be leap seconds). It only needs to be accurate to the day so this is good enough.
# sevenDays is the number of 10 millionths of a second in 7 days. Watch for seasonal time changes.

$fudge = 116444736390271392;
$sevenDays = 6048000000000;

# connect to the LDAP server to gather information
$ldap = Net::LDAP->new( '' ) or die "$@";

$mesg = $ldap->bind( dn => 'cn=mail_ldap,ou=Mail Objects,DC=blank,DC= blank,DC= blank',
password => 'blank'

# die if there was an error above
$mesg->code && die $mesg->error;

# retrieve the maxPwdAge field from the LDAP
$mesg = $ldap->search( base => 'DC= blank,DC= blank,DC= blank',
attrs => 'maxPwdAge',
scope => 'base',
filter => 'distinguishedName=DC= blank,DC= blank,DC= blank'

# die if there was an error above
$mesg->code && die $mesg->error;

# Store the result in a standard scalar
# get the first result return by the ldap search
$entry = $mesg->entry(0);

# get the MaxPwdAge attribute from the entry extracted above
# It is the number of 10 millionths of a second old a password is allowed
# to get before it expires. For some reason this value is negative.
@maxPwdAgeArray = $entry->get_value( 'maxPwdAge' );
$maxPwdAge = $maxPwdAgeArray[0];

# get the current time in unix time format
$now = time();

# multiple that value by 10 million and the add the fudge factor, this puts it in AD/Windows format
$now = ($now * 10000000) + $fudge;

# These value help us make a range with-in which passwords will soon expire.
# We want passwords that will expire in the next seven days but not ones that have already
# expired since people whose password expired already can't read their mail, thus no use in pestering them.

# Calculate the value of a pwdLastSet that would expire right now

$expNow = $now + $maxPwdAge;

# Calculate the value of a pwdLastSet that would expire in seven days
$expInSevenDays = $expNow + $sevenDays;

# get list of user for whom to check password expiration
$mesg = $ldap->search( base => 'OU=Mail Objects,DC= blank,DC= blank,DC= blank',
attrs => ['member'],
filter => 'CN=MailUsers'

# die if there was an error above
$mesg->code && die $mesg->error;

# Extract the array of mailUsers from the returned object
$entry = $mesg->entry(0);
@members = $entry->get_value( 'member' );

# create a new message sending object
$msg = new Mail::Send;

# set reply to address
$msg->add('Reply-To', '"HelpDesk" <helpdesk@ blank. blank. blank >');
$msg->add('From', '"HelpDesk" <helpdesk@ blank. blank. blank >');

# for each mailUser
foreach $member (@members)
# get that mail user's username and time they last set their password
$mesg = $ldap->search( base => "$member",
attrs => ['pwdLastSet', 'sAMAccountName', 'userAccountControl'],
filter => "distinguishedName=$member"
# die if there was an error above
$mesg->code && die $mesg->error;

# get the returned user entry from the returned search item
$entry = $mesg->entry(0);
# extract from the entry all the pwdLastSet values (should be and we assume only be one)
@pwdLastSet = $entry->get_value( 'pwdLastSet' );
# extract from the entry all the sAMAccountName(their username) values (should be and we assume only be one)
@sAMAccountName = $entry->get_value( 'sAMAccountName' );
# extract from the entry all the userAccountControl (attributes of their domain account such as if it is subject to password expiration) values (should be and we assume only be one)
@userAccountControl = $entry->get_value( 'userAccountControl' );

# if the pwdLast value is older than the cutoff for passwords that expire in seven days but
# but hasn't expired yet and don't have the "Never expire" flag set in their AD account
if (($pwdLastSet[0] < $expInSevenDays) and ( $pwdLastSet[0] > $expNow ) and !( $userAccountControl[0] & 0x10000 ) )
# send them a warning
$howLong = int( ( ( $pwdLastSet[0] - $expNow ) / 10000000 ) / 86400 );

# Define the subject lines used in emails
$normalSubject = "Password expires in $howLong day(s)";
$critSubject = "Warning: Password expires TODAY!!";

# put pretty dates in the email message so it is easy for our users to read
$day = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday)[(localtime)[6]];
$month = (January,February,March,April,May,June,July,August,September,October,November,December)[(localtime)[4]];
$mday = (localtime)[3];
$year = 1900 + (localtime)[5];

# set the out going username to current user

# if the password expires today email with a more worrisome subject line
if ( $howLong == 0 )
} else {

# start a new email with vars defined above
$fh = $msg->open;

# Put the body into the email
print $fh <<"END";
This is an automatic message sent on $day, $month $mday $year

Your password is due to expire in $howLong day(s). When it expires you will lose access to your \@ blank. blank. blank email until the password is changed. You may change it before this happens by logging to one of the many desktop computers in the blank blank at which point you should be prompted to change your password.

If there any questions or problems please don't hesitate to call. Have a great day.

blank blank HelpDesk
helpdesk\@ blank. blank. blank,

$fh->close; # complete the message and send it

# clean-up, clean-up, every body every where. ;)
$mesg = $ldap->unbind; # take down session

[ Reply to This | # ]