I had a requirement from customer to develop an archival workflow solution using which they can automate the Site Collection archival based on a set of business rules. The features should be, notify users for the key LOB information expiration based on which the sites were created, Maintain the notification count and based on the count take a call to make a particular site read-only, offline or take a back up & delete it permanently from the content database in case of no action taken to update the key LOB information.
And, just to give you a little idea about the size of the farm, it’s in TBs and there are thousands of site collections created automatically across multiple content databases through an automated process. so to do the above steps manually for each site collection based on different notification counter values and repeat it every week, was just impossible and that’s how we decided for an automatic site archival solution.
The purpose of this blog post is to give you an idea about the various features and parts of the solution so in case you come across any of the similar business requirement in future then can make use of some of these ideas or code snippets and make your life little easier
This solution has several features like
And following are the configuration features of the solution
So here is how I designed these configuration features
For Configurable LOB pointer & Workflow Admins list, I kept txt files with solution which would contain the connection and Administrator details respectively so can be modified anytime.
Created XML for the email templates and would read the specific template from the code using template id.
Built whole application as an exe so can be configured with windows task scheduler.
Since no deployment of WSP to SharePoint and solution is just a stand alone exe, no IISReset/ App Pool Recycle required.
Used Event viewer for writing the execution log.
Now following are a few Code Snippets which are used for the above functionalities.
For txt read
try
{
const string f = "ConnectionString.txt";
using (StreamReader r = new StreamReader(f))
connectionString = r.ReadLine();
}
catch (Exception ex)
WritetoEventViewer("Exception(ConnectionString Fileread) : " + ex.Message.ToString());
To check user validity with directory services
static bool checkValidUser(string UserID)
bool isValid = false;
using (var ctx = new PrincipalContext(ContextType.Domain))
var user = UserPrincipal.FindByIdentity(ctx, UserID);
if(user != null)
isValid = true;
user.Dispose();
WritetoEventViewer("Exception(Checking AD User Validation) : " + ex.Message.ToString());
return isValid;
static void GetMailTemplates()
mailTemplates = new string[3, 5];
int i = -1, j = 0;
XmlTextReader reader = new XmlTextReader("EmailTemplates.xml");
while (reader.Read())
if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "template"))
i++;
j = 0;
//to save from array overload
if (i == 2)
break;
if (reader.NodeType == XmlNodeType.Text)
mailTemplates[i, j] = reader.Value.ToString().Trim('\n', '\r', ' ');
j++;
WritetoEventViewer("Exception(Getting Mail Templates) : " + ex.Message.ToString());
To make NoAccess to the Site Collection
bool operation = false;
using (SPSite site = new SPSite(url))
site.WriteLocked = true;
site.LockIssue = "Making site collection NoAccess as per the Archival Workflow";
site.ReadOnly = true;
site.ReadLocked = true;
operation = true;
operation = false;
WritetoEventViewer("Exception(Making SiteCollection Offline) : " + ex.Message.ToString());
To backup & move the Site Collection in a shared location
string bkLocation = @"c:\";
string bkFileName = DateTime.Now.ToString() + ".bak";
bkFileName = bkFileName.Replace("/", "");
bkFileName = bkFileName.Replace(":", "-");
SPWebApplication webApp = site.WebApplication;
SPSiteCollection siteCol = webApp.Sites;
siteCol.Backup(url, bkFileName, true);
//Move the file to destination after creation
File.Move(bkFileName, bkLocation + bkFileName);
WritetoEventViewer("Exception(SiteCollection Backup) : " + ex.Message.ToString());
To delete Site Collection
//Making site accessible if it is made NoAccess
site.WriteLocked = false;
site.ReadOnly = false;
site.ReadLocked = false;
//Delete the site
site.Delete();
WritetoEventViewer("Exception(SiteCollection Deletion) : " + ex.Message.ToString());