Oct 21 2008

Retrieve All Documents from SharePoint

I needed a way to quickly retrieve all documents from SharePoint. You can specify which files to retrieve by changing the WHERE clause in the SQL query.  Otherwise, just pass it a path for the output files and set the connection string for your SharePoint content database.

Props to Michael O’Donovan for his helpful article on recovering SharePoint files.

public static void GetDocs(string path)
{
    SqlConnection _conn = new SqlConnection(Settings.Default.conn);
 
    string sql = "SELECT AllDocs.LeafName, AllDocs.DirName, AllDocStreams.[Content] ";
    sql += "FROM AllDocs INNER JOIN AllDocStreams ON AllDocStreams.Id = AllDocs.Id AND AllDocs.[Level] = AllDocStreams.[Level] ";
    sql += "WHERE AllDocs.IsCurrentVersion = 1 AND right(AllDocs.LeafName, 4) in ('.doc','.pdf','.xls','.csv','.ppt','docx','xlsx','pptx','.rtf','.txt','.xps','.mdb','.msg','.wmv','.xsn','.vsd')";
 
    SqlCommand getEmp = new SqlCommand(sql, _conn);
 
    FileStream fs;                          // Writes the BLOB to a file (*.bmp).
    BinaryWriter bw;                        // Streams the BLOB to the FileStream object.
    int bufferSize = 100;                   // Size of the BLOB buffer.
    byte[] outbyte = new byte[bufferSize];  // The BLOB byte[] buffer to be filled by GetBytes.
    long retval;                            // The bytes returned from GetBytes.
    long startIndex = 0;                    // The starting position in the BLOB output.
    string filename = string.Empty;         // The orignial filename.
    string outfile = string.Empty;
    string subpath = string.Empty;
    int i = 0;
 
    // Open the connection and read data into the DataReader.
    _conn.Open();
    SqlDataReader myReader = getEmp.ExecuteReader(CommandBehavior.SequentialAccess);
 
    while (myReader.Read())
    {
        i++;
 
        // Get the filename and build the file path for the output files.
        filename = myReader.GetString(0);
        subpath = myReader.GetString(1).Replace("/", "\\") + "\\";
        outfile = path + subpath + filename;
 
        if (!Directory.Exists(path + subpath))
        {
            Directory.CreateDirectory(path + subpath);
        }
 
        // To prevent overwriting files.
        if (File.Exists(outfile))
        {
            outfile = path + subpath + "_" + i.ToString() + filename;
        }
 
        // Create a file to hold the output.
        fs = new FileStream(outfile, FileMode.Create, FileAccess.Write);
        bw = new BinaryWriter(fs);
 
        // Reset the starting byte for the new BLOB.
        startIndex = 0;
 
        // Read the bytes into outbyte[] and retain the number of bytes returned.
        retval = myReader.GetBytes(2, startIndex, outbyte, 0, bufferSize);
 
        // Output status messages
        string msg = String.Format("{0} ", subpath + filename); 
        Console.Write(Right(msg,48));
 
        while (retval == bufferSize)
        {
            bw.Write(outbyte);
            bw.Flush();
 
            // Reposition the start index to the end of the last buffer and fill the buffer.
            startIndex += bufferSize;
            retval = myReader.GetBytes(2, startIndex, outbyte, 0, bufferSize);
        }
 
        // Write the remaining buffer.
        bw.Write(outbyte, 0, (int)retval);
        bw.Flush();
 
        // Close the output file.
        bw.Close();
        fs.Close();
        Console.Write(" [Complete]");
        Console.WriteLine();
    }
 
    // Close the reader and the connection.
    myReader.Close();
    _conn.Close();
}


Apr 18 2008

Working with Users and Groups in SharePoint 2007

As I am about to show you, one of the easier things to do in SharePoint (programmatically) is that add a user to a group and add a user or group to a site.

I’ll be using the SharePoint web service to do this, so first we need to setup the web reference.  Add a web reference to your project using the URL: http://[sitename]/_vti_bin/usergroup.asmx (of course you’ll substitute your site name).

Then we need to setup the web service object (I named my web reference AdminService):

   1: static AdminService.UserGroup userService = new AdminService.UserGroup();
   2: userService.Credentials = System.Net.CredentialCache.DefaultCredentials;

NextI have an enum, class and method to make it easy to remember and work with the different permission types.

   1: /// <summary>
   2: /// Enumeration representing the various permission levels in SharePoint
   3: /// </summary>
   4: public enum SharePointPermissionType
   5: {
   6:     /// <summary>
   7:     /// Full Control - Has full control.
   8:     /// </summary>
   9:     [Description("Full Control")]
  10:     FullControl, 
  11:     /// <summary>
  12:     /// Design - Can view, add, update, delete, approve, and customize.
  13:     /// </summary>
  14:     Design,
  15:     /// <summary>
  16:     /// Manage Hierarchy - Can create sites and edit pages, list items, and 
  17:     /// documents.
  18:     /// </summary>
  19:     [Description("Manage Hierarchy")]
  20:     ManageHierarchy,
  21:     /// <summary>
  22:     ///  Approve - Can edit and approve pages, list items, and documents. 
  23:     /// </summary>
  24:     Approve, 
  25:     /// <summary>
  26:     /// Contribute - Can view, add, update, and delete.
  27:     /// </summary>
  28:     Contribute, 
  29:     /// <summary>
  30:     /// Read - Can view only.
  31:     /// </summary>
  32:     Read,
  33:     /// <summary>
  34:     /// Restricted Read - Can view pages and documents, but cannot view historical 
  35:     /// versions or review user rights information.
  36:     /// </summary>
  37:     [Description("Restricted Read")]
  38:     RestrictedRead,
  39:     /// <summary>
  40:     /// View Only - Members of this group can view pages, list items, and documents. 
  41:     /// If the document has a server-side file handler available, they can only view 
  42:     /// the document using the server-side file handler.
  43:     /// </summary>
  44:     [Description("View Only")]
  45:     ViewOnly
  46: }

   1: /// <summary>
   2: /// This internal class is used in conjunction with the SharePointPermissionType enum.  
   3: /// It allows for the definition of values as strings.
   4: /// </summary>
   5: class Description : Attribute 
   6: { 
   7:     public string Text; 
   8:     public Description(string text) 
   9:     { 
  10:         Text = text; 
  11:     } 
  12: }

Place this within the class where you’re using the enum:

   1: /// <summary>
   2: /// Used in conjunction with the SharePointPermissionType enum. It returns the value 
   3: /// as a string.
   4: /// </summary>
   5: /// <param name="en">SharePointPermissionType</param>
   6: /// <returns>String representation of a SharePointPermissionType</returns>
   7: private string GetDescription(Enum en)
   8: {
   9:     Type type = en.GetType();
  10:     MemberInfo[] memInfo = type.GetMember(en.ToString());
  11:     if (memInfo != null && memInfo.Length > 0)
  12:     {
  13:         object[] attrs = memInfo[0].GetCustomAttributes(typeof(Description), false);
  14:         if (attrs != null && attrs.Length > 0)
  15:             return ((Description)attrs[0]).Text;
  16:     }
  17:     return en.ToString();
  18: }

 

Finally the meat & potatoes…

Add a user to a SharePoint Group (SPGroup):

   1: /// <summary>
   2: /// Adds a user to a group
   3: /// </summary>
   4: /// <param name="userName">username of user to add</param>
   5: /// <param name="groupName">group name</param>
   6: /// <param name="userEmail">user's email address</param>
   7: public void AddUserToGroup(string userName, string groupName, string userEmail)
   8: {
   9:     try { userService.AddUserToGroup(groupName, userName.Replace("CSUpmProvider:", ""), userName, userEmail, ""); }
  10:     catch { }
  11: }

 

Add a user to a SharePoint Site (SPSite):

   1: /// <summary>
   2: /// Adds a user to a site
   3: /// </summary>
   4: /// <param name="userName">username of the user to add</param>
   5: /// <param name="siteUrl">url of the site</param>
   6: /// <param name="permission">permission level to grant the group on the site.</param>
   7: public void AddUserToSite(string userName, string siteUrl, SharePointPermissionType permission)
   8: {
   9:     OpenSite();
  10:     SPWeb web = _site.OpenWeb(siteUrl);
  11:     SPMember member = web.ParentWeb.ParentWeb.AllUsers[userName];
  12:     if (member != null)
  13:     {
  14:         SPRoleAssignment roleAssignment = new SPRoleAssignment((SPPrincipal)member);
  15:         SPRoleDefinitionBindingCollection roleDefBindings = roleAssignment.RoleDefinitionBindings;
  16:         roleDefBindings.Add(web.RoleDefinitions[GetDescription(permission)]);
  17:         web.RoleAssignments.Add(roleAssignment);
  18:     }
  19:     web.Close();
  20:     web.Dispose();
  21:     CloseSite();
  22: }

 

Add a Group to a Site:

   1: /// <summary>
   2: /// Adds a group to a site
   3: /// </summary>
   4: /// <param name="group">SharePoint group</param>
   5: /// <param name="siteUrl">url of the site.</param>
   6: /// <param name="permission">permission level to grant the group on the site.</param>
   7: public void AddGroupToSite(SPGroup group, string siteUrl, SharePointPermissionType permission)
   8: {
   9:     OpenSite();
  10:     SPWeb web = _site.OpenWeb(siteUrl);
  11:     SPMember member = web.SiteGroups[group.Name];
  12:  
  13:     if (member != null)
  14:     {
  15:         SPRoleAssignment roleAssignment = new SPRoleAssignment((SPPrincipal)member);
  16:         SPRoleDefinitionBindingCollection roleDefBindings = roleAssignment.RoleDefinitionBindings;
  17:         roleDefBindings.Add(web.RoleDefinitions[GetDescription(permission)]);
  18:         web.RoleAssignments.Add(roleAssignment);
  19:         web.Update();
  20:     }
  21:     web.Close();
  22:     web.Dispose();
  23:     CloseSite();
  24: }

 

Finally you’ll notice I keep using the methods OpenSite() and CloseSite().  These simply open and close the SPSite _site object:

   1: /// <summary>
   2: /// Opens a SharePointSite
   3: /// </summary>
   4: /// <returns>SPSite object representing the base site collection</returns>
   5: private SPSite OpenSite()
   6: {
   7:     CloseSite();
   8:     _absoluteUrl = "http://myspsite.com";
   9:     _site = new SPSite(_absoluteUrl);
  10:     return _site;
  11: }
  12:  
  13: /// <summary>
  14: /// Close opened site
  15: /// </summary>
  16: private void CloseSite()
  17: {
  18:     if (_site != null)
  19:     {
  20:         _site.Close();
  21:         _site.Dispose();
  22:         _site = null;
  23:     }
  24: }


Apr 17 2008

Create a new alert for a SharePoint list

A code snippet for creating a new alert for a SharePoint list.  The OpenSite() method simply creates an SPSite object named which I’ve named _site.

Make sure that your alertUser has permissions to the list. Also you need to set the property AlwaysNotify = false.  For some reason it doesn’t seem to work if you don’t set this property.

public void CreateAlert(SPList list, SPUser alertUser, string alertTitle, bool notify)

        {

            OpenSite();

            try

            {

                SPWeb web = _site.AllWebs[list.ParentWebUrl];

                SPAlertCollection alerts = web.Alerts;

 

                // get the lists alert template and apply that to the new alert

                SPAlertTemplate alertTemplate = list.AlertTemplate;

                alertTemplate.Name = list.AlertTemplate.Name;

 

                // setup the alert

                SPAlert alert = alerts.Add();

                alert.AlertType = SPAlertType.List;

                alert.AlertTemplate = alertTemplate;

                alert.Title = alertTitle;

                alert.EventType = SPEventType.Add;

                alert.AlertFrequency = SPAlertFrequency.Immediate;

                // make sure to set this to false. Don't know why but doesn't seem to work if you don't.

                alert.AlwaysNotify = false;

                alert.User = alertUser;

                alert.List = list;

                alert.Update(notify);

                

                // cleanup

                web.Close();

                web.Dispose();

            }

            catch

            {

                Console.WriteLine("Unable to create alert");

            }

            CloseSite();

        }


Apr 16 2008

Creating and deploying a custom site definition for MOSS 2007

I’ve spent the last couple weeks trying to create a custom site definition for SharePoint 2007. If you’re unsure of what a custom site definition is and how it differs from a site template, there is a good MSDN article which explains both.

I found a bunch of good resources out there that describe the steps in creating a custom site definition, but none gave me everything I needed. I will give a brief rundown of the steps that I followed, and provide links to the articles that I referenced.

  1. Download WSPBuilder and the WSPBuilder Extensions for Visual Studio. (I believe you need to install the Visual Studio SDK prior to installing the extensions)
  2. In Visual Studio create a new WSPBuilder Project.
  1. I don’t know if it is supposed to be this way or just a problem that I was having, but it did not create the entire 12 hive folder structure like I thought it would. To fix this, I ran WSPBuilder.exe –createfolder true from the command line, and then added the resulting folder structure to my Visual Studio project.
  • Then follow these steps: Creating a Custom WSS Site Definition [2007]
    1. In the example from that article, the author uses a folder named SampleMPS. In your Visual Studio project, you will be using the \12\TEMPLATE\ directory.
  • Now, I wanted to associate a custom masterpage to my site definition. The steps I followed to do that are outlined here: http://statto1974.wordpress.com/2007/04/30/using-a-custom-master-page-in-a-site-definition/. Put your master file in the \12\TEMPLATE\SiteTemplates\v2DefaultOrg\ (where v2DefaultOrg is whatever you named your site definition) directory, beside the default.aspx file. Below is a screenshot of my project folder structure. You’ll notice the eight folders in my FEATURES folder. The first is a feature that, when activated, associates a site with a new custom masterpage (read more). The remaining seven are custom list definitions. I have two site definitions in my project 1) v2DefaultOrg and 2) v2DefaultUser.
    clip_image002
  • Once you have everything setup as you like. Right-click on the project and choose WSPBuilder –> Deploy. Then go into SharePoint and test out your Site Definition by creating a new site using it.
  • When you’re ready and it’s time to package it up and deploy it on your production SharePoint farm. Right-click on the project again and choose WSPBuilder –> Create deployment folder.
  • Then go to your project BIN folder and you’ll see a deploy folder. Inside this folder you should see a setup.exe and a .wsp file. The .wsp file is the Solution Package, and the setup.exe is from the SharePoint Solution Installer project on CodePlex. You’ll need to create and modify a configuration file as described on the SharePoint Solution Installer home page.
  • Then you simply need to run the setup.exe and the project should install on your SharePoint farm.
  • As I’ve found creating and deploying a custom site definition can be frustrating. Hopefully the information I’ve provided will be of help to someone.