My last post outlined how to automate backing up SharePoint using visual basic scripting, but being a DBA and developer it was only a matter time before I spun this into a SQL related exercise. I would again love to take credit for the aforementioned posted vbs code, but my only efforts were to make MINIMAL changes to the script outlined on Technet:
So again let me lay out my specific business needs:
1. Due to limited storage only 2 full SharePoint farm backups can be maintained on our storage device
2. A full SharePoint farm backup for the most recent two days must be maintained
3. To assure ease and reduce confusion the spbrtoct.xml file must be kept up to date recording ONLY those backups in SharePoint that are available
The above link provides an EXCELLENT source for using vbs to accomplish this task, but aside from my admitted personal bias and preference, there are several benefits that are immediately realized in replacing this script with managed code. Some of these benefits include:
1. Structured error handling
2. Logging
3. Task History
Public Sub Main()
Dim logcount As Integer = 0
So again let me lay out my specific business needs:
1. Due to limited storage only 2 full SharePoint farm backups can be maintained on our storage device
2. A full SharePoint farm backup for the most recent two days must be maintained
3. To assure ease and reduce confusion the spbrtoct.xml file must be kept up to date recording ONLY those backups in SharePoint that are available
The above link provides an EXCELLENT source for using vbs to accomplish this task, but aside from my admitted personal bias and preference, there are several benefits that are immediately realized in replacing this script with managed code. Some of these benefits include:
1. Structured error handling
Please do not interpret this statement as to say that there is no structured error handling in vbs, but the catching and handling or errors in .NET is easier and more encompassing.
2. Logging
SSIS packages can utilize log providers that provide a much greater depth of information into what occurs during package execution than what is immediately available in scheduling vbs from scheduled tasks
3. Task History
After deploying and scheduling an SSIS package using SQL server agent the history can be viewed and maintained along with the recorded outcome and error(s).
Rather than ramble on let's jump into the process of creating an SSIS package to maintain SharePoint backups. The first step is to create a SQL Server integration services project using BIDS, in this post I am using SQL/BIDS 2008, which supports script tasks for both C# and VB.NET. The posted VB code will works just as well in SQL 2005, but the C# code is obviously not an option as only VB is supported in SSIS script tasks.
Once the project is created drag and drop a Script Task onto the control flow pane. The task will need to Import System.IO and Import System.XML, for C# you must reference using System.IO and using System.XML.
The VB code is listed here:
Once the project is created drag and drop a Script Task onto the control flow pane. The task will need to Import System.IO and Import System.XML, for C# you must reference using System.IO and using System.XML.
The VB code is listed here:
Public Sub Main()
'An XmlDocument is used to hold the spbrtoct.xml
Dim doc As New XmlDocumentDim logcount As Integer = 0
' path(s) variables contain the path for the log and spbrtoct
'In order to assure consistency and reduce the chance of improper
'In order to assure consistency and reduce the chance of improper
Dim log As String = "\\SERVER\MOSS Backup\BackupCleanUp.log"
Dim spbr As String = "\\SERVER\MOSS Backup\spbrtoct.xml"
' Begin by adding a line to the log file that will delineate the date
' that the process began
'Structured error handling is used in case an error occurs during the
End Try
Dim bupHistory As XmlNode
'If thereturns true and the is more than two days old
'The directory specified in the <SPBackupDirectory> is deleted and the
'deletion is recorded in the log
Directory.Delete(bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1))
Dts.TaskResult = ScriptResults.Success
//Begin by adding a line to the log file that will delineate the date that the process began
File.AppendAllText(log, @"----------------------------" + "\t Backup/Cleanup Process Begun:\t " + DateTime.Now + "\t----------------------------
\r\n");
doc.Load(spbr);
try {
Once the script task is completed then drop an Execute Process Task onto the control flow pane and connect the script tasks success precedent constraint to the Execute Process Task.
Configure the Execute Process Task to be point at the STSADM.exe, the default path is :
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\Bin\STSADM.exe
the Arguments should be:
-o backup -directory "\\SERVER\MOSS Backup" -backupmethod full
and the WorkingDirectory should be configured as:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\Bin\
***Keep in mind my requirements are for a farm backup so the below screen shot of the command line arguments are for a full farm back up.
After I completing this package I began to obsess about all of the possible enhancements I could include, bells, whistles, features, etc, but was soon called back to reality with the oh so familiar, “C’mon man!! We got other projects to complete!!” The one enhancement I do plan on implementing is to create an SSIS variable that will be assigned the script error and package messages, using the OnError event handler, and then emailed using a Send Mail Task.
I have done my best to clean up the script task code to make it easy to cut and paste, but I finally gave up so please contact me if there are any question.
' that the process began
File.AppendAllText(log, "----------------------------" & vbTab & "Backup/Cleanup Process Begun: " & vbTab & ().ToString & vbTab & "----------------------------" & _ vbCrLf)
Try
'Structured error handling is used in case an error occurs during the
'loading of the spbrtoct.xml
doc.Load(spbr) Catch ex As Exception
' If an error occurs during the loading of the spbrtoct.xml then an
' entry is made in the log along with the ex.Message and since
' nothing more can be done the sub is Exited
File.AppendAllText(log, Now().ToString & vbTab & "Error: Could not load the SharePoint Backup / Restore History." & vbCrLf & _Now() & vbTab & "Reason: " & ex.Message.ToString & vbCrLf)
logcount += 1
Exit Sub
End Try
Dim bupHistory As XmlNode
Try
'Loop through each elements child node
For Each bupHistory In doc.DocumentElement.ChildNodes
'If the
If bupHistory.ChildNodes(6).InnerText = True And & _
CDate(bupHistory.ChildNodes(5).InnerText.ToString) & _
< Now.AddDays(-2) Then
< Now.AddDays(-2) Then
'The node is deleted and the deletion is recorded in the log
doc.DocumentElement.RemoveChild(bupHistory)
File.AppendAllText(log, Now().ToString & vbTab & "Removed node: "& _ bupHistory.ChildNodes(7).InnerText.Substring(0, Len(bupHistory.ChildNodes(7).InnerText) - 1) & "." & vbCrLf)
logcount += 1
'The directory specified in the <SPBackupDirectory> is deleted and the
'deletion is recorded in the log
If Directory.Exists(bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1)) = True Then
Len(bupHistory.ChildNodes(7).InnerText) - 1)) = True Then
Directory.Delete(bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1))
File.AppendAllText(log, Now().ToString & vbTab & "Deleted: " &
bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1) & "." & vbCrLf)
bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1) & "." & vbCrLf)
logcount += 1
Else
File.AppendAllText(log, Now().ToString & vbTab & "Directory does not exist: " & bupHistory.ChildNodes(7).InnerText.Substring(0,
Len(bupHistory.ChildNodes(7).InnerText) - 1) & "." & vbCrLf)
Len(bupHistory.ChildNodes(7).InnerText) - 1) & "." & vbCrLf)
End If
End If
Next
Catch ex As Exception
'If an error occurs during the deletion of the node or directory an entry is made 'in the log
File.AppendAllText(log, Now().ToString & vbTab & "Error: Could not delete the directory or remove the historic backup node." & vbCrLf & _
Now() & vbTab & "Reason: " & ex.Message.ToString & vbCrLf) logcount += 1
End Try
Try
'The changes made to the spbrtoct.xml are saved back to the directory and if an 'error occurs then an entry is made in the log
doc.Save(spbr)
Catch ex As Exception
File.AppendAllText(log, Now().ToString & vbTab & "Error: Could not save changes made to spbrtoct.xml." & vbCrLf & Now() & vbTab & "Reason:" & ex.Message.ToString & vbCrLf)
logcount += 1
End Try
If logcount = 0 Then
File.AppendAllText(log, "############################ Nothing Logged Completed At " & Now().ToString & " ###########################" & vbCrLf)
End If
Dts.TaskResult = ScriptResults.Success
End Sub
End Class
and the C# code:
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
using System.IO;
using System.Xml;
namespace ST_1ca426443e474993a2ce11e5f0224a09.csproj
{
[System.AddIn.AddIn("ScriptMain", Version = "1.0", Publisher = "", Description = "")]
public partial class ScriptMain :
Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
#region VSTA generated code
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
public void Main()
{
{//In order to assure consistency and reduce the chance of improper path(s) the paths
//for both the spbrtoct and log paths are stored as variables
string log = "\\\\SERVER\\MOSS Backup\\BackupCleanUp.log";
string spbr = "\\\\SERVER\\MOSS Backup\\spbrtoct.xml";
File.AppendAllText(log, @"----------------------------" + "\t Backup/Cleanup Process Begun:\t " + DateTime.Now + "\t----------------------------
\r\n");
//An XmlDocument is used to hold the spbrtoct.xml
XmlDocument doc = new XmlDocument();
XmlDocument doc = new XmlDocument();
int logcount = 0;
try {
//Structured error handling is used in case an error occurs during the loading of the spbrtoct.xml
doc.Load(spbr);
}
catch (Exception ex) {
//If an error occurs during the loading of the spbrtoct.xml then an entry is made in the log
//along with the ex.Message and since nothing more can be done the sub is Exited
string loaderror = DateTime.Now + @"\t Error: Could not load the SharePoint Backup / Restore History. \t" + DateTime.Now + "Reason: " + ex.Message + "\r\n";
File.AppendAllText(log, loaderror);
logcount += 1;
return;
}
try {
//Loop through each elements child node
foreach (XmlNode bup in doc.DocumentElement.ChildNodes)
{
//If the returns true and the is more than two days old
if (bup.ChildNodes[6].InnerText == "True" & DateTime.Parse(bup.ChildNodes[5].InnerText) < DateTime.Now.AddDays(-2))
{
//The node is deleted and the deletion is recorded in the log
doc.DocumentElement.RemoveChild(bup); File.AppendAllText(log, DateTime.Now + "\t Removed node: " +
bup.ChildNodes[7].InnerText.Substring(0, (bup.ChildNodes[7].InnerText).Length -
1) + ". \r\n");
bup.ChildNodes[7].InnerText.Substring(0, (bup.ChildNodes[7].InnerText).Length -
1) + ". \r\n");
logcount += 1;
//The directory specified in the <SPBackupDirectory> is deleted and the
//deletion is recorded in the log
//deletion is recorded in the log
if (Directory.Exists(bup.ChildNodes[7].InnerText.Substring(0,
(bup.ChildNodes[7].InnerText).Length - 1)) == true)
(bup.ChildNodes[7].InnerText).Length - 1)) == true)
{
Directory.Delete(bup.ChildNodes[7].InnerText.Substring(0,
(bup.ChildNodes[7].InnerText).Length - 1));
(bup.ChildNodes[7].InnerText).Length - 1));
File.AppendAllText(log, DateTime.Now + "\t Deleted: " + bup.ChildNodes[7].InnerText.Substring(0, (bup.ChildNodes[7].InnerText).Length - 1) + ". \r\n");
}
else
{
{
File.AppendAllText(log, DateTime.Now + "\t Deleted: " + bup.ChildNodes[7].InnerText.Substring(0, (bup.ChildNodes[7].InnerText).Length - 1) + ". \r\n");
}
logcount += 1;
}
}
}
catch (Exception ex) {
//If an error occurs during the deletion of the node or directory an entry is made in the log
File.AppendAllText(log, DateTime.Now + @"\t Error: Could not delete the directory or remove the historic backup node. \t" + DateTime.Now + " \tReason: " + ex.Message + "\r\n");
logcount += 1;
}
try {
//The changes made to the spbrtoct.xml are saved back to the directory and if an error occurs then an entry is made in the log
doc.Save(spbr);
}
catch (Exception ex) {
File.AppendAllText(log, DateTime.Now + @"\t Error: Could not save changes made to spbrtoct.xml. \t" + DateTime.Now + "\t Reason: " + ex.Message + "\r\n");
logcount += 1;
}
if
(logcount == 0) {
(logcount == 0) {
File.AppendAllText("C:\\BackupCleanUp.log", "############################ Nothing Logged Completed At " + DateTime.Now + " ########################### \r\n");
}
}
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
}
Once the script task is completed then drop an Execute Process Task onto the control flow pane and connect the script tasks success precedent constraint to the Execute Process Task.
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\Bin\STSADM.exe
the Arguments should be:
-o backup -directory "\\SERVER\MOSS Backup" -backupmethod full
and the WorkingDirectory should be configured as:
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\Bin\
***Keep in mind my requirements are for a farm backup so the below screen shot of the command line arguments are for a full farm back up.
After I completing this package I began to obsess about all of the possible enhancements I could include, bells, whistles, features, etc, but was soon called back to reality with the oh so familiar, “C’mon man!! We got other projects to complete!!” The one enhancement I do plan on implementing is to create an SSIS variable that will be assigned the script error and package messages, using the OnError event handler, and then emailed using a Send Mail Task.
I have done my best to clean up the script task code to make it easy to cut and paste, but I finally gave up so please contact me if there are any question.


