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 todayforeach (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 siteSPSite.UsageInfo info = site.Usage;
item.Size = Convert.ToString(info.Storage / 1024 / 1024); //Here we put the object into the ArrayListsites.Add(item);
}
//Disposing of the objectssite.RootWeb.Close();
site.RootWeb.Dispose();
site.Close();
site.Dispose();
}
}
catch (Exception error)
{ Console.WriteLine(error.Message.ToString());}
return sites;}
//***Function to backup every single siteprivate 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 objectSPSite site = virtualServer.Sites[item.Url];
try { //Backup the siteConsole.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 portalif (item.Url.IndexOf("sites", 0, item.Url.Length - 1) > -1)
{ //The actual backupvirtualServer.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 intoitem.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 listprivate 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 listforeach (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 objectsweb.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