Thursday, January 24, 2008

Recursive Site Backup Script

I came across this backup script today while looking for a way to enumerate sites and then create individual site backups based on the resulting .XML output.

Just copy the following code into a .vbs file and modify the top variables for your environment.

'Moded by Stephen Costigan stephen.costigan@us.sogeti.com
Option Explicit

'Set path to STSADM
Const STSADM_PATH = "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm"

'Change based on where you want the log files to go to
Const STSADM_LOGPATH = "C:\LogFiles"

'Change based on where you want the backup files to go to
Const STSADM_BAKPATH = "C:\BakFiles"

'Set file names for log and XML
Const STSADM_LOGFILE = "BackupLog.txt"
Const STSADM_XMLFILE = "BackupXML.txt"

'Change based on the portal URL
Const STSADM_PORTAL_URL = "https://portal.com/"

'Change to determin how many instances of backup you want running at once
Const NUM_BACKUP_PROCESSES = 4

'Declare objects
Dim objFso, objFolder, objFiles, objFile, objShell, objExec, objXml, objSc, objUrl, objLog, objLog2, objRunningBackupProcess

'Declare strings and integers
Dim strResult, strUrl, strFileName, strCmd, n

Dim g_intTotalProcessesLaunched ' As Integer
Dim g_intOpenProcessSlot ' As Integer
Dim g_bInitialLaunch ' As Boolean
Dim g_bOpenProcessSlot ' As Boolean
Dim g_bKeepWaiting ' As Boolean
ReDim g_CurrentProcesses(NUM_BACKUP_PROCESSES) ' As Array

'Set values
g_intTotalProcessesLaunched = 0
g_bInitialLaunch = True
g_bKeepWaiting = False

'Open folder where backups and log files will be stored
Set objFso = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFso.GetFolder(STSADM_LOGPATH)

'Delete all files currently present in the backup folder.
Set objFiles = objFolder.Files
For Each objFile in objFiles
objFile.Delete(True)
Next

'Create log file and write first entry
Set objLog = objFso.CreateTextFile(STSADM_LOGPATH + STSADM_LOGFILE, True)
objLog.writeline(Now & ": Begin backup")

'Retrieves all site collections in XML format.
Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec(STSADM_PATH & " -o enumsites -url " & STSADM_PORTAL_URL)
strResult = objExec.StdOut.ReadAll
objLog.writeline(Now & ": Enum Sites")

'Create XML log file and push content into it
Set objLog2 = objFso.CreateTextFile(STSADM_LOGPATH + STSADM_XMLFILE, True)
objLog2.writeline(strResult)
objLog2.close
objLog.writeline(Now & ": Wrote XML")

'Load XML in DOM document so it can be processed.
Set objXml = CreateObject("MSXML2.DOMDocument")
objXml.LoadXML(strResult)
objLog.writeline(Now & ": Read XML into DOM")

'Loop through each site collection and call STSADM to make a backup.
For Each objSc in objXml.DocumentElement.ChildNodes
If (g_bInitialLaunch) Then
Set objExec = LaunchNewProcess()
g_intOpenProcessSlot = (g_intTotalProcessesLaunched - 1) Mod NUM_BACKUP_PROCESSES
Set g_CurrentProcesses(g_intOpenProcessSlot) = objExec
If (NUM_BACKUP_PROCESSES = g_intTotalProcessesLaunched) Then
g_bInitialLaunch = False
End If
Else
g_bKeepWaiting = True
' Delay here until one of the processes in the array exits, then start another
Do While g_bKeepWaiting
WScript.Sleep 1000
objLog.writeline(Now & ": Waiting for command to execute and complete")

'Walk the array and see if everything is still running
'N.B., This algorithm finds only the lowest open slot and fills it with a new running process
'If there are multiple open slots, the higher ones will be filled on subsequent passes through
'the loop. This may mean that if processes exit in less than the sleep delay above, there may
'be fewer running instances than the NUM_BACKUP_PROCESSES limit.

For n = (NUM_BACKUP_PROCESSES - 1) To 0 Step -1
Set objRunningBackupProcess = g_CurrentProcesses(n)
g_bOpenProcessSlot = Not (objRunningBackupProcess.Status <> 1) ' 1 is WshScriptExec.WshFinished
If g_bOpenProcessSlot Then
g_bKeepWaiting = False
g_intOpenProcessSlot = n
objLog.writeline(Now & ": Found Open Slot: g_intOpenProcessSlot is " & g_intOpenProcessSlot)
End If
Next
If (False = g_bKeepWaiting) Then
Set objExec = LaunchNewProcess()
Set g_CurrentProcesses(g_intOpenProcessSlot) = objExec
objLog.writeline(Now & ": g_intTotalProcessesLaunched is " & g_intTotalProcessesLaunched)
End If
Loop
End If
Next

'Write completion message to lof file
objLog.WriteLine(Now & ": Backup of portal site collections complete")
objLog.WriteLine("Total Backup Processes: " & g_intTotalProcessesLaunched)

'Close log file
objLog.close


'Function that actually kicks off the backup process for each site collection
Function LaunchNewProcess()
strUrl = objSc.Attributes.GetNamedItem("Url").Text
strFileName = STSADM_BAKPATH & Replace(Replace(strUrl, "https://", ""), "/", "_") & ".bak"
strCmd = STSADM_PATH & " -o backup -url """ + strUrl + """ -filename """ + strFileName + """"
objLog.WriteLine(Now & ": Executing Command '" & strCmd & "'")
Set LaunchNewProcess = objShell.Exec(strCmd)
g_intTotalProcessesLaunched = g_intTotalProcessesLaunched + 1 ' Keep track of how many instances are launched
End Function

No comments: