One of the strategies I often employ when deploying Active Directory (AD) for customers is to use the local Windows Server Backup (WSB, previously NTBackup) tool to make system state backups on the local machine. I’ll also often place backups on neighboring Domain Controllers (DCs) to provide for redundancy if there is a failure. This strategy ensures that a backup is available in the same site and it also removes the dependency on an external backup team. Many third party backup applications can backup a file share without needing to install an agent on the server as well which is a better all around situation for DC backup at many customers. Note that you’ll want to tightly secure the shares that backups are placed on given they include full copies of your AD database (ntds.dit) which has all of the password hashes in it.
The script below implements this strategy of backing up DCs to neighboring DCs and it also will implement retention and aging of backups. You’ll need to configure the age, log location, and backup table at the top. Note that the DC names in the table are case sensitive. In the example, DC01 backs up to a share on DC02 and vice versa.
'========================================================================== ' NAME: WS08 DC Backup ' ' AUTHOR: Brian Desmond, email@example.com ' DATE : 7/10/2009 ' ' COMMENT: ' Version Date Author Note ' ----------------------------------------------------------------- ' 1.0 10Jul09 Brian Desmond Initial VERSION ' 1.1 05Feb11 Brian Desmond Bug fixes, documentation '========================================================================== Option Explicit Const VERSION = "1.0" ' How many days to keep the backup for Const MAX_BACKUP_AGE = 7 ' Where to store the log file Const LOG_FILE = "C:\Scripts\Backups\DCBackupLog.txt" Dim backupLocation Set backupLocation = WScript.CreateObject("Scripting.Dictionary") ' List of DCs and the shares to store their backups in backupLocation.Add "DC01", "\\DC02.green.briandesmond.net\adbackup$\dc01" backupLocation.Add "DC02", "\\DC01.green.briandesmond.net\adbackup$\dc02" '========================================================================== Dim fso Set fso = WScript.CreateObject("Scripting.FileSystemObject") Dim shl Set shl = WScript.CreateObject("Wscript.Shell") Dim net Set net = WScript.CreateObject("WScript.Network") Dim logFile Set logFile = fso.OpenTextFile(LOG_FILE, 8, True) ' 8 = ForAppending If Not backupLocation.Exists(net.ComputerName) Then WriteLogLine "Server not found in backup location table." WScript.Echo "Server not found in backup location table." WScript.Quit 1 End If Dim backupRoot backupRoot = backupLocation(net.ComputerName) CleanOldBackups MAX_BACKUP_AGE, backupRoot Dim wbAdminCmd wbAdminCmd = "wbadmin start backup -AllCritical -Quiet -BackupTarget:" wbAdminCmd = wbAdminCmd & GetBackupPath(backupRoot) wbAdminCmd = wbAdminCmd & """" WScript.Echo wbAdminCmd WriteLogLine "Launching " & wbAdminCmd Dim execObj Set execObj = shl.Exec(wbAdminCmd) While execObj.Status = 0 WScript.Sleep(1000) Wend Dim wbAdminOutput wbAdminOutput = execObj.StdOut.ReadAll WScript.Echo wbAdminOutput WriteLogLine wbAdminOutput Sub CleanOldBackups(MaxAge, SearchLocation) WriteLogLine "Beginning CleanOldBackups; MaxAge=" & MaxAge Dim foldersToDelete() ReDim Preserve foldersToDelete(0) Dim doDeleteFolder doDeleteFolder = False If fso.FolderExists(SearchLocation) Then Dim folder For Each folder In fso.GetFolder(SearchLocation).SubFolders If IsDate(folder.Name) Then Dim age age = DateDiff("d", Now(), CDate(folder.name), vbSunday, vbFirstJan1) If age > MaxAge Then foldersToDelete(UBound(foldersToDelete)) = folder.Path doDeleteFolder = True End If Else WScript.Echo "Skipping " & folder.name & ", invalid name" End If Next End If If doDeleteFolder Then Dim i For i = 0 To UBound(foldersToDelete) WScript.Echo "Deleting " & foldersToDelete(i) WriteLogLine "Deleting " & foldersToDelete(i) fso.DeleteFolder foldersToDelete(i), True Next End If WriteLogLine "Ending CleanOldBackups" End Sub Sub WriteLogLine(line) logFile.WriteLine Date & " " & Time & ": " & line End Sub Sub SafeCreateFolder(path) If Not fso.FolderExists(path) Then fso.CreateFolder(path) End If End Sub Function GetBackupPath(RootPath) Dim cleanDate cleanDate = Replace(FormatDateTime(Date, vbShortDate), "/", "-") Dim cleanHour cleanHour = CStr(DatePart("h", Now, vbSunday, vbFirstJan1)) Dim backupPath backupPath = RootPath SafeCreateFolder backupPath backupPath = fso.BuildPath(backupPath, cleanDate) SafeCreateFolder backupPath backupPath = fso.BuildPath(backupPath, cleanHour) SafeCreateFolder backupPath GetBackupPath = backupPath End Function