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