Tuesday, March 20, 2007

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();
            }
        }
 
    }
}

Monday, February 19, 2007

MOSS : Microsoft Best Practices Analyzer for Windows SharePoint Services 3.0 and the 2007 Microsoft Office System released

From Daniel McPherson's (new) blog :

Typical, the minute I leave Premier Field Engineering, is the minute we decide to release the tool that would have transformed my life!

Download details: 2007 Office System Tool: Microsoft Best Practices Analyzer for Windows SharePoint Services 3.0 and the 2007 Microsoft Office System

http://www.microsoft.com/downloads/details.aspx?familyid=cb944b27-9d6b-4a1f-b3e1-778efda07df8&displaylang=en

I used it on a costumer environment and it shows no problems.. well ok.. one..  I unchecked the participation with customer feedback program :\

MOSS & SQL2k5 SP2 = :D

When I did a POC for a customer with MOSS and Excel Services where I demo'd the capability of Excel 2007 being used as a BI reporting tool and that this new type op report could be stored onto a sharepoint site where the users who did not have Excel2007 (or any version of Excel for that matter) could see and interact with the report like they would with a reporting server report. During that demo I 'livesearched' ;) on webparts for reporting server to show the customer that previously build reports using reporting server could also be shown. Unfortunatly during that time (couple of weeks ago) there were no reporting server webparts available for MOSS. The only thing that was available was a CTP of SP2 for SQL2k5. Again it was unfortunate because the software was running on 64bits hardware and there were no plans about releasing 64bits CTP versions for SP2.

Today I read some exciting news on the Sharepoint teams blog and instead of copy and pasting the whole post I recommend you read it yourself on Microsoft SQL Server 2005 SP2 Reporting Services integration with WSS 3.0 and MOSS 2007!

Well ok.. a short summary:

  • Single consistent user interface for managing and viewing reports.
  • A much richer user experience.
  • Storing reports in Office SharePoint Server 2007 document libraries. This allows a report to use standard Office SharePoint Server 2007 features, such as workflow, versioning, and collaboration.
  • Reports and all associated resources are stored within the Office SharePoint Server 2007 database and are automatically synchronized with the same reports that are stored and executed from the report server. Scheduling, caching, and subscriptions are stored in the report server database only because this functionality is not available natively in a SharePoint document library.
  • Single security model for reports because they are treated like any other document inside a SharePoint document library.
  • Common report filtering paradigm that is used in SharePoint document libraries and filtering Web Parts.

Special report integration in reports library list:

                  • Edit in Report Builder – Reporting Services functionality to launch the Report Builder tool to edit the definition of the report (see Figure 6). Report Builder enables end-users to easily modify or create reports and publish them to the Office SharePoint Server 2007.
                  • Delete – Standard Office SharePoint Server 2007 functionality to delete the document from the document library.
                  • Manage Subscriptions – Reporting Services functionality to add, edit, and delete report subscriptions. Users that subscribe to reports can automatically be notified when data changes in reports. For example, sales people can subscribe to a report to automatically receive their weekly sales figures via email.
                  • Manage Data Sources – Reporting Services functionality to select a shared or custom data source for the report. Shared data sources enable one data source definition to be used across multiple reports.
                  • Manage Parameters – Reporting Services functionality to manage the values and prompts for all parameters passed into the report. Parameters are a way to limit the data that is displayed in a report. For example, a report parameter named Year can be specified to limit the report data to the selected year when the report is run.
                  • Manage Processing Options – Reporting Services functionality to choose processing and snapshot options and timeouts. Snapshots and timeouts affect the performance of the Reporting Services server. It is important to consider these options to keep the server performing as well as possible.
                  • View Report History – Reporting Services functionality to view the history of report processing.

                  So it's totally brilliant! No more that (lousy) user interface of reporting server. It's all integrated in Sharepoint :)

                  Back from berlin

                  Well just got back from the Sharepoint Conference that was held in the Estrel Hotel in Berlin. I must say that I was a bit disappointed by the lack of depth of the presentations, although it was very cool to see all the famous names in the Sharepoint community like Lawrence Lui, Mike Fitzmaurice, Patrick Tisseghem and our very own Bart Wessels :)

                  I did saw a very interesting Business Data Catalog presentation by Mike where he gave Nick Swan a chance to demo the BDC MetaMan that is created by him and Todd S Baginski. It looked very promising so I reckon you should check it out! I know I will when the time is there :)

                  Also during the conference it was made clear that the community should check http://sharepoint.microsoft.com/sharepoint (that actually is based on MOSS) as it is a central place for all your Sharepoint needs  ..

                  Monday, February 05, 2007

                  MOSS Install : 32 bit emulation mode in IIS

                  If you are running the MOSS installer (or WSS v3 for that matter) on a x64 machine with Windows 2003 64bit installed and you get an error that sounds like 'IIS in running 32-bit emulation mode, please fix this error to continue' you must run the following script from the command line : CScript "%SystemDrive%\InetPub\AdminScripts\adsutil.vbs" set w3svc/AppPools/Enable32bitAppOnWin64 1 And do an IISRESET after that! Thanks to Adrian Hamza!