Summary: Guest blogger, Matt Tisdale, talks about mounting a previous version of Active Directory to see what has changed. Microsoft Scripting Guy, Ed Wilson, is here. This week, guest blogger, Matt Tisdale contributed the following posts:
- Optimize Performance of AD DS Queries via PowerShell
- Weekend Scripter: A Little PowerShell Help Here…Please?
Let’s finish off the weekend with more from Matt… On occasion, I am asked questions similar to, “Can you tell me what users were in the Central Division group yesterday?” and “Can you tell me what data was in the Department attribute of a specific user last week?” It is very easy for anyone to look at information in Active Directory to see exactly when an object (for example, a group or user) was last changed or exactly when a particular attribute of an object was changed. However, it can be a little more challenging to find out what a previous value of the attribute was. This information is not maintained in the current version of Active Directory. The solution to this issue is to mount a previous version of Active Directory and then view it by using Windows PowerShell. To view Active Directory data from a previous date, we follow three basic steps:
- Restore a previous backup (snapshot) of the Active Directory database to a temporary location.
- Mount the restored Active Directory database to an alternate LDAP port on a live domain controller.
- Use LDAP or any other Active Directory searching tools to browse the Active Directory database.
Because we all know Windows PowerShell is the correct answer to most administrative needs, we will specifically focus on using Windows PowerShell as our search tool. In this post, I am making the assumption that we already have a snapshot of DC1 available at \server1backupsDC1.
Note These steps are written for a Windows Server 2008 R2 environment, and they may be different for other versions of Active Directory. Let’s dig in to these steps in more detail…
1. Restore a previous backup of the database
To begin, we want to restore a previous backup of the Active Directory database to a temporary location. To restore a previous copy of the Active Directory database
- Sign in to DC1 with Admin credentials.
- Create a temporary folder for the restored ntds.dit file. We will use G:Temp for this example.
- Open the Windows Backup tool (wbadmin.msc).
- Click Action, and then click Recover.
- Select the A backup stored on another location radio button, and then click Next.
- Select the Remote shared folder radio button, and then click Next.
- Enter the UNC path to where the desired backup of DC1 is stored (\server1backupsDC1, for this example), and then click Next.
Note The entered path should be to a backup of the domain controller where you are signed in and running wbadmin. The entered UNC path should be to the location where a folder named WindowsImageBackup is stored. Do not go past this folder. - Verify that the correct backup date is highlighted, and then click Next.
- Select the Files and folders radio button, and then click Next.
- Note This step assumes that the Active Directory database (ntds.dit) is located at E:ADdataNTDS on DC1.
- In the Available Items window, expand DC1, E:, expand adData, and select NTDS.
- In the Items to recover window, select only ntds.dit (do not select the other files), and then click Next.
- Select the Another location radio button, browse to G:Temp, and then click Next.
- Click Recover.
- After the recover job status shows Complete, click Close.
- Exit the Windows Server Backup tool.
2. Mount the previous version to an alternate port
Now that we have restored a copy of the Active Directory database that we want to look at, we need to mount it to an available LDAP port on a live domain controller. The port number I recommend using is 51389. To mount the database
- With Administrator credentials, open a command prompt.
- Run the command dsamain -dbpath {path to restored ntds.dit} -ldapPort {desired port number}, for example: dsamain -dbpath G:Tempntds.dit -ldapPort 51389.
- After a few seconds you should see the following message: “Microsoft Active Directory Domain Services startup complete.”
You have now made a previous instance of Active Directory available for browsing. No changes can be made to this (for obvious reasons), but you will be able to read all the properties for any object that existed when the backup was taken.
Important After you are finished searching the old data, make sure that you dismount the old ntds.dit database, and then delete the restored file and the temporary folder. You can dismount the database by pressing Ctrl+C in the Command Prompt window. Then simply delete the G:Temp folder.
3. Browse the data with Windows PowerShell
Any number of tools can be used to browse this restored database, including Active Directory Users and Computers, adsiedit, and ldp.exe. We’re going to investigate a few Windows PowerShell commands to use to look at the data. Open Windows PowerShell (with the Active Directory module imported) and run the following command. This command assumes that the domain controller you have been working with is named DC1. If you are using another server, simply use the appropriate name.
Get-ADUser -Identity MartyMcFly -Server DC1:51389 -Properties * This command displayed all the available attributes for the user account MartyMcFly from the old copy of Active Directory mounted on port 51389. Notice how we used the -Server parameter and then passed it to DC1:51389? Adding :51389 after the server name is how we force a connection to that specific port number. If I need to know the Department attribute (or any other attribute) for this account on the date this backup was taken, I can see it in the provided data.
Real world example
Now let’s look at a real world example where I recently used this process. Here is the question I was asked:
“We have an automated group that should contain everyone where division = central, but that group is empty today. I suspect this is because HR changed all central staff to another division name, and group automation removed all of the users. I need to look at the current Division attribute data for each person who was in this group before the HR change. This will help me figure out how to modify the group automation that is using new division names. Can you get that for me?” To resolve this issue, I mounted a copy of Active Directory that was backed up prior to the HR change, and then I ran the following commands. This command stores the group name in a variable (this is the name of the group you need to read the membership of):
$groupname = “Central Division” This command stores the old membership of the desired group in a variable:
$members = get-adgroup $groupname -server DC1:51389 -properties members This command reads the old Division attribute data for each user account from the restored (mounted) version of Active Directory—note the connection to port 51389:
$members.members | foreach {get-aduser -identity $_ -server DC1:51389 -properties division | select name,division} Now for the fun part… The next command reads each member of the old group, finds that user account in the current “live” version of Active Directory, and then displays the Division attribute data for each current account. It also sorts the returned user accounts by division to make it easier to identify each new division name. Notice how the first Get-ADUser command connects to port 51389, and the second Get-ADUser command connects to port 389 (389 is the current live version of Active Directory).
$members.members | foreach { get-aduser -identity $_ -server DC1:51389 | foreach { get-aduser -identity $_.samaccountname -server DC1:389 -properties division | select name,division } } | sort -Property division There you have it! Marty McFly goes back in time with Windows PowerShell. Happy PowerShelling! ~Matt Thank you, Matt, for sharing your time and knowledge. I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. Ed Wilson, Microsoft Scripting Guy
0 comments