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. I simply schedule the script to run on the appropriate interval (e.g. nightly) using the Task Scheduler. The script runs well under Local System.

'==========================================================================
' NAME: WS08 DC Backup
'
' AUTHOR: Brian Desmond, brian@briandesmond.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