Subscribe to Windows IT Pro
January 27, 2009 12:00 AM

Track Active Directory Changes

Use this handy script for do-it-yourself AD auditing
Windows IT Pro
InstantDoc ID #100428
Rating: (8)
Downloads
100428.zip

Where I work, we have a relatively large domain and every day some type of Active Directory (AD) change takes place: new users are added, users are moved from one organizational unit (OU) to another, computers are added, removed, and disabled from the domain, admins leave the company and new ones join—you get the picture. Keeping track of all those changes would be virtually impossible for one person to do manually, but with the help of a script, it's an almost effortless task.

The script I wrote captures a snapshot of specific AD objects such as groups and members of groups and writes the distinguished name (DN) of each object along with a run date and category to an .xml file in the form of an ActiveX Data Objects (ADO) database. (If you’re not familiar with ADO, you might first check out “Rem: Obtaining Data from a SQL Server Database,” InstantDoc ID 25628, and “Introduction to ADO,” InstantDoc ID 98718.) Each subsequent run of the script compares the new database with the previous database. By using a simple compare process, you can detect new AD objects as well as objects that existed in the previous database but aren't present in the new database.

As you'll see, I structured this script to query specific groups, but you can add your own queries within the code fairly easily and start keeping tabs on the objects of your choice. The script does cover a wide range of AD objects and should provide you with useful and comprehensive reports.

The script helps you monitor general AD activity, and, more importantly, it's a valuable tool that you can use to spot new accounts or missing accounts that were added to or removed from security groups such as Enterprise Admins, Domain Admins, and Administrators. With this script you can also see new, moved, disabled, or deleted user and computer accounts, spot OU changes, and keep tabs on group membership changes that take place within groups such as Server Operators and Account Operators.

Querying Sets of AD Categories

The script's main thrust is based on querying two sets of AD categories. The first set pertains to groups and class queries that can ascertain AD objects with fairly generalized LDAP query statements:
• AdminGroups: any group name containing the string Admin
• ComputersDisabled: disabled computer accounts; ComputersEnabled: enabled computer accounts
• Groups: all groups
• GroupsNoMembers: groups that have no members
• OUs: all OUs
• Servers: all computer objects whose operatingSystem attribute value contains the string Server
• ServiceAccounts: any account whose description attribute value contains the string Service
• ServiceGroups: any group whose sAMAccountName attribute value contains the string Service
• UserAccountsDisabled: disabled user accounts

The second set centers on obtaining memberships of high-level security-related groups:
• Account Operators
• Administrators
• Backup Operators
• Domain Admins
• Enterprise Admins
• Replicator
• Schema Admins
• Server Operators

The second set also requires a bit more scripting logic than the first set—the script needs to evaluate group membership, which involves checking for nested groups, acquiring members of nested groups if nested groups exist, avoiding endless loop recursion should nested groups refer to each other, and checking for domain accounts whose primary group is set to a group being evaluated. As you are probably aware, if an account's primary group is set to a specific group, querying that specific group's membership won't return that account nor any other accounts whose primary group is set to that specific group.

How the Script Works

When the script is run, each object from both sets of category queries is written to an ADO disconnected recordset. Each record contains the script's run date, the object's DN, the category description, and a concatenation of the category and the DN. I’ll explain those areas, including the concatenated field, in the next section.

After the script's initial run, any AD changes in any of the defined object categories can be detected on a subsequent run simply by traversing the current run's database and checking it against the previous run's database to see if those objects were found. The script checks each record in the previous database against the new database to see if the previous objects still exist in the new database. If records from either database are not found in the other, those records get written to a Microsoft Excel spreadsheet. After all of the records have been written to the spreadsheet, an Excel pivot table worksheet is produced within the Excel workbook showing the AD changes by categories of new AD objects and by objects that weren't found, providing a clear snapshot of changes that took place between the dates of the newest run and the previous run.

How often you run this process should coincide with the amount of activity your domain undergoes. The more activity you have, the more frequently you should run this process. I run mine daily, but should activity slow down, I can choose to run it only once a week. Incidentally, I have coded the script so that it can easily be run as a scheduled task. I avoided using message boxes created with VBScript's MsgBox function and used pop-ups created with Windows Script Host's (WSH's) WshShell.Popup method instead. Message boxes shouldn't be used in scripts that run as scheduled tasks because they don't go away until a user clicks a button. Unlike message boxes, pop-ups appear for only a given number of seconds. The added benefit of pop-ups is that you see the messages even if you decide to run the script manually.

The databases created and used in this script contain four fields as I mentioned above: Rundate, which is simply the date that the script was run; Category, which is an item from one of the two sets of categories I described earlier (e.g., UserAccountsDisabled); DN, which is the DN of the AD object; and CatDN, which is a combination of the values in the Category and DN fields.

The reason behind concatenating the values in the two fields has to do with the way ADO functions when you use the Find method to find a record within the database. As much as I like ADO, it does have shortcomings: One is that you can't use the AND operator with the Find method—and my script depends on finding a category and a DN. An alternative to the Find method, the Filter method, allows the use of the AND operator; however, I found that using the Filter method with mid-to-large-sized databases (over 500 records) results in terrible performance hits on your computer. To counter that, I decided to take the disk-space hit over the performance hit and combine the two fields so I could use the speedy Find method.

I should also point out that you should carefully consider where you choose to house your databases. Depending on the size of your domain you could have databases that are a few megs in size for every run of the script. Currently each of my databases is roughly 3.5MB. You can, of course, zip and/or archive older databases if need be. The .xml files zip quite nicely; a 3.5MB file zips down to approximately 145KB. To change the default location of where your files are stored, locate the line DBPath = C:\Scripts\ADacctTrack\ in the script and change C:\Scripts\ADacctTrack\ to the appropriate path.

The first time this script is run, only the xml database is produced because there’s nothing to compare it with. Whenever the script is run, the database produced is saved as NewestAcctTracker.xml when the process completes. When the script is run the second time, the newest database is renamed PreviousAcctTracker.xml and the database created from the current run is named NewestAcctTracker.xml. On the third and all subsequent runs, the database named PreviousAcctTracker.xml gets renamed to ArcAcctTrackerDateTime.xml. (e.g., ArcAcctTracker09-26-20081305-45.xml). DateTime will always be the DateLastModified property value of PreviousAcctTracker.xml before it's renamed. I obtain this value by using the GetFile method of the Scripting.FileSystemObject object to access the PreviousAcctTracker.xml file properties. I store the value in a variable named DateTime, making sure I fill dates with leading zeroes (e.g., 07/07/2008), convert the time portion of the date to military time (e.g., 1307:54), and replace every slash (/) and colon (:) with a hyphen (-). This makes it very easy to find a specific database if you need to examine one by date. The files also sort by name more appropriately when you use this naming convention.

One last note about how the script works before we explore the code. When the script runs, it creates a new ADO disconnected recordset. After the script retrieves the data from the category queries and stores it in the ADO database, it then opens the previous database and steps through each of the new records, attempting to find that record within the previous database. If it can't find that data, then that record is considered new since it didn’t exist in the previous database and it's written to an Excel spreadsheet. Each record written to the spreadsheet includes
• A Status entry of New
• A Category entry that refers to the Category field of the current database record
• A DN entry that refers to the DN field of the current database record
• A Note entry of Not in Previous List.

After reaching the end of the file in the current database, the script steps through the previous database and attempts to find a matching record in the current database. If a matching record isn't found then that record is considered "not found" and a similar process occurs in which I write the data from the previous database to the spreadsheet. The Status entry in this case becomes Not Found and the Note entry becomes In Previous – Not in Most Recent List.

A Not Found entry could mean that the object in question could have been deleted, moved, renamed, or disabled. Whatever the case, the original DN and category of that entry no longer exist. It's certainly possible that the object in question will appear in one of the other categories as a “New” object, unless the object was deleted. You’ll see later on that I choose to sort the master worksheet by DN rather than Status or Category—it makes finding moved, disabled, and renamed objects much easier when evaluating the spreadsheet because the DN entries are grouped together.

Related Content:

ARTICLE TOOLS

Comments
  • JANIS
    3 years ago
    Sep 23, 2009

    I've had several issues running the script - the last script error is Line 183 Char 2 There is no object on the server, Code 80072030. Unfortunately I'm not very versed in VB Script so I have terrible time trying to fix things that aren't working for me. Any help would be appreciated.

  • Karen
    3 years ago
    Aug 31, 2009

    The script discussed in the article is AccountTracker.vbs, which you can access by clicking the “Download the Code Here” button at the top of the page. (You need to be a Windows IT Pro subscriber to see this button.)

    Unfortunately, on the current website, the only way to post a Reader Comment is to rate the article. Fortunately, the website is being redesigned. In the redesigned website, the Reader Comment and rating areas are separate, so you can post a Reader Comment without having to rate the article and vice versa.

    Karen Bemowski, senior editor, Windows IT Pro, SQL Server Magazine

  • Marc
    3 years ago
    Aug 28, 2009

    a script named adacctcountstoxl.vbs is mentioned in the print article but is nowhere to be found here.

    also, are authors & editors really allowed to rate articles when they post comments? wouldn't that skew things a bit?

  • JAMES
    3 years ago
    Feb 25, 2009

    If you are having problems accessing the article, please scroll down to the bottom of this page and click on Contact Us/Customer Service and let them know that you are having problems accessing the article with your subscription.

  • Wayne
    3 years ago
    Feb 11, 2009

    Where is the article? I have the same problem as floresj.

You must log on before posting a comment.

Are you a new visitor? Register Here

advertisement

advertisement

Windows is a trademark of the Microsoft group of companies. Windows IT Pro is used by Penton Media Inc. under license from owner.