Configure Retention Policy through Code

September 4th, 2011 No comments

Information Policies are nice to have it. It is also a reasonably simple job to configure an IM policy through user interface. But in order to automate the process, sometime you want to configure IM policies from code. In the below example I will give you some hint that how you can configure retention policy from the code. 

For this test I have created a content type in content type hub. Yes I recommend, plan your content types properly and use content type hub on all the possible places. It is a great feature in SharePoint 2010. Alright back to the today’s topic. Open visual studio 2010 and create a feature. Add a feature receiver to the feature and start writing the code. 

Something is better to understand on the first hand about retention policy. Retention policy can be defined for records and non-records.  Also you can set different stages for a retention policy and can set different actions for each stage. 

/// <summary>
/// Defines a constant used as the key for the workflow template name.
/// </summary>
private const string WorkFlowTemplateName = "Disposition Approval";

/// <summary>
/// Defines a constant used as the key for the Records Centre name to use in SendTo link.
/// </summary>
private const string RecordCenterNameForSendTo = "Corporate Records Centre";

/// <summary>
/// Defines a constant used as the key for the Records Centre name to use in SendTo link.
/// </summary>
private const string RecordCenterURLForSendTo = "<a href="http://archive/_vti_bin/officialfile.asmx">http://archive/_vti_bin/officialfile.asmx</a>";

/// <summary>
/// Gets or sets the SendTo ID.
/// </summary>
protected string SendToId { get; set; }

/// <summary>
/// This method will publish the content types from Content Type Hub.
/// </summary>
/// <param name="properties">The SPFeatureReceiverProperties object.</param>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    try
    {
        if (properties == null)
        {
            throw new ArgumentNullException("properties");
        }

        SPSite site = properties.Feature.Parent as SPSite;

        using (SPWeb web = site.OpenWeb(site.RootWeb.ID))
        {
            this.SendToId = GetRCSendToLinkId(site);

            string ctypeName = "MyContentType";
            SPContentType ctype = web.ContentTypes[ctypeName];
            this.AddPolicyToContentType(ctype);
        }
    }
    catch (Exception e)
    {
        // handle the exception here
    }
}

/// <summary>
/// Returns the SPOfficialFileHost for record center SendTo link.
/// </summary>
/// <param name="site">The feature parent SPSite object.</param>
/// <returns>ID of the send to link.</returns>
protected static string GetRCSendToLinkId(SPSite site)
{
     string sendToID = string.Empty;
     if (site != null)
     {
         string sendToHostName = string.Empty;

         SPSecurity.RunWithElevatedPrivileges(delegate
         {
             SPWebApplication webApp = site.WebApplication;
             for (int i = 0; i < webApp.OfficialFileHosts.Count; i++)
             {
                 SPOfficialFileHost host = webApp.OfficialFileHosts[i];
                 sendToHostName = host.OfficialFileName;

                 if (sendToHostName.Equals(RecordCenterNameForSendTo))
                 {
                     sendToID = host.UniqueId.ToString();
                     break;
                 }
             }
         });
     }

     return sendToID;
}

/// <summary>
/// Add a policy to content type.
/// </summary>
/// <param name="ctype">The content type.</param>
protected void AddPolicyToContentType(SPContentType ctype)
{
    string policyFeatureId = "Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration";

    Policy policy = Policy.GetPolicy(ctype);

    if (policy == null)
    {
        Policy.CreatePolicy(ctype, null);
        policy = Policy.GetPolicy(ctype);
    }

    if (policy.Items[policyFeatureId] == null)
    {
        string customData = string.Empty;

        if (ctype != null)
        {
            string workflowID = string.Empty;
            SPWorkflowAssociation workflowTemplate = ctype.WorkflowAssociations.GetAssociationByName(WorkFlowTemplateName, System.Globalization.CultureInfo.CurrentCulture);

            if (workflowTemplate != null)
            {
                workflowID = workflowTemplate.ParentAssociationId.ToString();
            }

            string ctypeName = ctype.Name;

            if (ctypeName.Equals("MyContentType"))
            {�
                customData = "<Schedules nextStageId='4' default=\"false\">"
                    + "<Schedule type='Default'>"
                    + "<stages>"
                    + "<data stageId='1'>"
                    + "<formula id=\"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn\">"
                        + "<number>1</number>"
                        + "<property>Modified</property>"
                        + "<period>Years</period>"
                    + "</formula>"
                    + "<action type=\"action\" id=\"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Action.DeletePreviousVersions\" />"
                    + "</data>"
                    + "<data stageId='2'>"
                    + "<formula id=\"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn\">"
                        + "<number>1</number>"
                        + "<property>Modified</property>"
                        + "<period>Years</period>"
                    + "</formula>"
                    + "<action type=\"action\" id=\"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Action.SubmitFileLink\" destnExplanation=\"Transferred due to organizational policy\" destnId=\"" + this.SendToId + "\" destnName=\"" + RecordCenterNameForSendTo + "\" destnUrl=\"" + RecordCenterURLForSendTo + "\" />"
                    + "</data>"
                    + "</stages>"
                    + "</Schedule>"
                    + "<Schedule type='Record'>"
                    + "<stages>"
                    + "<data stageId='3' recur='true' offset='1' unit='years'>"
                    + "<formula id=\"Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn\">"
                        + "<number>10</number>"
                        + "<property>_vti_ItemDeclaredRecord</property>"
                        + "<period>Years</period>"
                    + "</formula>"
                    + "<action type=\"workflow\" id=\"" + workflowID + "\" />"
                    + "</data>"
                    + "</stages>"
                    + "</Schedule>"
                    + "</Schedules>";

                policy.Items.Add(policyFeatureId, customData);
            }
        }
    }
}

So what the above code is doing. It is creating a retention policy for provided content type. It is creating
retention policy for non-records (documents) and for records. As you can see you can define multiple stages
for policy. In each stage you can define different actions. Here in first stage it is deleting all the
previous versions and in next stage moving document to record centre. In my case record centre name is
Corporate Record Centre. For records it is staring a disposition workflow after a defined time.
You have to create this disposition workflow for the content type separately.

So that’s all really. Here how it looks after the feature activation.

Have fun ……… :)

Replace the In place Record Action Item in Ribbon

August 26th, 2011 No comments

Recently I worked on an interesting work item. I have been asked to change the In place record action item image in SharePoint ribbon. As you might know adding a custom action in ribbon is just a piece of cake. But when I started looking for records action item, I couldn’t find it in the list of all default custom actions.

So I did some more work on it and found the feature which is adding the custom action.  It is available in 14 hives with the name InPlaceRecords. It uses an action.xml element file. This file defines the custom action for In place record icon in ribbon. Here is the xml for this action file.

<?xml version="1.0" encoding="utf-8"?>
<!-- _lcid="1033" _version="14.0.4758" _dal="1" -->
<!-- _LocalBinding -->
<Elements xmlns="<a href="http://schemas.microsoft.com/sharepoint/">http://schemas.microsoft.com/sharepoint/</a>">
    <Control
        Id="AdditionalPageHead"
        Sequence="70"
        ControlSrc="~/_controltemplates/recordsribbon.ascx">
    </Control>
    <CustomAction
        Id="InPlaceRecordsSettingsSite"
        GroupId="SiteCollectionAdmin"
        Location="Microsoft.SharePoint.SiteSettings"
        Rights="ManageWeb"
        Sequence="110"
        Title="$Resources:dlccore, InPlaceRecords_SettingsLink">
            <UrlAction Url="_layouts/InPlaceRecordsSettings.aspx?Source=settings.aspx" />
    </CustomAction>
    <CustomAction
        Id="InPlaceRecordsSettingsList"
        GroupId="Permissions"
        Location="Microsoft.SharePoint.ListEdit"
        Rights="ManageLists"      �
        Sequence="110"
        Title="$Resources:dlccore, InPlaceRecords_ListSettingsLink">
            <UrlAction Url="_layouts/InPlaceRecordsListSettings.aspx?List={ListId}" />
    </CustomAction>
    <CustomAction
        Id="Ribbon.Documents.Manage.DeclareRecord"
        Location="CommandUI.Ribbon"
        Rights="EditListItems"
        Sequence="17"
        Title="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText">
     <CommandUIExtension>
      <CommandUIDefinitions>
       <CommandUIDefinition Location="Ribbon.Documents.Manage.Controls._children">
              <Button
                Id="Ribbon.Documents.Manage.DeclareRecord"
                Sequence="25"
                Command="DeclareRecord"
                LabelText="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText"
                Image16by16="/_layouts/images/declarerecorditemhs.png"
                Image32by32="/_layouts/images/declarerecorditemhh.png"
                ToolTipTitle="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText"
                ToolTipDescription="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonToolTipDescription"
                TemplateAlias="o1"
              />
       </CommandUIDefinition>
      </CommandUIDefinitions>
     </CommandUIExtension>
    </CustomAction>
    <CustomAction
        Id="Ribbon.ListItems.Manage.DeclareRecord"
        Location="CommandUI.Ribbon"
        Rights="EditListItems"
        Sequence="17"
        Title="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText">
     <CommandUIExtension>
      <CommandUIDefinitions>
       <CommandUIDefinition Location="Ribbon.ListItem.Manage.Controls._children">
              <Button
                Id="Ribbon.ListItem.Manage.DeclareRecord"
                Sequence="25"
                Command="DeclareRecord"
                LabelText="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText"
                Image16by16="/_layouts/images/declarerecorditemhs.png"
                Image32by32="/_layouts/images/declarerecorditemhh.png"
                ToolTipTitle="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonText"
                ToolTipDescription="$Resources:dlccore, InPlaceRecords_DeclareRecordButtonToolTipDescription"
                TemplateAlias="o1"
              />
       </CommandUIDefinition>
      </CommandUIDefinitions>
     </CommandUIExtension>
    </CustomAction>
</Elements>

Now in order to replace it I created a new feature and added an element file in it. I copied the whole action.xml in it and changed the images icon for 32 and 64 sizes. Then I deployed my solution and activated the feature. I realised it worked fine but not as expected. My new custom action was visible there but alongside default action item for In place record. So to remove the default action item, I deactivated site level feature named In Place Record Management feature. This is OOTB feature and required for In place record management.

If you select and item in a list, default In place record action item looks like this.

So that’s all really. My new custom action menu for In place record custom action look like this.

Isn’t this simple. I hope you would have enjoyed it.

Regards

Set Content Types of default list and libraries

July 6th, 2011 No comments

We discussed the branding of the MySite through feature stapling in previous post. Now, what if you have to change the content types of the personal and shared document libraries in the personal MySites.

Unfortunately you cannot do it from feature stapling. As your feature stapler executed before the creation of document libraries and it cannot find the document libraries to set the content type. In simple words you need to set content type after site provisioning, so your code can see the document libraries. I thought we can have a control on the master page which should run on the first time user open the site. But need to run just once.

So the solution is to use the power of SharePoint delegate controls. I created a custom control and then loaded that control in a SharePoint delegate control through a feature. This control set the content types for libraries and after completing the job it deactivated the feature. This deactivation actually removes the custom user control from SharePoint Delegate control. So it executed just once and I got the desired results from an elegant solution.

Lets start the work now……

Use the same project we created last time for MySite branding. Create a custom user control in the MySiteBranding project. Your project will look like this at this stage.

Now add a new feature to hook up your custom user control in a delegate control. Add an empty element to the project and add it to the new ContentTypeFeature. Remember to set the feature scope to Site.

Now load your custom user control to the AdditionalPageHead delegate control. Change your elements.xml file as below.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Control Id="AdditionalPageHead"
           Sequence="80"
           ControlSrc="~/_controltemplates/MysiteBranding/ContentTypeHook.ascx"></Control>
</Elements>

Here is the code for custom user control. I’m assuming that you already added the content types to the site. You can add it through feature stapler.

/// <summary>
/// Defines the MySiteHook class.
/// </summary>
public partial class MySiteHook : UserControl
{
    /// <summary>
    /// Page load method.
    /// </summary>
    /// <param name="sender">object for sender</param>
    /// <param name="e">object for events args </param>
    protected void Page_Load(object sender, EventArgs e)
    {
        SPWeb web = SPContext.Current.Web;
        SPSite site = web.Site;
        string contentTypeFeatureGuid = "6369c736-eff8-4c72-9397-b56fbc456a3b";
        string personalDocLibName = "Personal Documents";
        string sharedDocLibName = "Shared Documents";
        try
        {
            web.AllowUnsafeUpdates = true;

            // Get the SPList objects
            SPList sharedList = web.Lists[sharedDocLibName];
            SPList personalList = web.Lists[personalDocLibName];

            // Your content types has to be added to the site.
            SPContentType customContentType = web.ContentTypes["Salman Docs"];
            AddAsDefaultContentType(sharedList, customContentType);
            AddAsDefaultContentType(personalList, customContentType);
            web.Update();

            // Deactivate the feature that this control is linked to so that this code will not run again.
            bool hasFeature = false;
            foreach (SPFeature feature in site.Features)
            {
                if (feature.DefinitionId.ToString().Equals(contentTypeFeatureGuid, StringComparison.CurrentCulture))
                {
                    hasFeature = true;
                    break;
                }
            }

            if (hasFeature)
            {
                site.Features.Remove(new Guid(contentTypeFeatureGuid));
            }
        }
        finally
        {
            web.AllowUnsafeUpdates = false;
        }
    }

    /// <summary>
    /// This method add the content type as default content type.
    /// </summary>
    /// <param name="list">The SPList object.</param>
    /// <param name="customContentType">The SPContentType object.</param>
    private static void AddAsDefaultContentType(SPList list, SPContentType customContentType)
    {
        // Enable content type management on this list
        list.ContentTypesEnabled = true;
        list.Update();

        // Add the custom content type
        list.ContentTypes.Add(customContentType);
        list.Update();

        // Set it as default content type
        foreach (SPContentType contentType in list.ContentTypes)
        {
            if (contentType.Name != customContentType.Name)
            {
                list.ContentTypes.Delete(contentType.Id);
                list.Update();
            }
        }
    }
}

You have no need to make any change in the master page. If you look in the default master page, you can see that AdditionalPageHead delegate control exists there.

<SharePoint:DelegateControl runat=”server” ControlId=”AdditionalPageHead” AllowMultipleControls=”true”/>

Ok so the last thing you have to do is to add your feature to site definition. Use the existing feature stapling concept and just add this feature as well in the elements file for MySiteStapler. Your feature file will look like this now.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <!-- Feature to staple with MySite host site collection -->
  <FeatureSiteTemplateAssociation Id="13719e8d-0a3d-4a1a-97a9-3e6aa9adf4c5" TemplateName="SPSMSITEHOST#0" ></FeatureSiteTemplateAssociation>
  <!-- Feature to staple with MySite personal site collection -->
  <FeatureSiteTemplateAssociation Id="13719e8d-0a3d-4a1a-97a9-3e6aa9adf4c5" TemplateName="SPSPERS#0" ></FeatureSiteTemplateAssociation>
  <!--MySiteDocs: Feature to replace content types in document libraries for MySite personal site collection-->
  <FeatureSiteTemplateAssociation Id="6369c736-eff8-4c72-9397-b56fbc456a3b" TemplateName="SPSPERS#0" ></FeatureSiteTemplateAssociation>
</Elements>

Ok all is done now just create the site with new site definition. So when you create your new MySite, it will change the master page as we discuss in the last post. Also it will load your custom control to the AdditionalPageHead delegate control. When user opens the MySite first time your control’s code will change the content type of the shared and personal document libraries. So all is done. Your project finally looks like this.

You can use this approach for anything which needs to be done after site provisioning.

MySite Branding for SharePoint 2010

July 4th, 2011 No comments

randing of MySites is always a challenging task. It was complicated in SharePoint 2007 and still confusing in SharePoint 2010. Recently we had a requirement to applying cooperate branding for MySites. I tried to find a reasonable solution but nothing was fitting well in the required scenario. So after completion I decided to share my idea with the world.

Before start applying new branding for MySites. We need to understand that MySites are actually use two different types of site collections. First you need a MySite host site collection and then each personal site is a separate site collection. So we have to apply branding on both sites.

Now come to the main task. There could be different ways to customise the MySites. But the best possible solution would be using feature stapling. If you are new to feature stapler you can see this good post from Chris (http://www.sharepointnutsandbolts.com/2007/05/feature-stapling.html).

So we need to create first feature with Site level scope. This feature will be called MySiteStaplee. This feature will deploy master pages to the site and also change the master page for the site. Right first step would be to create a new project in Visual Studio 2010 and create a feature with Site level scope. It will look like this.

MySite Stapler Project View
Now we need to attach an elements.xml to include the master pages to deploy through this feature. Now it is bit different in Visual Studio 2010. We need to add a module. Add master page in the module, and make changes in the elements.xml file as below.

<?xml version=”1.0″ encoding=”utf-8″?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”>
<Module Name=”MasterPages” List=”116″ Url=”_catalogs/masterpage”>
<File Path=”MasterPages\salman.master” Url=”salman.master” Type=”GhostableInLibrary” />
</Module>
</Elements>

Your project will look like this now.

Now add a property to the master with a value as master name.

<?xml version=”1.0″ encoding=”utf-8″ ?>
<Feature xmlns=”http://schemas.microsoft.com/sharepoint/“>
<Properties>
<Property Key=”MySiteMasterPage” Value=”/_catalogs/masterpage/salman.master”/>
</Properties>
</Feature>

Next thing we need to add a feature event receiver to replace the master page for mysite. For this add feature event receiver with the MySiteStaplee. Your code for featureactivated will look like this.

/// <summary>
/// Key for MySite master.
/// </summary>
private const string MySiteMasterPage = “MySiteMasterPage”;

/// <summary>
/// Set master page on feature activation.
/// </summary>
/// <param>The SPFeatureReceiverProperties object.</param>
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;

if (site != null)
{
SPWeb web = site.RootWeb;
string oldMasterUrl = web.MasterUrl;

web = site.RootWeb;
string newMySiteMasterUrl = properties.Feature.Properties[MySiteMasterPage].Value;
if (!string.IsNullOrEmpty(newMySiteMasterUrl))
{
web.CustomMasterUrl = SPUrlUtility.CombineUrl(web.ServerRelativeUrl, newMySiteMasterUrl);
web.MasterUrl = SPUrlUtility.CombineUrl(web.ServerRelativeUrl, newMySiteMasterUrl);
}

web.Update();
}
}

Ok, so your staple feature is ready. Now you need a stapler to staple your feature with mysite site definition.
In order to achieve this create a new project. Create a new feature in this project with Farm level scope. It will look like this.

Now we need to staple the MySiteStaple with MySite host and MySite personal site definitions. So we need elements file here. Add a new Empty Element from Visual Studio 2010. Remember mysite host site definition’s template name is SPSMSITEHOST and MySite personal site template name is SPSPERS. Your elements file will look like this.

<?xml version=”1.0″ encoding=”utf-8″?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/“>
<!– Feature to staple with MySite host site collection –>
<FeatureSiteTemplateAssociation TemplateName=”SPSMSITEHOST#0″ >
</FeatureSiteTemplateAssociation>
<!– Feature to staple with MySite personal site collection –>
<FeatureSiteTemplateAssociation TemplateName=”SPSPERS#0″ >
</FeatureSiteTemplateAssociation>
</Elements>

Ok so all is done. Now you have to deploy these wsp solutions to the server. This will apply your master page with MySite host and MySite personal site definitions. So whenever you create a new MySite host or whenever a user creates his/her MySite, this feature will replace the master page for the new site. Your final solution structure will look like this in visual studio 2010.

I hope it will help you start the branding. Please wait for my next post with the advance solution required for some more branding issues with MySites.

Cheers.

Add Links in SummaryLinksWebpart using PowerShell scripting

May 23rd, 2011 No comments

More on the automation and adding data in other webparts. In previous post I talked about loading data in ContentEditorWebpart. Now look at SummaryLinkWebpart . Recently when i was working with SummaryLinkWebpart. I realised it is a bit different then other web parts to load links in summaryEditorWebpart. I looked for the internet but I couldn’t find any single example for SummaryLinksWebpart with power shell. So here is the example for others. I hope it will help some folks.

$webpart = new-object  $typeName
$webpartType = $webpart.GetType().ToString()

if($webpartType -eq “Microsoft.SharePoint.WebPartPages.ContentEditorWebPart”)
{
        if($values)
       {
               $keyValuePairs = $values.split(“,”)
               foreach ($keyValuePair in $keyValuePairs)
              {
                       $keyValueArray = $keyValuePair.Split(“|”)

                       [string]$propertyName = $keyValueArray[0].Trim()
                       [string]$propertyValue = $keyValueArray[1].Trim()

                       $sumLink = New-Object Microsoft.SharePoint.Publishing.SummaryLink $propertyName
                       $sumLink.LinkUrl = $propertyValue
                       $webpart.SummaryLinkValue.SummaryLinks.Add($sumLink)
                       $webpart.SummaryLinkValue = $webpart.SummaryLinkValue
              }
       }
}

Cheers

Load data in ContentEditorWebpart using PowerShell scripting

May 23rd, 2011 No comments

If you are working on SharePoint content automation then powershell scripts are the most talked item. But sometime it is very difficult to find the right way to load data in web parts. For different web parts you have to treat differently. Here is the example to load data in ContentEditorWebpart.
I have a powershell function, where I’m passing some values including web part type and HtmlContent. HtmlContent is the text I want to set in ContentEditorWebpart.

$webpart = new-object  $typeName
$webpartType = $webpart.GetType().ToString()

if($webpartType -eq “Microsoft.SharePoint.WebPartPages.ContentEditorWebPart”)
{
        if($HtmlContent)
       {
              [string]$content = $HtmlContent.ToString()
              $docXml = New-Object System.Xml.XmlDocument
              $contentXml = $docXml.CreateElement(“Content”)
              $contentXml.set_InnerText($content)
              $docXml.AppendChild($contentXml)

              $webpart.Content = $contentXml
       }
}

I hope it will help.

Cheers

Hide the ‘Pages’ library in SharePoint breadcrumb

May 11th, 2011 No comments

SharePoint breadcrumb is a nice feature to have on the pages. But it doesn’t fit very easily in usual scenario. If you also want to get rid of ‘Pages’ library link in the breadcrumb of a publishing site then see the below instructions.

Normal breadcrumb

My Portal -> Pages -> Test Page1

Updated breadcrumb

My Portal -> Test Page1

Then change the breadcrump source provide to CurrentNavSiteMapProviderNoEncode.  You have to change this in SiteMapPath tag like this…..

<asp:SiteMapPath SiteMapProvider=”CurrentNavSiteMapProviderNoEncode” id=”ContentMap” SkipLinkText=”" NodeStyle-CssClass=“ms-sitemapdirectional runat=“server”/>

 Now when we use CurrentNavSiteMapProviderNoEncode, we have to make sure that ‘Show Pages’ is true for current navigation. Even if you don’t want to display pages on the left navigation you have to enable it. Then you can hide your pages one by one from the navigation settings.

Cheers

Unique Column/Field in SharePoint List

August 9th, 2010 6 comments

It is always a desire to have unique field in SharePoint list. Sometimes you have to replicate a database table and sometimes it could be a special requirement. Recently when I have been asked to have a unique field in a SharePoint list, I searched for it. Thanks to CodePlex. There is a solution called Unique Column Policy.

It is actually a feature. It creates a new information policy that allows you to specify a column in a list or library that should have unique values. Unfortunately on the website there is not enough information on how to use it. So I created this blog, I will show how it works.

First of all you need to download it. You can download it from this link. (Download). Then you need to install it on your SharePoint server. For this addsolution to solution store.

stsadm –o addsolution –filename UniqueColumnPolicy.wsp

Now deploy the solution. You can deploy it either from the stsadm command or you can deploy it using the SharePoint Central Administration site. This solution deploys globally. So you cannot just deploy it for a single site collection. Once your solution is deployed. Now you can create unique columns in SharePoint lists.

In order to, apply it on a column. Create a new column in a SharePoint list. Now open the list settings page and open the Information management Policy Settings link.

List Settings Page

In order to, apply it on a column. Create a new column in a SharePoint list. Now open the list settings page and open the Information management Policy Settings link. Select ‘Define a Policy’ and click ‘OK’.

Information Management Policy Settings

It will open edit policy page. Now select ‘Enable Unique Column Policy’.

Edit PolicySelect the field you want to use for unique values.

Select a field

Now when you try to add the same value you used before in unique column. It will give you an error like this.

Unique Column ErrorIt will show the same error when you try to update and item and give it same value you used before in any other list item. Good thing is this also works with datasheet view.

DataSheet View

Like in the above image, we tried to use the same value UC_999 in unique column field. When we moved to next column. It displayed an error icon in front of the affected row. This is the error to notify user that duplicated values are not allowed in this column. Click on the icon and you can see more details.

DataSheet View - Error Details

In simple words this feature is amazing, and it gives more power to SharePoint list.

I hope this will help implementing unique column/field in SharePoint list.

MOSS – Change Maximum File Upload Limit

June 17th, 2010 No comments

By default you can upload a maximum file of 50 MB in a SharePoint document library. It might be very rare when you want to increase this limit but sometime it happens. Recently it happened with me.
It’s not really difficult.
Open SharePoint Central Admin site
Click on Application Management
Click on Web Application General Settings

Now on this screen you can changes the maximum file upload size.

You may also need to change the timeout settings for your webpage to upload big files.
 

You may also need to change the timeout settings for your webpage to upload big files.

Have fun

Create Workflow Using SharePoint Designer 2007

June 13th, 2010 1 comment

It is part of the same series of workflows creation I started a few days ago. As promised this time here is the example to create a copy item workflow using SharePoint designer 2007 for SharePoint 2007. Obviously there is no much difference between the workflows creation process of SharePoint designer 2010 and SharePoint designer 2007.

This is an example for copy item workflow. Whenever you create or change an item in a list it will copy your item in the destination list.
Open the SharePoint designer and open your website. Select new from file menu and then Workflows to create a new workflow.

 

Give your workflow some name and select the list/library to initiate workflow. Also select when the workflow triggers. I selected on item created and item changed.

 

In this workflow we will put a condition. Actually I created a field in document library. This is a ‘Yes/No’ field. This workflow will check for the field value and triggers only if it is ‘Yes’.

 

Select the condition in workflow’s settings page and select the first option to compare list field for condition.

 

Select field name to MoveFlag from the drop down list.

Set the value to ‘Yes’ for condition. It defines that if MoveFlag value will be equal to Yes then this workflow will trigger.

Now it’s time to set the action statement. Your condition is done, now select Action. Select ‘Copy List Item’ from the drop down list.

 

Select the source list name in first instance and select destination list name in second instance. I selected the ‘Issued Documents’ library for source list. This statement will look like this.

 

All done, now just click finish it will process your workflow and associate it with the source list as well.

 

Now what else, start using the workflow. It’s ready and will work as required. In next post I will explore the programmatic way to create workflows. That would be more interesting I think.

Thanks

 Thanks