Friday, March 27, 2009

Running out of CALs?

Can we restrict features programmatically? That is what this article is about.

Consider the options

Control adapters
Well, you could for instance create a control adapter which disables the Activate button of the MOSS Enterprise feature. How does it do that? The control adapter alters the way another control is rendering. My dear friend Robin Meuré from zevenseas has a nice blog post about that. But it might be that you are not allowed to go down that path. Or the problem might be that you want to block the Enterprise features but they already got stapled and activated on almost every template. So what other options do we have?

Hiding Site collection features (or something else) from Site Settings menu
To start with you could hide the Site Collection features from the Site Settings menu to prevent Site Collection Administrators to activate features at site collection level. Useful? Maybe. I certainly don’t want to discard that idea entirely. It might be very useful in tightly controlled environments. So here is the code you can put in the elements.xml of your custom feature. See the HideActionId? That does the trick.


<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<
HideCustomAction
GroupId="SiteCollectionAdmin"
Id="HideManageSiteCollectionFeatures"
HideActionId="ManageSiteCollectionFeatures"
Location="Microsoft.SharePoint.SiteSettings">
</
HideCustomAction>
</
Elements>

Deactivating Enterprise features
You could create a feature, staple that to the site templates you would like and next deactivate enterprise features upon feature activation. I will not go into the first part. Deactivation is easy enough. Loop though the features at web and site level and check either for a specific feature definition ID or a feature definition display name. I find the latter nicer to read. Example:


foreach (SPFeature _feature in _site.Features)
{
if (_feature.Definition.DisplayName.ToLower() == "premiumsite")
{
_site.Features.Remove(_feature.DefinitionId,true);
}




Let us clean up the web part gallery
You know, when you deactivate a feature, the web part gallery still shows all of the enterprise web parts. Not very nice. So let us clean up things after that.

The trick is that we run a query against the web part gallery list that returns all web parts that belong to a specific group that were introduced by the Enterprise features. Those groups are Search, Outlook Web Access, Business Data and so on. Be aware that if you added your own web parts to those same groups, they will get deleted as well. Remember that!


Your query might look like this:


SPQuery _query = new SPQuery();

_query.Query = "<Where><Or><Or><Or><Or><Or><Eq><FieldRef Name='Group' /><Value Type='Choice'>Search</Value></Eq><Eq><FieldRef Name='Group' /><Value Type='Choice'>Filters</Value></Eq></Or><Eq><FieldRef Name='Group' /><Value Type='Choice'>Business Data</Value></Eq></Or><Eq><FieldRef Name='Group' /><Value Type='Choice'>Site Directory</Value></Eq></Or><Eq><FieldRef Name='Group' /><Value Type='Choice'>Dashboard</Value></Eq></Or><Eq><FieldRef Name='Group' /><Value Type='Choice'>Outlook Web Access</Value></Eq></Or></Where>";
SPListItemCollection _items = _list.GetItems(_query);
foreach (SPListItem _item in _items)
{
SPListItem _itemToDelete = _list.GetItemById(_item.ID);
_itemToDelete.Delete();
}
_list.Update();


Or use any other statement to delete items like processing them using a batch command at the root web or calling updateListItems through web service, whatever you like.


Don’t bug me about inefficient code. ;-)


As to the above, maybe this helps you build whatever you need to hide, clean or disable things. And maybe there are other more efficient ways of doing it. If so, please add them as comments to this post. I would appreciate it.



Technorati Tags: