Scoping a SharePoint Feature for a Specific Web Application

This is something that came up at a client’s site yesterday, which I thought should be a trivial problem to solve. As always, it ended up being a little more complex than I originally anticipated. So everyone knows that a SharePoint solution can either be globally scoped, meaning that all web applications in the farm can leverage it, or it can be scoped at a specific web application. But what about features contained within these solutions?

Assume you have a custom .WSP solution that contains 1 feature and which is scoped for your web application on port 81 (e.g. http://localhost:81). One would assume that by default, if the solution is only made available to the Web Application on port 81 (scoped at web app level) that it would be the same for the feature contained within it, meaning that this feature, assuming it it scoped at the site collection level, would only be accessible by site collections within the Web Application contained in the Web Application on port 81. Well, in fact it is not. A feature is always made available to all web applications in a farm, even if its associated solution is targeted at a unique web application.

For this article, I will be using new SharePoint 2010 Foundation Single Server Farm. My farm contains two web applications: one deployed on port 80 and a second one deployed on port 81. From the following picture we can clearly see that I have a custom solution named “MySP2010Solution.wsp” scoped at the web application level and which has been deployed against my web application on port 80.

Webappscopedsolution

This solution contains a single feature, which in turn contains a web part. The feature is scoped at the site collection level. Since my solution was deployed against my web application on port 80, it is expected to see my feature show up in every site collection Under that web application:

featureport80

What one may not expect however, is to also find this feature available to every site collection in my web application hosted on port 81. After all, the solution was never deployed to it in the first place. However, navigating to the site collection feature page of a site collection Inside the web application on port 81 does show my feature and allows me to activate it.

featureport81

The following schema summarizes what is really happening in my environment:

schema

How it Works in the Background

In order to better understand why SharePoint is behaving this way, we need to first understand what really happens in the background when we deploy a solution that contains a feature. When deploying a solution that contains a feature, SharePoint automatically creates a folder in <14 Hive>\TEMPLATES\FEATURES for your custom feature contained within your solution:
Featurelocaldisk
Because this feature is stored physically on disk, it is by default made available by all web applications. Upon activating the feature from the Web interface, SharePoint will create an entry in the Features table of the content database associated with the current Web Application.

SQLFeatureTable

Options

So if you are in the business of managing several web applications for different clients, how can you let one client deploy a web application scoped solution without having it appear on all of your other clients’ web application? Well there are really 3 options made available to you:

1 – Hide the feature by default and activate it via PowerShell

The first option is to make your feature hidden by default, and then to use PowerShell to activate it manually only on the site collections that require it. This is what I consider a nasty workaround. The beauty about SharePoint feature is that you wish to let Site Collection admins manage the features to be activated themselves. With this approach, first off the site collection admins need to know that the feature exists because remember, it will be hidden from them via the web interface, and second they will need to contact the IT admin team so that they can activate it via PowerShell everytime they need a hidden feature activated. This adds a burden on both the site collection administators ad the IT admins responsible for SharePoint.

If you wish to make a feature hidden, simply navigate to its associated folder under <14 Hive>\TEMPLATE\FEATURES\, edit the Feature.xml by adding the property hidden=”true” to the Feature node. Save the file, and do an IISReset on the server. Remember to perform this on every server in the farm.
HideaFeatureSP

2 – Context Feature Logo

The second option is probably a even worst idea than the first one, but I list it here anyway in case it fits someone’s business scenario. Whenever you create a custom feature, you can specify a custom “logo” (icon) for it. By default, if no logo has been specified for a feature, SharePoint uses the default half spinwheel icon (GenericFeature.gif).
GenericFeatureicon

The idea here is to specify a custom icon for your feature, but that would be hosted at the root of each web application. Still unclear on what I mean right? Imagine we had two icons, a Green light icon, and a red “cancel” circle icon. We would ensure that the feature displays the cancel icon on all site collections contained within a Web Application for which we did not intent to deploy the feature onto, and the green icon on the ones where the feature was intended for the users to consume.

Let’s show you a graphical example of what I mean. By simply modifying the Feature.xml file for my feature and adding the following property to the Feature node

FeatureFakeIcon

I was able to tell SharePoint to go and check the root of the current Web Application for a Library called “Icons”, which contains a file named MySPWebPart.png file and to use that image as my feature icon. In my scenario, if a user is to navigate to the Site Collection feature page on the Web Application hosted on port 80 (where the feature was intended for) they would be presented with the green light icon, meaning that this feature is meant for them to consume:

GoodFeatureCanConsume

However, if a user was to navigate to the site collection feature page on a site collection hosted within the Web Application on port 81 (whee the feature was not intended to be deployed). they would be presented with the cancel icon, meaning that this feature is not intended for them to consume:

BadFeatureDoNotConsume

This solution can cause a LOT of maintenance nightmare for your IT Admin team, and relies 100% on the user’s discipline to not activate features that are not meant for them to consume. It salso requires you to create individual icons for every feature you create and to have them stored in the icons Library of each root web of your Web Applications.

3 – Make your Feature Dépendent of a Web Application Scoped One

This solution is by far the best option you have. You could even combine it with Option #2 to get even more out of it for your clients. The idea here is to create an empty Feature, have it scoped at the Web Application level, and make all other features dépendent on it. For example, if we wish to make sure the features contained within our custom MySP2010Solution.wsp can only be activated on site collections contained within the Web Application hosted on port 80, we can make our custom feature (containing our web part) dependent on a web application scoped feature that would only be activated on that web application. Users who would navigate to the site collection feature page on the Web Application hosted on port 81 would still see the feature, but as soon as they would try to activate it, SharePoint would present them with a message saying that a dependent feature was not activated.

Let’s have a closer look at that solution. Within Visual Studio, add a new feature to your project (let’s call it Controller for Web App Port 80) and scope it at the Web Application level.
ControllerFeature

Then open the Feature Wizard for the feature that contains our Web Part. At the bottom of the main screen, there’s a section called Feature activation dependencies. Expand that section and click on the Add… button.
Featureependency

You will be brought to a dialog box that let’s you pick any of the other features included in the current solution, and make your feature dependent on them. From the list, select the “Controller for Web App Port 80” Feature we just created and click on the Add button
pickdependency

You can now go ahead and deploy your solution. By default the feature will be made available to all web applications in your farm, and can be activated from anywhere. What we need to do now, is go in central administration and de-activate the Controller for Web App Port 80 feature on the Web Application hosted on port 81. To do this, in central administration, navigate to Application Management > Manage Web Applications. From the list of web application, pick the Web Application that is hosted on port 81, and in the ribbon, click on the Manage Features button.
ManageWebAppFeatureCA
Clicking this button will launch a dialog window listing all features that have been activated against this Web Application. Make sure the Controller for Web App Port 80 is deactivated.

ControllerDeactivated

By deactivating this feature you prevent anyone from being allowed to enable dependent features on the Web Application hosted on port 81. Even if the feature is still listed in the site collection feature, anyone trying to activate this feature on that web application will get a message from SharePoint:

Preventactivationmessage

While this may not be a pretty option still, it at least prevents the feature from being activated within a Web Application it was not intended for.

Bridging the Gap Between IT Pros & Devs using PowerShell

The title of this article also happens to be the title of my PowerShell book. For a long tiem I’ve been wanting to go and write a non-technical article explaining how I envision the future of traditional IT shops with the rapid growth of PowerShell in the industry. When I first started working with SharePoint 2003 back in 2006, my role was to develop several webparts and application pages for my company. The environment I was maintaining had over 1,500 site collections with about 150 sites each. Whenever I created a new webpart, I had to go back and add it retro-actively to all sites (150 * 1,500 = 225,000 sites). Off course there was not way in hell I was going to do this manually. Instead, I started creating new console applications from within Visual Studio (VS 2005 at the time), and had to my application loop through all site collections, through all sites, and add the webpart to the main page of each one using the SharePoint Object Model and some C# code. Then my application was packaged as an .exe (a.k.a. total black box), and this executable file was sent off to the servers’ administrators for them to execute directly on the SharePoint servers (starting with the dev environment off course). I can just imagine being in their shoes, where some crazy developer just gave me a piece of executable, that I need to trust does20150415-01.png what the developers says it does, and then simply have to execute it on the server and wait for hours for it to complete. I used to be known as the “Dev cow-boy” back then due to my total lack of risk adversion 🙂 Depending on the timeframes I had, I would even threat the administrators with some verbose logging of what was really happening in the background…..if I had the time. Otherwise, they would be starting at a good old black MS-DOS style dialog for quite a while.

That is how I use to do it back in the days. The dev guys were doing the work, and then the admins had to trust them entirely, and only be invovled at the very end of the process, whenever the code was all finalized. They had no say really in the code’s logic, and had no exposure to the SharePoint object model. This very often initiated very interesting discussions between the dev teams and the administrators. “You need to activate the feature at the SPSite level!”……”Say what???”. On one end you had developers spending their times in C# and the SharePoint object model, and on the other end, you had the administrators trying to do everything using batch files and STSAdm.exlifelong-learning-skills-gap.jpge. Looking back at it, I think the worst part was that developers used to improvised them as being adminsitrators. I remember my team creating such a .exe console app to automate the creation of Shared Service Providers (SSPs), the ancestors of the SharePoint 2010 Service Application architecture. This is some scary stuff, since the devs at total control over components that could directly have a huge negative impact on the overall stability of the environment (god knows that th SSPs were shaky at best). Back then, the gap between IT Pros and the developers was incredibly hard to bridge.

Then towards the end of life of SharePoint 2007 (beginning of year 2009), a new technology emerged at Microsoft: PowerShell. This technology opened up a lot of possibilities for both the developers and the IT Pros. First off, it was for most scenario, faster to accomplish a task than the STSAdm. Secondly, it now allowed developers, who were willing to learn the language, to provide their servers admins with a clear text .ps1 file that they could open and read instead of the scealed box that was the console applications my team used to write. Even if the IT Pros didn’t want to learn the object model and understand exactly what each line of code was doing, it was at least giving them the false feeling that it was not only a Dev thing anomore, and that they had some little more control as to what was being execued on their servers. One problem remained however, in order for one to write an efficient script, they had to learn and understand the SharePoint Object model. Back then, with SharePoint 2007, you didn’t have any PowerShell cmdlets to help you out. So for example, if you wimage002.pngished to acquired the number of items contained in a specific SharePoint list, say “Fruits”, your code would have looked like the following:

[Void][System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.SharePoint”)
$site = New-Object Microsoft.SharePoint.SPSite(“http://portal”)
$web = $site.RootWeb
$list = $web.Lists[“Fruits”]
$count = $list.Items.Count

Therefore, even if there was some light at the end of the tunnel, there was still a huge gap in that in the eyes of IT Pros, the lines of code above are dev specific and most of them had no interest in learning how to become a programmer.

Then at the end of year 2009, Microsoft revealed what was to become SharePoint 2010, and everything changed. Microsoft introduced over 400 SharePoint specific PowerShell cmdlets. These “shortcut” methods made the code required to accomplish a set of very powerful actions against a SharePoint environment extremely simple, and most of all, human readable to both IT Pros and Devs. I think that this is where the true power of PowerShell resides. Both developers and IT Pros were now given the tools to write their own scripts. Off course IT Pros still had to learn a bit about the Object Model if they wished to interact with what I consider to be lower level objects (lists, items, views, pages, etc), and developers still had to understand some SharePoint architecture concepts if they wished to interact with higher level objects (Shared services applications, Web Applications, etc.), but all in all, the gap between devs and admins was being bridged! Based on my example above, with the venue of SharePoint specific PowerShell cmdlets, one could now achieve the same result with the following lines of code:

$web = Get-SPWeb http://localhost

$list = $web.Lists[“Fruits”]

$count = $list.Items.Count

3 lines instead of 6, and the code if much more readable.  PowerShell is just that great. It completely changed the story for SharePoint as far as I am concerned. You guys just stay tuned for what is coming up with SharePoint 2016 🙂 !

Creating Custom PowerShell Cmdlets for SharePoint

Something that a lot of people don’t realize with PowerShell for SharePoint is that it only provides cmdlets down to the list level. Meaning that you do not have any Powershell cmdlets available out-of-the-box to help you interact with Lists and below (e.g. Items, Fields, etc). In order to interact with these, you need to understand the SharePoint Object Model and this very often requires some high level development skills, which unfortunately is not something a lot of IT Pros have. For example, you can use the following cmdlet to get a reference to the root SharePoint web on http://localhost:

​$web = Get-SPWeb http://localhost
But if you wish to get a reference to the library “Documents” that exist under that web, you’ll need to call the List property on the object and reference its collection to get the appropriate reference back (see code below):
​$list = $web.Lists[“Documents”]
​While this may prove to be obvious for some, it is not a syntaxt most administrators will be used to, as it forces you to switch your mindset from a typical scripting logic to an object oriented one. Wouldn’t it be cool if there was a Get-SPList cmdlet available? Well friends, there is always the option to build it our selves, and this is exactly what this blog post will be covering. Off course my goal here is not to steal the thunder from fellow @GLapointe​ who’s been offering a list of such custom cmdlets (including his version of Get-SPList). My goal is to teach you all how to do it yourselves.

​​What do I need?

​A development machine that has both Visual Studio and SharePoint (any version) installed on. Yes, that’s right, there will be Visual Studio development involved. Basically, what we will do is created a new assembly (.dll) file that will be imported into our Powershell session and that will exposed methods as cmdlets (methods such as Get-SPList).

​​​Code

​We will start by creating a new C# Class Library project in Visual Studio. For the sake of this example, I’ve used Visual Studio 2013 with update 2, but really, any version supporting .NET 3.5 will do. The first thing you will need to do with your Visual Studio project is add references to the PowerShell core assemblies. These are System.Management and System.Management.Automation. The first one should be part of the default Visual Studio list of available assemblies in the GAC, while the second one will be located under C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0. ​We also need to make sure we add a reference to the Microsoft.SharePoint assembly because our PowerShell cmdlet will ultimately require us to interact with SharePoint (see Figure 1).
SolExplorerSPPS.png
Figure 1 – Solution Explorer showing referenced Assemblies and default class
Next, we will need to make our main class inherit from the Cmdlet class. This is what will allow Powershell to recognize that the methods and logic included in our class is to be exposed as a cmdlet. For my example, I named my main class GetSPList to make it clear that the code it contain was to expose the Get-SPList cmdlet. The next thing you’ll need to do in you code, is to declare your class as a cmdlet by specifying the verb to use, and the noun. In our case, our verb is “Get” and our noun “SPList, meaning that our cmdlet will be accessed using the Get-SPList method (see blue line below).
​After declaring our class as a cmdlet, we need to specify what parameters our method will accept. This is done by declaring class variables as being cmdlet parameters (see green lines). For each paramter, we will need to mention what their default input order should be, and mention if they are mandatory or not.
​Last but none the least, we need to override the ProcessRecord method (line in orange), which is the method that truly performs an action based on the parameters that were passed. In our case, We will use the URL received to create a new SPWeb object, we will get a reference to a list it contains using either its name (because we’ve specified string as the variable type, we should use GUID if we want to access the list based o a GUID), and will return the list instance.
​​​​using System;

using System.Management;
using System.Management.Automation;
using Microsoft.SharePoint;
 
namespace SPPS
{
    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Get, “SPList”)]
    public class GetSPList:Cmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true)]
        public string Web;
        [System.Management.Automation.Parameter(Position = 1, Mandatory = true)]
        public string List;
        protected override void ProcessRecord()
        {
            using(SPSite site = new SPSite(this.Web))
            {
                using(SPWeb web = site.OpenWeb())
                {
                    SPList list = web.Lists[this.List];
                    this.WriteObject(list, false);
                }
            }
        }
    }
}​
​​​​​All that is left now is to compile​ our code into a reusable assembly (.dll file). In my case I’ve copied the resulting SPPS.dll file into the C:\Script\ repository on my development machine.

Make PowerShell Use Our Custom Cmdlet

To tell PowerShell to load the logic contained in our custom assembly, we will need to use the Import-Module  and reference the custom .dll. In my case, I will be calling the following line of Powershell to load my assembly in the session:
Import-Module c:\Script\SPPS.dll
Once this is done, I can verify that everything is working as expected by calling the Get-SPList cmdlet that is contained within that assembly. Figure 2 below shows a PowerShell session in which I have loaded my custom assembly and used my custom PowerShell cmdlet to get a reference to the library “Documents” located at the root of the http://localhost site collection.
SPPSGetListInAction.png
Figure 2 – Using a custom PowerShell cmdlet to get a reference to a SharePoint list.
What we’ve just learned in this article is extremely powerfull and can be extended to bridge many gaps that currently exist in the SharePoint/PowerShell world. Before you dig too deep in this, however, I recommend taking a look at what Gary Lapointe has already made available to us all on his site (visit Gary’s site). Enjoy!

My First Thoughts on the NAPA Cloud Apps IDE

Last July 17th, Microsoft unveiled the preview version of the upcoming Office 2013 suite, including the server bits. One of the major changes, in my opinion, is the introduction of these new “Office Apps”. This concept opens the door to infinite possibilities for developers since they can now develop their own generic “pluggable” components and sell them directly on the Office App Store. Office Apps can target either the client applications like Word or Excel, or can target the Web like it is the case for the SharePoint Apps. These apps require developers to learn javascript and jQuery since they are required to run client side. Off course you can always develop a lightweight front-end component that would require minimal JavaScript code, and place the major part of the logic on the server side, but for real world scenarios, this would require you to register for a Windows Azure account, or to have your own on premises server.

 

With the Office 2013 preview announcement, Microsoft also made available an “obscure” online IDE component codenamed NAPA. This tool allows developers to create, deploy and test Office Apps from their browsers. In order to use this online IDE, you are required to register for an Office 365 vNext account. To find your way to its interface, you either need to create a new SharePoint site based on the Developer’s site template, and then add the NAPA apps to it, or you can simply navigate to https://www.napacloudapp.com/ . Please note that the later link requires you to be signed into your Office 365 vNext account first.

 

Now, I am one of the few lucky people to be using Visual Studio 2012 RTM. The release includes a downloadable version of the VS 2012 SharePoint 2013 developers tools that allows you to create new applications directly from within the Visual Studio IDE, which let’s face it, just feels more…natural.

 

Over the next couple of weeks I’ll try to write several articles on Office Apps development for SharePoint. I’ve taken the decision to mainly focus my new development on these types of Apps, and believe me, the future for these is extremely bright.