With Windows Server 2008's release, there has been a lot of discussion around the use of Read-Only Domain Controllers and AD Domain Services running on Server Core. Yet, one of the more interesting features that I find that a lot of people are overlooking is DSAMAIN.EXE (AD Database Mounting Tool). If you've used ADAM (now AD LDS) in the past, you'll recognize DSAMAIN.EXE as the process that ADAMDSA.DLL runs under. This is ADAM's equivalent of NTDSA.DLL running under LSASS.EXE on a Domain Controller.
ADAM has really paved the way for portable directory services on Windows. Although we may never see the full separation of Active Directory Domain Services running as a service (because of the security implications of running outside of LSASS), we are one step closer. In Windows Server 2008, AD DS is instantiated under a service called NTDS (with the display name of "Active Directory Domain Services"). So now, AD DS can be restarted without having to reboot the DC.
Building on the portable directory concept, AD DS took a page from the book on ADAM and implemented what is called the AD Database Mounting Tool (DBMT). With the DBMT, you can actually mount a backup of AD DS under a different set of ports and have read-only access to your backups through LDAP. Just like how multiple instances of ADAM can run on the same machine under different ports, snapshots of NTDS.DIT can now do so as well. This provides read-only access to an offline copy of AD, but only through LDAP. Remember, this instance is not running in LSASS protected memory, so we don't want it issuing tickets or authenticating anyone - or doing anything else other than act as a vanilla directory service, for that matter.
So what are the scenarios that can be exposed in this situation? So let's say that someone on the MIIS team just replaced the displayName attribute of every user object in the domain with "John Smith". Using NTDSUTIL, you can mount a copy of a previous snapshot to an alternate port and easily export the displayName attribute for every user object that was changed. These values can then be imported into the running instance of AD DS. Let's walk through the scenario:
So first, you need a VSS snapshot of the volume that the DIT is on. For our purposes, we'll take the snap using NTDSUTIL. So log on to your WS08 DC and open up a command prompt. Run the following command:
ntdsutil "Activate Instance NTDS" snapshot create quit quit
You could also run NTDSUTIL and run each command separately to drill down through the menus, but you can schedule the above one-liner to run every night in a scheduled task.
Now that you have a snapshot, you need to mount it so you can have access to NTDS.DIT. To mount the snapshot that we took in the previous step, we'll use NTDSUTIL again. First, you can list the snapshots that you have available:
ntdsutil snapshot "list all" quit quit
After you target which snapshot you want to mount, you can reference it using the snapshot index. FYI - NTDSUTIL requires that the "list" command be run in the same session that you mount the snapshot. So in order to mount the snapshot with a one-liner, you will need to run "list all" first.
ntdsutil snapshot "list all" "mount 11" quit quit
Note the path that it was mounted under: "C:\$SNAP_200803060936_VOLUMEC$". This coincides with the date and time that the snapshot was taken, as well as the volume that was snapped.
In the last two steps, we've just been making the actual NTDS.DIT backup available to us. We can now access the DIT with the following path (assuming you used the default database path when running DCPROMO): "C:\$SNAP_200803060936_VOLUMEC$\Windows\NTDS\NTDS.DIT.
Now, we'll use DSAMAIN.EXE (the Database Mount Tool - DBMT) to mount the DIT. There are a couple of things to note here. First, ensure that you put in the correct path to the NTDS.DIT file that you are mounting. Second, you have to give the DBMT a unique port to service LDAP requests on. In this example, we'll use 10389. What actually happens here is that the DBMT will expose the directory on LDAP, LDAP/SSL, GC, and GC/SSL. If can feed the command the different ports that you want to use for each protocol connection, but if you just give it one port (i.e. 10389), it will mount the subsequent listeners numerically. So if you specific 10389 for the LDAP port, this is what you end up with:
Here's the command to mount the DIT:
dsamain -dbpath C:\$SNAP_20080306_VOLUMEC$\Windows\NTDS\ntds.dit -ldapport 10389
A funny thing happens next. The only thing that will actually indicate that the DIT is mounted is the message "Microsoft Active Directory Domain Services startup complete":
Do not close the command prompt. As long as the DBMT is running, you can access the directory over LDAP on the port you specified. To prove it, let's run ADSIEdit.
Now that we have access to a snapshot of the DIT, we can just export the data that we need. There are a million ways to do this. I'm a big fan of VBScript, so let's use the following script to pull the data out and write it to TSV (Tab Separated Values) file. We'll go through each user account and export the samAccountName and displayName attributes to the TSV. Remember, we're connecting to port 10389.
'-------------------------------------------------------------------------- ' NAME: export-attr.vbs ' DATE: 3/6/2008 ' DESCRIPTION: Connects to a directory service provider on the specified ' port and exports a list of attributes for each user object ' in the directory to a tab-separated values file. ' AUTHOR: Ken St. Cyr '-------------------------------------------------------------------------- Option Explicit ' Define our parameters CONST LDAPPORT = 10389 CONST DCNAME = "localhost" CONST ATTRIBUTES = "samAccountName,displayName" CONST OUTPUT_FILE = "attribute_backup.tsv" ' Create the necessary objects for writing to a file Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject") Dim objFile : Set objFile = objFSO.OpenTextFile(OUTPUT_FILE, 8, True) ' Get the RootDSE for the directory on the port that we want Dim objRootDSE : Set objRootDSE = GetObject("LDAP://" & DCNAME & ":" & _ LDAPPORT & "/RootDSE") ' Create the connection object for the AD provider Dim objConnection : Set objConnection = CreateObject("ADODB.Connection") objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" ' Define the search to execute Dim objCommand : Set objCommand = CreateObject("ADODB.Command") objCommand.CommandText = "<LDAP://" & DCNAME & ":" & LDAPPORT & "/" & _ objRootDSE.Get("defaultNamingContext") & ">;(&objectCategory=user);" & _ ATTRIBUTES & ";subtree" objCommand.ActiveConnection = objConnection ' Execute the search Dim objRecordSet : Set objRecordSet = objCommand.Execute objRecordSet.MoveFirst ' Go through each result about output the attributes to a Tab-Separated file While Not objRecordSet.EOF Dim strSAMAccountName : strSAMAccountName = objRecordSet.Fields("samaccountname") Dim strDisplayName : strDisplayName = objRecordSet.Fields("displayName") objFile.WriteLine strSAMAccountName & vbtab & strDisplayName objRecordSet.MoveNext Wend objFile.Close WScript.Echo objRecordSet.RecordCount & " entries written to " & OUTPUT_FILE
Now that we have the data, we can get out and reverse everything we just did. To dismount the DIT, its simply a matter of pressing CTRL-C at the command window for the DBMT. You'll get a message indicating that the DS shut down successfully.
The last thing we need to do is to unmount the snapshot. Again, this can be done through NTDSUTIL. The same concept as step 2 applies here, so you are required to perform a "list mounted" before we can actually perform the unmount command.
ntdsutil snapshot "list mounted" "unmount 1" quit quit
And that's it. I know this process may seem a little confusing at first, but after running through it a few times in the lab, you'll get the hang of it. Besides, it's MUCH better than the alternative - taking down the DC (or standing up an offline DC), restoring from a backup, rebooting into DSRM, and then exporting the attributes. At least with the DBMT, you can use a snapshot and perform it on a live DC using an alternate port - and the DC remains functional the entire time.
-
Thus concludes the first post in this new blog. I had a few other blogs out there running with various topics, but I've decided to collapse them all into this one. The problem is that I forgot to back up the articles that I wrote before I took the blogs offline (doh!), so most of my content is gone. When/if I find it, I'll repost it all here. In the mean time, I'll be moving over material from some of my other articles.
Think of this real world scenario - a help desk guy accidentally 'nukes' a security group out of your AD environment. The security group in question had over 1000 items inside and had not been documented very well. Tapes from last night have already gon
A bit shameless plug but here is a tool which might simplify this process a bit :) :
http://www.one-identity.net/tools/snapshot/