Finding Users Whose Accounts Are About to Expire






Finding Users Whose Accounts Are About to Expire

Problem

You want to find users whose accounts are about to expire.

Solution

Using Perl
	# This code finds the user accounts that are about to expire.
	# ------ SCRIPT CONFIGURATION ------ 
	# Domain and container/OU to check for accounts that are about to expire
	my $domain = '<DomainDNSName>'; ' e.g. amer.rallencorp.com
	my $cont = ''; # set to empty string to query entire domain
	               # Or set to a relative path in the domain, e.g. cn=Users
	# Number of weeks until a user will expire
	my $weeks_ago = 4;
	# ------ END CONFIGURATION --------

	use strict;
	use Win32::OLE;
	    $Win32::OLE::Warn = 3;
	use Math::BigInt;

	# Need to convert the number of seconds until $weeks_ago
	# to a large integer for comparison against accountExpires
	my $future_secs = time + 60*60*24*7*$weeks_ago;
	my $intObj = Math::BigInt->new($future_secs);
	   $intObj = Math::BigInt->new($intObj->bmul('10 000 000'));
	my $future_largeint =
	           Math::BigInt->new($intObj->badd('116 444 736 000 000 000'));
	   $future_largeint =~ s/^[+-]//;

	# Now need to convert the current time into a large integer
	    $intObj = Math::BigInt->new( time );
	    $intObj = Math::BigInt->new($intObj->bmul('10 000 000'));
	my $current_largeint =
	            Math::BigInt->new($intObj->badd('116 444 736 000 000 000'));
	   $current_largeint =~ s/^[+-]//;

	# Set up 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 name.
	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 .= "( 
accountExpires<=$future_largeint)";
	$query .= "(accountExpires>=$current_largeint)";
	$query .= "(!accountExpires=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 whose account will expire in $weeks_ago weeks or less:\n";
	my $total = 0;
	while (!($resObj->EOF)) {
	   print "\t",$resObj->Fields("distinguishedName")->value,"\n";
	   $total++;
	   $resObj->MoveNext;
	}
	print "Total: $total\n";

Discussion

The code to find expiring user objects is very similar to that of Recipe 6.28 for finding expiring passwords. The main difference is that instead of querying the pwdLastSet attribute, you need to query accountExpires.Also, instead of setting accountExpires to a timestamp in the past as you did for pwdLastSet, it needs to contain a future timestamp for when accounts will expire. This makes the logic only slightly different. Let's break down the search filter and review the other differences.

This part of the filter finds all enabled user objects:

	$query .= "(&(objectclass=user)";
	$query .= "(objectcategory=Person)";
	$query .= "(!useraccountcontrol:1.2.840.113556.1.4.803:=2)";

This next part finds only the accounts that are going to expire. The second line prevents all currently expired accounts from being returned.

	$query .= "(accountExpires<=$future_largeint)";
	$query .= "(accountExpires>=$current_largeint)";

The last part of the filter excludes users that are marked to never expire:

	$query .= "(!accountExpires=0));";

See Also

Recipe 6.28 for more on large integer manipulation, Recipe 6.30 for setting a user's account to expire, and MS KB 318714 (How to Limit User Logon Time in a Domain in Windows 2000)



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows