How To Disable SharePoint Designer on SharePoint 2010 Programmatically

Here's a little PowerShell script to disable users from using SharePoint Designer 2007 on your SharePoint 2010 sites. It is not really a complicated matter like it was during the SharePoint 2007; the only thing to note here are 3 main points:
  • you must have access to the namespace Microsoft.SharePoint.Client
  • you MUST run this script with at least Admin permissions for the Site Collection in question
  • The functionality to enable and disable this must have been set during the site collection creation. By default it is NOT. You can check that on the Site Collection properties.
Failing to attend these 2 conditions will throw you back an exception.

function Lock-SharePoint-Designer-Use([string]$url)
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
    $rootSite = new-object Microsoft.SharePoint.SPSite($url)
    if($rootSite.RootWeb.AllowDesignerForCurrentUser -eq "true")
        $rootSite.AllowDesigner = false
        write-output "site "$($rootSite.RootWeb.Title)) "locked for SharePoint designer"
        write-output "site "$($rootSite.RootWeb.Title)) "does not allow designer to be configured for this site collection"

Additionally you can also try other configurations to increase the lockdown surface for nasty actions that can be accomplished by some users, such as :

See you later,



How to increase SharePoint performance. Use of retail and debug modes.

...when was the last time you checked your machine.config for retail="true" ?

I've heard a few times that SharePoint is a beast, a heavy monster, or is too slow, or is too boring. Truth is not many people out there are following SharePoint best practices. Just to mention one: when deploying a SharePoint solution many people overlook a simple switch that can make a huge difference and and have serious implications when we are talking about performance: The debug switch.
Maybe because it is too simple find in the web.config, maybe because it is too easy to change using notepad... the truth is: a lot of extra plumbing work is done when an application in debug mode is released to your users.
Scenario: we have a SharePoint page that has a delegate control. that delegate control loads a custom ascx that's deployed as a feature. that control might popup in many places across the whole portal.
What happens when your web.config has debug=false ?
For starters, let's take a look at the size of the generated assemblies, the number of handles created in the system and the internals of the DLL compilation.
When your SharePoint DLLs are compiled and deployed with the debug mode switch turned to false, the first thing you will notice is the assembly files. Look their sizes. They are determined by the compilation switch, not by the web.config switch. For comparison purposes I will use assemblies compiled in release mode against assemblies compiled in debug mode.

When your SharePoint web.config application has the web config debug = false SharePoint, or more precisely the .net framework, will handle the assembly reference this way:
When the user makes the very first request to a page that contains that ascx, the framework will compile that ascx into a temporary DLL. That DLL will receive a random name and it will not contain the code-behind that might be present in the GAC. The framework will also create a shadow copy of that DLL and both copies will be placed in the ASP.NET temporary folder. That reference will be returned to that page and the page will be rendered to the user.
If you get to inspect the content of one of these files you will that that a kind of 'proxy' will be generated for them with all the references for the real control stored in the 12 hive. That's generated when the first call is made to the control.

contents of the file myapps.aspx.d7b311e5_CBMResult.compiled
<?xml version="1.0" encoding="utf-8"?>
<preserve resultType="7" virtualPath="/MySharepointApp.Personalisation.MyApps/12/TEMPLATE/LAYOUTS/MySharepointApp/MyApps.aspx"
          hash="fffffff6f2b2ee5f" filehash="fffffff6c7a1c8b7"
        <filedep name="/MySharepointApp.Personalisation.MyApps/_controltemplates/AudienceTrimmedControl.ascx" />
        <filedep name="/MySharepointApp.Personalisation.MyApps/_controltemplates/LinkSection.ascx" />
        <filedep name="/MySharepointApp.Personalisation.MyApps/_layouts/application.master" />
        <filedep name="/MySharepointApp.Personalisation.MyApps/12/TEMPLATE/LAYOUTS/MySharepointApp/MyApps.aspx" />
For all the subsequent requests from other pages using that same control, the same reference will be retrieved. It means the page will apply less pressure in the server and naturally the application will perform close to its best.
Now let's navigate the site opening more pages and see what's happening in the system. The number of handles keeps a steady balance.
Now let's observe what happens if we do the same process and leave the web.config debug=true and we deploy the DLLs compiled in debug mode.
First thing we will notice is an increase in the assembly file, because the symbols added to the assembly.
It is not much of a difference, just 1-5 KB here and there.
so we are led to believe it will not increase the footprint on the system, right? Yeah.. but no...but yeah; that's not the problem, the problem will reveal itself when we inspect the page lifecycle...That's what's going to happen in this scenario.  
For every single call to the page using the control, a brand new temporary DLL will be generated and that's my friend... is a problem. You can not afford to have a portal with, let's say, 500 pages and do not suffer from (the lack of) performance management  there with every single one of these assemblies loaded. See the overhead placed in the temp folder, see the overhead placed in the SharePoint portal handler...
Let's repeat the same process as case 1 and let's open another page that uses the same control. Look at the handlers in the system. They had a significantly increase. Now imagine that with hundreds of users.
That's going to be a lot of work for the garbage collector that should not be there if the person only took time to apply some basic best practices when deploying solutions. And the garbage collection is as we know a very expensive operation to be carried (probably) that often.

What should we do then?
Avoid debug=true in production environment. User Retail=true. Maybe you can't avoid people going there to the web.config and changing the settings to debug=true and false, but you can reduce the surface for problems. And one of the very first things you apply in production is the not so much talked about: retail mode.
      <deployment retail="true" />
The retail mode is a switch in the machine.config that automatically:
  1. ignores all the debug=true switches and force them to be false.
  2. disable the trace output in the pages
  3. disable the custom errors configuration
  4. disable the debug capabilities
In short: just flicking this switch you automatically reduces the surface for performance issues and also some hacking attacks by not exposing unnecessary information on the screen in case of an application crash. And because machine.config is hierarchically higher that web.config it will take precedence over any web.config from other applications deployed to your server.
Now go there and take a look how is your retail mode set and maybe with just a little flick you can change the performance of a whole portal and offer a better experience to the users.
See you later,



How to list all the sites for a sharepoint web application using powershell script ?

Solution 1:
Here's an quick and very useful script often requested by admin guys that I'd like to share and hopefully it will be useful to someone as well: list all the sites for a SharePoint Url and its owners.
Made in PowerShell
function List-Sites([string]$url)
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") > $null
    [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Administration") > $null
    $rootSite = new-object Microsoft.SharePoint.SPSite($url)
    $webApp = $rootSite.WebApplication
    if($webApp.Sites.Count -gt 0)
        write-output "site url`tlast date content modified`tsite owner`tsite name`tsite url`tsite template`tsite description"
        foreach ($site in $webApp.Sites)
            $rootweb = $site.RootWeb
            foreach($template in $allwebtemplates)
                if ($template.ID -eq $rootweb.WebTemplateId)
            $lastUpdatedDate = Get-Date "1/1/2000 1:00 AM"
            foreach($web1 in $site.AllWebs)
                foreach($list in $web1)
                    if ($lastUpdatedDate -lt $list.LastItemModifiedDate)
            $SiteAdmin = new-object Microsoft.SharePoint.Administration.SPSiteAdministration($rootweb.URL)
            write-output "$($site.Url)`t$($lastUpdatedDate)`t$($site.Owner.LoginName)`t$($rootWeb.PortalName) $($rootWeb.Title)`t$($site.PortalUrl)`t$($rootWeb.WebTemplate) ( $templatename )`t$($rootWeb.Description)"

There is also a reference for the object SPSiteAdministration just in case you want to output more information.
Execute this script in the Powershell command line in your server and the output will be something like this:

Solution 2:
Not really a good solution if you have several sites; but if you just want to quickly find out the templates of a specific site alternatively you can go to your root web site and add this to your query string: /_vti_bin/owssvr.dll?Cmd=GetProjSchema
this will display the ONET.XML for that site, and if you scroll down until the Configuration node you can get the template being used currently

The admin guys are happy, developers are happy... win-win :)
See you later,



How to Customize My Links Control in SharePoint

User adoption is  everything in a successful SharePoint implementation and one of the main things to attract users to use the site is by customizing the site according to their needs or a previous product. In a lot of cases this never gets 100% done and then one day when a power users is browsing the site he can see things like that: A reference to the Microsoft product inside their own organization.

My SharePoint Sites link being displayed in the client screen
The ideal situation is for a product to be vendor/technology agnostic. From the user's point of view, he doesn't care what is the framework or the company; he just want to have access to his tools.
So, how to customize that My Links control from SharePoint web sites?
Answer: We will create a SharePoint feature to place our own ASCX control in the page instead the default SharePoint OOTB control.
First let's inspect how is this control implemented. If you open the homepage using SharePoint Designer and search for that specific part of the code you will notice that control is a SharePoint DelegateControl.
A delegate control is one of the coolest aspects of the SharePoint ecosystem. This control has the ability to render any user custom ASP.NET controls inside SharePoint pages on the fly by just changing the ControlId.
If we come back to our case, what that line is doing is: at this exact position, render the control called 'GlobalSiteLink2'.
Now remember these functionality are available to the application by features. Let's go then and search for the key 'GlobalSiteLink2' in the TEMPLATE\FEATURES folder on the 12 hive.

You will discover that there is a feature called 'MySite' there which implements the actual control.
Open the file MySiteFeatureElements.xml and you will see this:
   1 <Elements xmlns="">
    2   <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
    3   <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/mylinks.ascx"/>
    4   <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
    5 </Elements>
there it is our control Id='GlobalSiteLink2' and its source is in a file called 'mylinks.ascx'.
Next step, we need to find out the mylinks.ascx control. For that you have to navigate to the user controls folder at the 12 hive ($\TEMPLATE\CONTROLTEMPLATES). There you will see all the user controls available to SharePoint.  Let's have a look at the source code of this control.

Code Snippet
  1. <%@ Control className="MyLinksUserControl" Language="C#" Inherits="Microsoft.SharePoint.Portal.WebControls.MyLinksUserControl&#44;Microsoft.SharePoint.Portal, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  2. <%@ Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls" Assembly="Microsoft.Office.Server, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  4. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <table><tr>
  6. <td class="ms-globallinks"><SPSWC:MyLinksMenuControl id="MyLinksMenu" runat="server" /></td>
  7. <td class="ms-globallinks"><asp:Literal id="hlMySiteSpacer" runat="server" /></td>
  8. </tr></table>

We now see that MyLinksMenu is an object of MyLinksMenuControl, and this class is defined inside Microsoft.SharePoint.Portal.WebControls.Dll

That's good news. We find a method called LoadMenuItems() that returns an array list of menu items.
Ok. At this point we have to question ourselves something very important: We should avoid as much as we can interfere during the natural course of SharePoint's behavior. Given that method call we assume that instead modifying it we should be able to configure that string somewhere in the configuration files and then LoadMenuItems() would just return the items with the new label. Would not be the easier and most logical way for Microsoft and everybody else to modify that value?
As much as this proposition might sound correct, unfortunately the answer is no. That string is hardcoded somewhere into the SharePoint source code as a resource file and embedded within the DLL. If you try to inspect that, here's what you get:
The funny thing is that many other areas and messages and labels across the whole SharePoint platform can be configured by updating the resource files, makes you wonder:  "why they did not used the same approach here?"
So, how to fix that?
Using the same delegate control to render your control instead of the out of the box one; and to avoid breaking the natural SharePoint flow of things we are going to create a control inheriting from the OOTB SharePoint MyLinksMenuControl.
We should start by creating a solution that looks like this with WSPBuilder. We will mimic the complete structure for MyLinks.ascx's feature and give it another name.
Compile the solution for the very first time and then extract the public key token. Go to the folder where the DLL is located and execute this command.
Copy and paste the public key token displayed in the screen in our next step, into the ascx source code.
Now will create a similar ascx control just like the original one, but instead of using the webcontrols part we will be using our own MyCustomLinksMenu.ascx
Code Snippet
  1. <%@ Control className="MyLinksUserControl" Language="C#" Inherits="Microsoft.SharePoint.Portal.WebControls.MyLinksUserControl&#44;Microsoft.SharePoint.Portal, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  2. <%@ Register Tagprefix="OSRVWC" Namespace="Microsoft.Office.Server.WebControls" Assembly="Microsoft.Office.Server, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  3. <%@ Register Tagprefix="SPSWC" Namespace="CustomizeMyLinks" Assembly="CustomizeMyLinks, Version=, Culture=neutral, PublicKeyToken=995e4d025d306cec" %>
  4. <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
  5. <table><tr>
  6. <td class="ms-globallinks"><SPSWC:MyCustomLinksMenu id="MyLinksMenu" runat="server" /></td>
  7. <td class="ms-globallinks"><asp:Literal id="hlMySiteSpacer" runat="server" /></td>
  8. </tr></table>

Let's go to and get ourselves a brand new Guid for the feature. Keep this Guid, we will use it in our next step to assign it to the feature Id.
This is how it will looks like our new feature.XML.
    1 <?xml version="1.0" encoding="utf-8"?>
    2 <Feature Id="{6fed26c0-57d3-4237-afd7-722c5c13a147}"
    3         Title="Customize MyLinks menu control"
    4         Description="Renames the mention to SharePoint from the MyLinks control, to make the website more vendor agnostic"
    5         Version=""
    6         Hidden="FALSE"
    7         Scope="Site"
    8         xmlns=""
    9         ImageUrl ="">
   10   <ElementManifests>
   11     <ElementManifest Location="elements.xml"/>
   12   </ElementManifests>
   13 </Feature>

And this is our new elements.XML which is a copy from MySiteFeatureElements.XML. Note the control GlobalSiteLink2 pointing to our brand new ascx control.
    1 <Elements xmlns="">
    2   <Control Id="GlobalSiteLink1" Sequence="100" ControlSrc="~/_controltemplates/mysitelink.ascx" />
    3   <Control Id="GlobalSiteLink2" Sequence="100" ControlSrc="~/_controltemplates/MyCustomLinksMenu/MyCustomLinksMenu.ascx"/>
    4   <Control Id="ProfileRedirection" Sequence="100" ControlSrc="~/_controltemplates/mysiteredirection.ascx"/>
    5 </Elements>

And here's the code for the custom control. The comments in the code are self-explanatory.
    1 using System.Collections;
    2 using Microsoft.SharePoint.Portal.WebControls;
    3 using Microsoft.SharePoint.WebControls;
    5 namespace CustomizeMyLinks
    6 {
    7     /// <summary>
    8     /// Customize the current MyLinks menu control
    9     /// and rename the link 'My SharePoint Sites' to 'Visit Your Sites'
   10     /// </summary>
   11     public class MyCustomLinksMenu : MyLinksMenuControl
   12     {
   13         /// <summary>
   14         /// Loads the menu items.
   15         /// </summary>
   16         /// <returns>a <see cref="ArrayList"/> with
   17         /// all the menu items from <see cref="MyLinksMenuControl.LoadMenuItems"/></returns>
   18         protected override ArrayList LoadMenuItems()
   19         {
   20             // make sure you will call the out of the box method that generates
   21             // the default items in SharePoint
   22             var currentMenuItems = base.LoadMenuItems();
   24             if ((currentMenuItems != null) && (currentMenuItems.Count>0))
   25             {
   26                 // now that you have the items, you can manipulate them the way you want
   27                 SubMenuTemplate customMenuTemplate;
   28                 using (customMenuTemplate = (SubMenuTemplate) (currentMenuItems[0]))
   29                 {
   30                     if (customMenuTemplate != null)
   31                     {
   32                         customMenuTemplate.Text = "Visit Your Sites"; // or any other text you want here
   33                         currentMenuItems.RemoveAt(0);
   34                         currentMenuItems.Add(customMenuTemplate);
   35                         // you can also try currentMenuItems.InsertAt(0,customMenuTemplate);
   36                     }
   37                 }
   38             }
   39             return currentMenuItems;
   40         }
   41     }
   42 }

Compile. Build the package with WSPBuilder and deploy the feature to the 12 hive, activate the feature in the web site and voilá! You will see the link customized.
See you later