Wednesday, June 27, 2012

Create a Visual Web Part that displays the entire SharePoint site structure of a SharePoint web application

In the following code sample, I've created a Visual Web Part that will display the entire site structure contained under the parent SharePoint Web Application.  This web part will display all sites despite the fact that the given user may not have access to all of the sites beneath the structure.  Naturally, unauthorized users won't be able to access the site when he/she clicks on the link, but they will at least be aware of its existence and can contact the SharePoint Admin in order to request access.  For this web part, I've chosen to use a Tree View control for displaying the structure, but feel free to get creative if you like.  By the way, I've also added a method, SetCurrentNodeFont, here that can be used for highlighting the SharePoint site under which the web part is installed.  Last but not least, I've removed my error handling code in order to simplify things a bit so be sure to include or suffer the consequences...  


Here is the code:

ASCX File

<asp:TreeView ID="treeViewSiteNav" runat="server">
</asp:TreeView>


ASCX.CS File

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Administration;

protected void Page_Load(object sender, EventArgs e)
{
    treeViewSiteNav.Nodes.Clear();
    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
        // Display the entire navigation structure of the web application
        SPSiteCollection sites = SPContext.Current.Site.WebApplication.Sites;
        foreach (SPSite currentSite in sites)
        {
            MapCurrentSiteCollection(currentSite.ID, currentSite.RootWeb.ID);
            currentSite.Dispose();
        }
    });
}


private void MapCurrentSiteCollection(Guid siteId, Guid webId)
{
    // Creating a new instance of the site because the currentSite is associated with the context of the
    // user whereas this new instance will run with elevated privileges
    using (SPSite site = new SPSite(siteId))
    {
        site.CatchAccessDeniedException = false;
        using (SPWeb currentWeb = site.OpenWeb(webId))
        {
            TreeNode siteNode = new TreeNode(currentWeb.Title, null, null, currentWeb.Url, "_self");
            SetCurrentNodeFont(ref siteNode, SPContext.Current.Web.ID, currentWeb.ID);
            treeViewSiteNav.Nodes.Add(siteNode);
            foreach (SPWeb web in currentWeb.Webs)
            {
                AddWebNodes(web, siteNode);
                web.Dispose();
            }
        }
    }
}

private void SetCurrentNodeFont(ref TreeNode node, Guid currentWebId, Guid evaluatedWebId)
{
    if (currentWebId == evaluatedWebId)
    {
        node.Text = Server.HtmlDecode(string.Format("<b>{0}</b>", node.Text));
    }
}

Friday, June 22, 2012

Remove special characters from a string using Regular Expression

If you're looking for an efficient way to remove special characters from a string, here is some sample code that utilizes a Regular Expression to do so:

using System.Text.RegularExpressions;
...
string inputString = "Sherman's Test #123";
string cleanOutputString = Regex.Replace(inputString,  @"[^A-Za-z0-9-_]", "");

This code sample will remove all characters except for alpha-numeric characters and "_".  If you would like to keep the empty characters/blank spaces, use this line instead:
string cleanOutputString = Regex.Replace(inputString,  @"[^A-Za-z0-9-_ ]", "");

Wednesday, June 20, 2012

Automatically activate a web or site scoped feature during site creation

I know of two good techniques for automatically activating a web or site scoped feature when a new SharePoint site is created and they are (1) if you're using a custom site definition, to insert a new <Feature> node within either the <SiteFeatures> or <WebFeatures> node of the ONET.xml file and (2) utilize a technique called Feature Stapling to attach your feature to a given site definition.

In both instances, you will need to know the ID, Title, and Scope of you feature.  These can be found by opening your feature's Feature.xml file and locating the appropriate attributes of the <Feature> node.  Here is a simplified example of what you might find in a sample Feature.xml file:

<?xml version="1.0" encoding="utf-8"?>
<Feature xmlns="..." Title="My Feature" Description="..." Id="b68c860b-b368-4e5f-ae06-dcfbfbd9c8da" ReceiverAssembly="..." Scope="Web"></Feature>


ONET.XML Update
This technique should only be used if your site is based on a custom site definition that you or your team created (i.e. that's the case if you have a custom ONET.xml file in your solution).  NOTE: You change will likely be overwritten with a service pack installation. With that said, the basic premise of this technique is to insert a new <Feature> node within either the <SiteFeatures> or <WebFeatures> node of the ONET.xml file which can be accomplished as follows:

  1. Open your ONET.xml file using Visual Studio or Notepad
  2. Locate the <SiteFeatures> or <WebFeatures> node depending on the scope of the feature
  3. Create a new <Feature> node and add the appropriate ID and Name attributes
  4. Save the changes
In this example, I will use the details from my sample feature:

<Project>
   <Configurations>
      <Configuration>
         <SiteFeatures />
         <WebFeatures>
            <Feature ID="b68c860b-b368-4e5f-ae06-dcfbfbd9c8da" Name="My Feature" />
         </WebFeatures>
      </Configuration>
   </Configurations>
</Project>

Feature Stapling
This technique is the only approach that I know of for automatically activating a feature on a standard SharePoint site template.  In this case, you will be creating a new Farm level feature that, when activated, will "staple" your feature to all sites that reference the specified template.  Here is an example of the "stapling" feature code that will be contained in a new Feature.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<Feature Id="7ac7f1e9-1c6a-4ff0-a2bc-0d81e2360b70"
    Title="Feature Staple Sample"
    Description="Staple the associated feature(s) to the specified site definition(s)"
    Version="1.0.0.0"
    Hidden="FALSE"
    Scope="Farm"
    xmlns="http://schemas.microsoft.com/sharepoint/">
   <ElementManifests>
      <ElementManifest Location="staple.xml" />
   </ElementManifests>
</Feature>

and here is some sample code that will be contained in the references staple.xml file that will automatically launch the specified feature on the standard SharePoint Team Site template:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
   <FeatureSiteTemplateAssociation Id="b68c860b-b368-4e5f-ae06-dcfbfbd9c8da" TemplateName="STS#0" />
</Elements>

Monday, June 18, 2012

Javascript code that can verify if special characters are used in a textbox

In the event that you would like to use client-side code to (1) inform a user that he/she has entered invalid characters in a textbox control, (2) highlight that control, and (3) place the focus on it, the following Javascript code can be added to a validation function to carry out all of three of those actions:

function ValidateRequest() { ... if (form.userinput_textbox.value != 0)
{ var userInputField = form.userinput_textbox.value; var invalidChars = "/!@#$%^&*(){}[]<>\\"; for (var i = 0; i < userInputField.length; i++) { if (invalidChars.indexOf(userInputField.charAt(i)) != -1) { window.scrollTo(0, 0); alert ("Please don't use any special characters or punctuation within the given textbox control."); form.userinput_textbox.backgroundColor = "C6ECFF"; form.userinput_textbox.focus(); return false; } } } ... }

Friday, June 15, 2012

Feature that can be used to control the list of available web templates

If you would like to control the list of possible web templates that are available on a SharePoint site to users who are authorized to add sites, I'd like to present some code that you can add to a feature that will allow you to adjust the list of possible options.  In case you aren't certain what I mean by these available web templates, you can view this list by navigating to your SharePoint site and clicking on Site Actions -> New Site and you will be presented with a list of possible templates to choose from.

In the code sample below, activating the feature will remove all possible web templates with the exception of the standard Document Workspace template from the display list.  Deactivating the feature will allow the list of options to return to its normal mode of displaying all web templates:

public override void FeatureActivated(SPFeatureReceiverProperties properties) { try { SPWeb web = properties.Feature.Parent as SPWeb; // Hide all available web templates with the exception of the Document Center web template SPWebTemplateCollection currentTemplates = web.GetAvailableWebTemplates(1033); Collection newTemplates = new Collection(); foreach (SPWebTemplate currentTemplate in currentTemplates) { if (currentTemplate.Title.Trim() == "Document Workspace") { newTemplates.Add(currentTemplate); } } web.SetAvailableWebTemplates(newTemplates, 1033); web.Update(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { try { SPWeb web = properties.Feature.Parent as SPWeb; // Show all available web templates web.AllowAllWebTemplates(); web.Update(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } }

Thursday, June 14, 2012

Restart a computer via Remote Desktop

If you're connected to a computer running Windows 7 or Windows Server 2008 via Remote Desktop and would like to restart it, here are two methods that you can use to do so:

  1. Click on the Remote Desktop session and hit Alt+F4
  2. Click on the Remote Desktop, open a DOS command prompt, type "shutdown -r", and hit Enter

Wednesday, June 13, 2012

Programmatically obtain a list of all properties associated with a user's profile in Active Directory

The following simplified code sample can be used for obtaining a list of all possible properties that are associated with a user's profile in Active Directory.  This code would be useful if you're trying to figure out which AD properties you may need to access to get the information you require:


using System.DirectoryServices;

...

try
{
   using (DirectoryEntry dirEntry = new DirectoryEntry("LDAP://yourOUPath))
   {
      using (DirectorySearcher dirSearch = new DirectorySearcher(dirEntry))
      {
         dirSearch.Filter = "(&(objectClass=user)(sAMaccountname=yourADLoginName))";
         SearchResult result = dirSearch.FindOne();
         if (result != null)
         {
            foreach (string propertyName in result.Properties.PropertyNames)
            {
               Console.WriteLine(propertyName);
            }
         }
      }
   }
}
catch (Exception ex)
{
   Console.WriteLine(ex.Message);
}


Likely culprits for issues with this code could be attributed to the following items:
  1. There could be issues with the structure of the LDAP path
  2. You may need to specify a DirectoryEntry.Username and DirectoryEntry.Password
  3. You may need to define a DirectoryEntry.AuthenticationType