Sunday, March 25, 2007

WSS v3 : Visual Studio 2005 Extensions released

Good news for us developers, version 1.0 of the Windows SharePoint Services 3.0 Tools: Visual Studio 2005 Extensions is now released! Grab your copy from the Microsoft site.

Things that bother me though are the system requirements :

System Requirements
  • Supported Operating Systems: Windows Server 2003
  • Windows SharePoint Services 3.0 (Basic installation only), or any product built on Windows SharePoint Services 3.0, such as Microsoft Office SharePoint Server 2007
  • Visual Studio 2005 (Standard Edition, Professional Edition, or Team System)

It's kinda odd isn't it? The CTP ran perfectly without needing Sharepoint and Win2k3 on my laptop.

Friday, March 23, 2007

SharePoint Information Architecture and the Information Architect

If you are, like me, a mix of a Sharepoint developer as well as a consultant and a bit of an architect you should definitly check out SharePoint Information Architecture and the Information Architect from Joel Oleson. He clearly points out what to think about when you are about to design and implement Sharepoint for customers and how to already deal with things the future may be bring.

Wednesday, March 21, 2007

MOSS/WSS 2007: Floating toolpane

From Vincent Rothwell comes this nice little add-on that enables the toolpane, which you use to edit properties of a particular webpart, to float. Another nice features of this is that is also resizeable and it can be minimized :) Nice work mate!

 

Vista: Dreamscene

Have you guys seen Dreamscene yet on Vista? It's one of the most useless features ever created but damn it's cool! Basically, if you don't know what it is, it's a movieclip that runs on your desktop instead of a backgroundpicture. But the movieclips that are included are so subtle (apart from the "rain-on-the-street" clip, that's just depressing :P) you hardly even notice that is 'moving'. And you got to have the Ultimate version of Vista installed to enable it (maybe when Dreamscene is released it will be made available for every copy of Vista?)

Check out the movieclip below to see what is like : 

Format: wmv
Duration: 00:16

Check out the Dreamscene Team blog at : http://windowsultimate.com/blogs for more information

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