Archive

Posts Tagged ‘SharePoint 2010’

Managed Metadata Service – Enable Feature

August 16th, 2012 Comments off

You have setup every bit you can think about the Managed Metadata Service and when you try to create a new Managed Metadata column. You see this message.

“The required feature is not enabled for this column type”

In order to solve this problem, you need to activate a hidden feature. Please use below PowerShell command to activate the feature on your site collection.

Enable-SPFeature –identity “73EF14B1-13A9-416b-A9B5-ECECA2B0604C” -URL http://yoursite

It all should be good afterward.

Cheers

Enable Upload Multiple Documents – SharePoint 2010

August 16th, 2012 Comments off

It is yet another tip of the day.

If you haven’t installed Office components in the SharePoint server then you might see Upload Multiple Documents option as disabled in the SharePoint libraries. This option is part of the client integration component and this component is part of the office 2010 install.

Now one option obviously is to install the office components. But if you don’t want to install the office then installation of SharePoint Designer 2010 will do the job for you. As, this component is also available in SharePoint Designer 2010.

Cheers

Enable DataSheet View – SharePoint 2010

August 16th, 2012 Comments off

This is just a tip of the day.

If you find that DataSheet view is disabled in the SharePoint list and libraries. You can only install this component to make it work.

2007 Office System Driver: Data Connectivity Components

It will do the little magic.

Cheers

Permissions for Managed Metadata Service

August 15th, 2012 Comments off

Recently I build a new SharePoint VM. When I started looking at the Managed Metadata Service, I found that I couldn’t add new group. Or simply in term store Add New Group option was not available.
Then I realised that I haven’t setup the permissions for MMS. In order to set the permissions for MMS, open Manage Service Applications. Then select the Managed Metadata Service. Don’t click on the link just select it by clicking in front of the link. Now select Administrators from the ribbon. Add your user account there and select Full Access in permissions box.

Now click on the Managed Metadata Service link and it will open the Term Store Management Tool. Add your user to Term Store Administrators and you are all set to do all with Managed Metadata.

Have fun!

Microsoft and the Social Enterprise – Presentation

August 6th, 2012 Comments off

This is one of my presentation from 2011. I thought it might be helpful to others.

Cheers

Sandboxed Solutions – Presentation

August 6th, 2012 Comments off

This is one of my presentation from 2011. I thought it might be helpful to others.

Cheers

Content Type Hub SharePoint 2010 – Presentation

August 2nd, 2012 Comments off

This is one of my presentation from 2011. I thought it might be helpful to others.

Cheers

Configure Retention Policy through Code

September 4th, 2011 Comments off

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 Comments off

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 Comments off

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.