SPS/WSS 2003 : Intelligent backup procedure
Ok, so it's a bad practice to use STSADM to backup your sites (check Keith Richie's post and his implementation of a new backup application Permanent Link to Perform non-intrusive Site Collection level backups with SPLSBackup) The backup procedure of the environment of the customer I'm currently located at, takes up about 12hrs per day (about 200+gb over 450+ sites). This is, ofcourse, unacceptable since the backup runs during working hours.
As we are facing an upgrade to MOSS, the implementation of the recycle bin for 2003 is not desirable because 1. it takes too much effort of the business and 2. the problem had to be solved real soon
As a result I created an new backup application using the object model of Sharepoint. Instead of backing every site every day, I only check if a site is changed (ContentLastModified or SecurityLastModified) and only back up that site.
And to make it even more fancy I store the results of every backup (including: sizing and duration of the backup) in a list on a Sharepoint site that is designed for monitoring (later in MOSS I even can use the KPI capabilities to make it more fancy :))
btw. The StopWatch function came from http://www.codinghorror.com/blog/archives/000460.html so thanks Jeff Atwood :)
using System;
using System.Collections;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace IncrementBackup
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// Application consists of three functions.
/// 1. Get all the sites that were modified today. Either content or security wise
/// 2. Backup all the sites that were collected in the previous function
/// 3. Push information about the backups into a custom Sharepoint List to
/// To store all the relevant data about a site, I created a class called "SiteItem.cs"
/// To monitor the time of each backup, I found a sample code with acts as a stopwatch "StopWatch.cs"
/// </summary>
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Getting sites");
ArrayList sites = GetSites();
foreach (SiteItem item in sites)
{
Backup(item);
}
Console.WriteLine("Pushing data into Sharepoint");
InsertDataIntoList(sites);
}
//***Function to get all the teamsites***
//Instead of backupping with this function,
//I only collect the urls of the site which have been changed.
//The reason is that if I backup immediatly,
//the lastmodifieddate and securitymodifieddate are not accurate
//anymore since the backup could take more than 12 hours.
private static ArrayList GetSites()
{
ArrayList sites = new ArrayList();
try
{
//Get the sitecollection through the Administration model using SPGlobalAdmin and SPVirtualServer
SPGlobalAdmin globalAdmin = new SPGlobalAdmin();
System.Uri uri = new System.Uri(PortalUrl);
SPVirtualServer virtualServer = globalAdmin.OpenVirtualServer(uri);
SPSiteCollection siteCollections = virtualServer.Sites;
//For each site in the sitecollection collect all relevant information from which the content or security is changed today
foreach (SPSite site in siteCollections)
{
if (site.LastContentModifiedDate.Date == DateTime.Today.Date || site.LastSecurityModifiedDate.Date == DateTime.Today.Date)
{
SiteItem item = new SiteItem();
item.SiteName = site.RootWeb.Title.ToString();
item.Url = site.RootWeb.Url.ToString();
item.ModifiedContentDate = site.LastContentModifiedDate;
item.ModifiedSecurityDate = site.LastSecurityModifiedDate;
//We also want to publish information about the sizing of the site
SPSite.UsageInfo info = site.Usage;
item.Size = Convert.ToString(info.Storage / 1024 / 1024);
//Here we put the object into the ArrayList
sites.Add(item);
}
//Disposing of the objects
site.RootWeb.Close();
site.RootWeb.Dispose();
site.Close();
site.Dispose();
}
}
catch (Exception error)
{
Console.WriteLine(error.Message.ToString());
}
return sites;
}
//***Function to backup every single site
private static void Backup(SiteItem item)
{
//To monitor how long each backup takes I found a sample code of using a stopwatch
Stopwatch sp = new Stopwatch();
sp.Start();
//Since it's not possible to declare these functions as a public variable, we have to declare them again
//to backup each site
SPGlobalAdmin globalAdmin = new SPGlobalAdmin();
System.Uri uri = new System.Uri(PortalUrl);
SPVirtualServer virtualServer = globalAdmin.OpenVirtualServer(uri);
Console.WriteLine(item.Url);
//Open the site using the URL which is stored in the SiteItem object
SPSite site = virtualServer.Sites[item.Url];
try
{
//Backup the site
Console.WriteLine("Site is currently being backupped");
//Replacing all the odd characters to ensure that a correct filename can be made
string normal = item.SiteName;
normal = normal.Replace("/", "");
normal = normal.Replace(" ", "_");
normal = normal.Replace("@", "_");
normal = normal.Replace("&", "_");
normal = normal.Replace("(", "");
normal = normal.Replace("}", "");
normal = normal.Replace(":", "_");
normal = normal.Trim();
item.SiteName = normal;
//Only backup the teamsites, not the portal
if (item.Url.IndexOf("sites", 0, item.Url.Length - 1) > -1)
{
//The actual backup
virtualServer.Sites.Backup(item.Url, @"\\fileshare\teamsites\" + item.SiteName + ".bak", true);
}
Console.WriteLine("Backup is made");
}
catch (Exception error)
{
//If an error is raised, we want to see them in the list where we are pushing all the SiteItem objects into
item.ErrorMessage = error.Message.ToString();
Console.WriteLine(error.Message.ToString());
}
finally
{
//Dispose all the objects
site.Close();
site.Dispose();
}
sp.Stop();
item.Duration = sp.Elapsed;
}
//***Function to push all the information about the backups into a custom list
private static void InsertDataIntoList(ArrayList sites)
{
//Open the site where the list belongs to
SPSite site = new SPSite(TeamSiteForMonitoring);
SPWeb web = site.RootWeb;
try
{
//Open the list
SPList list = web.Lists["Sitebackups"];
//Foreach backup that was made we push them in the list
foreach (SiteItem _item in sites)
{
SPListItem item = list.Items.Add();
item["Title"] = _item.SiteName;
item["Duration"] = "Minutes : " + _item.Duration.Minutes.ToString() + " Seconds: " + _item.Duration.Seconds.ToString() + " Miliseconds: " + _item.Duration.Milliseconds.ToString();
item["Last_x0020_modified_x0020_date"] = _item.ModifiedContentDate.ToShortDateString();
item["Last_x0020_Security_x0020_modifi"] = _item.ModifiedSecurityDate.ToShortDateString();
item["Size"] = _item.Size + "mb";
item["Error"] = _item.ErrorMessage.ToString();
item["Link"] = _item.Url.ToString();
item.Update();
}
}
catch (Exception error)
{
Console.WriteLine(error.Message.ToString());
}
finally
{
//Dispose all the objects
web.Close();
web.Dispose();
site.Close();
site.Dispose();
}
}
}
}
1 comment:
Please let me know how SiteItem.cs
looks like.Like to get the code plz
Post a Comment