Debugging Feature EventReceivers… the easy way

One of the great improvements of SharePoint 2010 is the ease of debugging your SharePoint projects. However, this does not hold for Feature Event Receivers, at least so it’d seem.

There is, however a very fast and easy way to start debugging your Feature EventReceiver’s overridden methods, like FeatureActivated() and FeaureDeactivating(): Simply add the following line of code at the point you want to start debugging:

System.Diagnostics.Debugger.Launch();

Now simply deploy your solution to your local SharePoint environment. This will start the debugger of your liking.

 

How to get the Managed Path for a Site Collection

There’s no easy way of retrieving the Managed Path for a Site Collection (SPSite) through the SharePoint 2010 object model.

Therefore, I wrote this method, to retrieve it for you. It should work with both wildcard inclusion and explicit inclusion Managed Paths, including nested managed paths (i.e. /sites/, /sites/projects/, /sites/depts/, etc.).

private Microsoft.SharePoint.Administration.SPPrefix GetManagedPath(SPSite site)
{
    if (site == null)
        throw new ArgumentNullException("site");
    string relativeUrl = site.ServerRelativeUrl;
    if (relativeUrl.Length == 0)
        throw new Exception("Invalid ServerRelativeUrl for this SPSite.");

    foreach (Microsoft.SharePoint.Administration.SPPrefix prefix in site.WebApplication.Prefixes)
    {
        switch (prefix.PrefixType)
        {
            case Microsoft.SharePoint.Administration.SPPrefixType.ExplicitInclusion:
                if (relativeUrl == "/" + prefix.Name || relativeURL == prefix.Name)
                    return prefix;
                break;
            case Microsoft.SharePoint.Administration.SPPrefixType.WildcardInclusion:
                // WildCard Inclusion prefixes can be nested (i.e. /sites/ , /sites/projects/, /sites/depts/).
                // Thus, we remove the site collection's name and compare against the whole string, in stead of using .StartsWith()
                if (relativeUrl.Substring(0, relativeUrl.LastIndexOf("/")) == "/" + prefix.Name)
                    return prefix;
                break;
        }
    }
    // A prefix should've been returned by now.
    throw new Exception("No SPPrefix (Managed Path) found for this SPSite");
}

The method returns an SPPrefix class, which contains the Name and PrefixType properties of the Managed Path. If the Site Collection is located at the root of the Web Application, the SPPrefix.Name property will be empty and of the type Explicit Inclusion.

New tool: SharePoint 2010 Theme Generator

I’ve just released version 1.0 of my SharePoint 2010 Theme Generator. You can find it on my site, under the new tools section.

This is a Silverlight application that generates a high quality color scheme from any base color, which you can use as a SharePoint theme.

It currently only has basic styling and no function for generating the .thmx files yet.

Go check it out and please give me feedback.

*Update* I just saw Microsoft’s Theme Builder doesn’t support Hex color values… So I’ve added RGB output to the generator as well.

Updating the User Information List in SharePoint 2010 from AD

In some cases, there is no need for User Profiles and My Sites. However, when you’re using Active Directory for authentication, you might notice that changes made to the AD Domain users are not effective for SharePoint users, such as a different or new email address. When you click “My Settings” from the user menu, you’ll still see the old values for name, email address, etc.

A simple way of solving this is using the Set-SPUser cmdlet in PowerShell, using the -SyncFromAD parameter. However, when you have multiple site collections with multiple users, you’ll need to do this for each user, in each site collection’s top level site.

The following PowerShell script will save you the trouble of going through this manually, it fetches all site collections with their RootWebs and syncs all available SPUser objects with AD.

Make sure you run it under a user that has access to each site collection, preferably as a site collection administrator.

$sites = Get-SPSite -Limit All
foreach($site in $sites) {
    $web = $site.RootWeb
    if($web -ne $null) {
        Write-Host "Processing: $site"
        Get-SPUser -Limit All -web $web | foreach {
            if ($site.WebApplication.UseClaimsAuthentication) {
                $claim = New-SPClaimsPrincipal $_.LoginName -IdentityType WindowsSamAccountName
                $user  = $web | Get-SPUser -Identity $claim -ErrorAction SilentlyContinue
            }
            else
            {
                $user = $web | Get-SPUser -Identity $_.LoginName -ErrorAction SilentlyContinue
            }
            if ($user -ne $null)
            {
                Set-SPUser -Identity $user -web $web -SyncFromAD -ErrorAction SilentlyContinue
            }
        }
    }
    $web.Dispose()
    $site.Dispose()
}

 

“Edit in SharePoint Designer” starts SPD 2007 instead of 2010

If you’ve installed both SharePoint Designer 2010 and SharePoint Designer 2007, you might run into this problem:

You’re on a SharePoint 2010 page and want to edit it in SharePoint Designer 2010. You switch to the Page menu on the ribbon, expand the Edit Page button and click the Edit in SharePoint Designer menu item.

You’d expect SharePoint Designer 2010 to start up and open the current page for you. Instead, SharePoint Designer 2007 starts up. Which is no good to you, and quite annoying!

There can be multiple ways to fix this, but by far the easiest is to go to your Windows Control Panel, open the Programs and Features list, locate Microsoft SharePoint Designer 2010 in this list and click the Change button. This opens a Setup window with several choices. Close all MS Office programs and choose the Repair option. Wait for a few minutes and after it’s finished, reboot your machine.

The correct settings have now been set for SharePoint Designer 2010 and you should be able to start it directly from the SharePoint pages.

Using Powershell to Add Permission Levels in SharePoint 2010

Besides using PowerShell to modify or adding list permissions, you can also add new Permission Levels. As permission levels don’t persist within site templates, this can be handy when creating deployment scripts for new sites.

Here’s how you do it:

# Add Permission Level to a site
# (c) 2011 Morgan de Jonge

$spSite = Get-SPSite "http://portal.contoso.com"
# We'll assume the list is in the top-level site in the site collection
$spWeb = $spSite | Get-SPWeb

# In this example, we add a new Permission Level labelled "Add Only" to the site, which will allow users to only add new items (no editing or removing)
if($spWeb.RoleDefinitions["Add Only"] -eq $null)
{
    # Role Definition named "Add Only" does not yet exist
    $spRoleDefinition = New-Object Microsoft.SharePoint.SPRoleDefinition
    $spRoleDefinition.Name = "Add Only"
    $spRoleDefinition.Description = "Can only Add items. Use this Permission Level for List or Library Permissions."
    # .Type is a ReadOnly property, hence it'll remain on "None".

    # Use the command [System.Enum]::GetNames("Microsoft.SharePoint.SPBasePermissions") to get a list of possible BasePermission values
    # For this Permission Level, we'll add four base permissions:
    $spRoleDefinition.BasePermissions = "ViewListItems, AddListItems, Open, ViewPages"
    $spWeb.RoleDefinitions.Add($spRoleDefinition)
}

#Display the properties for our new Permission level
$spWeb.RoleDefinitions["Add Only"] | Out-Host

$spWeb.Dispose()
$spSite.Dispose()

Unfortunately, the RoleDefinition.Type property, which contains a RoleType Enum value,  is Read-Only. Hence, it’ll get the default value “None”.

The .BasePermissions Property is a flags attribute which contains the actual permissions granted to users and groups assigned with the permission level. See MSDN for a description of these Permissions, or use the following command to enumerate them in PowerShell:

# Enumerate through SPBasePermissions
PS > [System.Enum]::GetNames("Microsoft.SharePoint.SPBasePermissions")
EmptyMask
ViewListItems
AddListItems
EditListItems
DeleteListItems
ApproveItems
OpenItems
ViewVersions
DeleteVersions
CancelCheckout
ManagePersonalViews
ManageLists
ViewFormPages
Open
ViewPages
AddAndCustomizePages
ApplyThemeAndBorder
ApplyStyleSheets
ViewUsageData
CreateSSCSite
ManageSubwebs
CreateGroups
ManagePermissions
BrowseDirectories
BrowseUserInfo
AddDelPrivateWebParts
UpdatePersonalWebParts
ManageWeb
UseClientIntegration
UseRemoteAPIs
ManageAlerts
CreateAlerts
EditMyUserInfo
EnumeratePermissions
FullMask

See the modify or adding list permissions article for instructions on how to assign this new Permission Level to a user or group.

Modifying list permissions from Powershell

There can be cases where you need to make changes to list permissions or list behaviour regarding security from PowerShell. One case may be where a saved site template does not contain all settings for a list, such as Item-level permission settings (found in List Settings → Advanced Settings). Another case may be a list with unique permissions.

This post contains two examples for making changes to these kind of list settings and permissions from Powershell. These are taken from a deployment script I created for a client.

This script will alter the Item-level Permissions for a list called “Questions” so that users can only access and edit list items they themselves created:

Furthermore, it adds Contribute permissions to the Visitors group for the list, providing unique list permissions (breaking inheritance).

# Alter Item-Level Permission settings and assign "Contribute" role definition to the visitors group
# (c) 2011 Morgan de Jonge

# Specify the name of the visitors SharePoint group
$visitorsSPGroupName = "Example Site Visitors"

$spSite = Get-SPSite "http://portal.contoso.com"
# We'll assume the list is in the top-level site in the site collection
$spWeb = $spSite | Get-SPWeb
# Look up the list named "Questions"
$questionsList = $spWeb.Lists["Questions"]

# Set the Read access Item-level permissions settings to "Read items that were created by the user"
$questionsList.ReadSecurity = 2
# Set the Create and Edit access Item-level permissions to "Create items and edit items that were created by the user
$questionsList.WriteSecurity = 2

# Assign the "Contribute" RoleDefition to the site's visitors group
$visitorsSPGroup = $spWeb.Groups[$visitorsSPGroupName]
$questionsList.BreakRoleInheritance($true)
$assignment = New-Object Microsoft.SharePoint.SPRoleAssignment($visitorsSPGroup)
# Assuming this is a default site, we'll look for a role definition of the type "Contributer".
# This way, the script will also work with SharePoint sites created in languages besides English.
$assignment.RoleDefinitionBindings.Add(($spWeb.RoleDefinitions | Where-Object { $_.Type -eq "Contributor" }))
$questionsList.RoleAssignments.Add($assignment)

$questionsList.Update()

$spWeb.Dispose()
$spSite.Dispose()
(To copy this code, double-click the anywhere in the code and press CTRL/Cmd+C to copy it)

In line 24, you could’ve also looked up the role using $spWeb.RoleDefinitions[“Contribute”], but selecting it based on type will ensure it also works with SharePoint sites in different languages.

See MSDN for the possible values for a list’s ReadSecurity and WriteSecurity.

Count all lists and list items in a site collection

I was recently asked how to inventorize all lists and list items for all sites in a site collection.

Here’s a PowerShell script that does exactly that, displaying the SharePoint site and List name, with the number of items per list:

$ListsInfo = @{}
$TotalItems = 0
$SiteCollection = Get-SPSite "http://<<SiteCollectionURL>>/"
ForEach ($Site in $SiteCollection.AllWebs)
{
    ForEach ($List in $Site.Lists)
    {
        $ListsInfo.Add($Site.Url + " - " + $List.Title, $List.ItemCount)
        $TotalItems += $List.ItemCount
    }
}
$ListsInfo.GetEnumerator() | sort name | Format-Table -Autosize
Write-Host "Total number of Lists: " $ListsInfo.Count
Write-Host "Total number of ListItems: " $TotalItems
(To copy this code, double-click the anywhere in the code and press CTRL/Cmd+C to copy it)

Replace the http://<<SiteCollectionURL>>/ string with the URL for your site collection.

How to find the SharePoint Server 2010 version

In some cases, i.e. installing a language pack, it’s handy to know which version of SharePoint you’re running exactly.

One way is to use Central Administration, go to System SettingsManage servers in this farm.

Or you can use PowerShell:

(Get-SPFarm).buildversion

The most common build numbers are:

  • 14.0.4762.1000 – RTM
  • 14.0.6029.1000 – SP1
  • 14.0.6109.5000 / .5002 – August 2011 CU

For a full list of build numbers, see Todd Klindt’s SharePoint Admin Blog.