Event Receiver to Remove “Recent” from SP2013 Quick Launch

I’m sure removing the Recent heading from the Quick Launch in SharePoint 2013 has been talked about a million times over since SharePoint 2013 was launched. It’s been solved in this way and that way, by hand, with javascript and programmatically. In this post I share the code to remove the heading with the ListAdded event receiver.

With and without the Recent heading on the Quick Launch navigation.
With and without the Recent heading on the Quick Launch navigation.

Event receiver code

It’s based on code provided as an answered on the SharePoint StackExchange website by Remko van Laarhoven. I’ve then wrapped in a list added event receiver so that it is executed each time a new list or library is added. As the list/library is then not available on the Quick Launch I’ve added a couple of lines to then show it.

Update (22nd June 2014): since creating this solution I have since discovered that the Recent heading still is created even with the event receiver triggering when lists/libraries created from templates. I resolved this by adding a sleep before the code to remove the heading is executed.
[code language=”c”]System.Threading.Thread.Sleep(1500);[/code]

This in conjunction with the jQuery method prevent users from ever seeing the Recent Heading whether they are viewing the page or editing the links on the page.
[code language=”js”]
// Hide Recent on Quick Launch
$("#ctl00_PlaceHolderLeftNavBar_QuickLaunchNavigationManager .ms-core-listMenu-root li:contains(‘Recent’)").children().remove();
$("#ctl00_PlaceHolderLeftNavBar_QuickLaunchNavigationManager .ms-core-listMenu-item:contains(‘Recent’)").remove();
[/code]

[code language=”c”]
public class ListAddedEventReceiver : SPListEventReceiver
{
public override void ListAdded(SPListEventProperties properties)
{
base.ListAdded(properties);
SPWeb web = properties.Web;
if (web != null)
{
//Sleep
System.Threading.Thread.Sleep(1500);

//Remove heading
var title = SPUtility.GetLocalizedString("$Resources:core,category_Recent", null, web.Language);
SPNavigationNodeCollection nodes = web.Navigation.QuickLaunch;
foreach (SPNavigationNode node in nodes)
{
if (node.Title.ToLower().Equals(title.ToLower()))
{
// Delete the recent heading node
node.Delete();
break;
}
}
// Show list on the quick launch
SPList list = web.Lists[properties.ListId];
list.OnQuickLaunch = true;
list.Update();
}
}
}
[/code]

Download Remove Recent Heading Solution

For those who don’t want to create the event receiver themselves in Visual Studio or don’t know how to, I have a packaged the solution so that you can deploy the WSP to your environment. For those who don’t know how to use this code, I will write a post explaining how to create this event receiver using Visual Studio from an IT Pros perspective very soon.

jcallaghan.removerecentheading.wsp

As with anything you download from the internet remember to review, rename and test this code/solution before using it in a production environment.

The Deployment Guide of all SharePoint 2013 Deployment Guides

Let me introduce you to the Deployment guide for Microsoft SharePoint 2013. Anyone deploying, installing or configuring SharePoint 2013 absolutely must read this!

This particular Deployment Guide is 674 pages long and like no other. It was published by the Microsoft Office System and Servers Team at Microsoft back in October 2012.

It is such a great guide and is packed full of information. Reading through the deployment guide, I discovered some neat little tricks and refreshed myself on some pretty important best practices which is always a good exercise.

Download it now, get reading and share it!

Working with SharePoint’s Second Stage Recycle Bin in PowerShell

I thought I’d share a PowerShell script that I’ve created to perform a few tasks against a Site Collection Second Stage Recycle Bin (SSRB) in SharePoint.

Remove-SecondStageRecycleBinItems.ps1
Remove-SecondStageRecycleBinItems.ps1

The requirement was to delete items that were older than a set number of days from the Second Stage Recycle Bin (SSRB). A record of each item deleted also needed to be added to a report.  But SharePoint can do this already I hear you say…well yes if a Site Collection quotas and the auditing features are used. In this scenario neither could be.

To display items in the Second State Recycle Bin in a table I used this command.

[code lang=”powershell”]$site.Recyclebin | where { $_.ItemState -eq "SecondStageRecycleBin" -and $_.deleteddate -le $dateDiff} | Format-Table -Property Title, Web, DeletedBy, DeletedDate -Autosize -Wrap
[/code]

Then to remove each item from the Recycle Bin I used the delete command.

[code lang=”powershell”]$site.Recyclebin.Delete($_.ID)[/code]

The full script is shared below. Remember to review, rename and test this script before using it in a production environment.

[code lang=”powershell”]
#——————————————————————————–
#
# Remove-SecondStateRecycleBinItems.ps1
#
# Author: James Callaghan (www.jcallaghan.com)
# Date: April 2014
#
# This script will delete items from the Second Stage Recycle Bin that
# are older than XX days.
#
#——————————————————————————–

Add-PSSnapin Microsoft.SharePoint.PowerShell

#Variables
$i = 0

#SharePoint Site Collection URL
$url = "http://apm.dev.jcallaghan.com"
#$url = Read-Host "Enter a valid URL to a SharePoint Site Collection?"
#if($url -eq ""){write-host "No URL provided." -foregroundcolor Red; Exit}

#How many days ago should items be deleted from?
$deleteFrom = -10
#$deleteFrom = Read-Host "Remove items older than how many days?"
#if($deleteFrom -eq ""){write-host "No value provided." -foregroundcolor Red; Exit}

#Create report in script path
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
$report = "$($dir)\DeletedSecondStateRecycleBinItems.csv"

#Date calculations
$dateNow = Get-Date
$dateDiff = $dateNow.AddMinutes(-$deleteFrom)
#$dateDiff = $dateNow.AddDays($deleteFrom)

#Display date/times for review in table
$table = @()
$review = New-Object System.Object
$review | Add-Member -type NoteProperty -Name "Date" -Value "Timestamp now"
$review | Add-Member -type NoteProperty -Name "Value" -Value $dateNow
$table += $review
$review = New-Object System.Object
$review | Add-Member -type NoteProperty -Name "Date" -Value "Files older than"
$review | Add-Member -type NoteProperty -Name "Value" -Value $dateDiff
$table += $review
$table | Format-Table –AutoSize

#Connect to the site
$site = Get-SPsite $url

#Report file and first row
New-Item $report -type file -Force | Out-Null
Add-Content $report "Deleted Items: $($dateNow)"
Add-Content $report "Name, Title, Deleted by, Deleted date, Path, File Guid"

#Get items from the Seconday Stage Recycle Bin (SSRB) that are older than are removel period.
$items = $site.Recyclebin | where { $_.ItemState -eq "SecondStageRecycleBin" -and $_.deleteddate -le $dateDiff}
$site.Recyclebin | where { $_.ItemState -eq "SecondStageRecycleBin" -and $_.deleteddate -le $dateDiff} | Format-Table -Property Title, Web, DeletedBy, DeletedDate -Autosize -Wrap

#Confirm there are items to delete
if($items -ne $null){

#Create prompt
$ok = New-Object System.Management.Automation.Host.ChoiceDescription "&OK","Description."
$cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&CANCEL","Description."
$options = [System.Management.Automation.Host.ChoiceDescription[]]($ok, $cancel)
$title = "Confirm"; $message = "Delete items from Second Stage Recycle Bin?"
$result = $host.ui.PromptForChoice($title, $message, $options, 1)

switch ($result) {
0{
#Get items to be deleted
$site.Recyclebin | where { $_.ItemState -eq "SecondStageRecycleBin" -and $_.deleteddate -le $dateDiff} | foreach{
#Add entry to report
Add-Content $report "$($_.LeafName),$($_.Title),$($_.deletedbyname),$($_.deleteddate),$($_.Dirname),$($_.Id)"

#Delete item by ID
$site.Recyclebin.Delete($_.ID)

$i++
}
write-host "$($i) items removed from Second Stage Recycle Bin."
}1{
write-host "Cancelled by user." -foregroundcolor Red
}
}
}else{
write-host "No files were found in the Second Stage Recycle Bin." -foregroundcolor Red
}

#Dispose
$site.dispose();
[/code]

One quirk I found while creating the script was that through the web browser, SharePoint reported the time each file was deleted correctly whereas in PowerShell, the time was not honouring GMT summer time.

British Summer Time  in SharePoint vs. PowerShell
British Summer Time in SharePoint vs. PowerShell

Enjoy and delete carefully!

Some light reading after the SharePoint Conference

I’ve managed to pickup some reading materials while in America that are going to keep me busy for some weeks.

Microsoft SharePoint 2013 Administration

First up was a book (Microsoft SharePoint 2013 Administration) I picked up at the AvePoint during a book signing during the SharePoint Conference.

Two of the Authors Randy Williams and Chris Givens kindly signed it for me – it was really great to meet these two authors after many years of reading their books.

Authors Randy Williams and Chris Givens at AvePoint book signing.
Authors Randy Williams and Chris Givens at AvePoint book signing.

Alcatraz 1259

Second up was a book (Alcatraz 1259) from Alcatraz Island signed by the author Willam G. Baker himself who happened to be there just after finishing his parole aged 81. He is one of the last living cons who served in US Penitentiary Alcatraz and shares his account of life there in the book.

Alcatraz 1259 author William G. Baker during book signing.
Alcatraz 1259 author William G. Baker during book signing.

I hadn’t appreciated the history of the Island, the Penitentiary or the prisoners and guards up until the audio tour. Up until this point I had just seen it as a prison in America that featured in the movie The Rock but the Island has a fascinating past – one that I am looking forward to learning more and more about.

I’ve struggled to put Bill’s account of life on the Island down since we brought it – once done I’m going to find a guards account of life on the Island among others.

MCSA Windows Server 2012 exams

During the SharePoint Conference I took the opportunity to update my Microsoft Certifications – more about that another day.

To complete the Microsoft Certified Solutions Expert (MCSE) in SharePoint I have to pass 70-410, 70-411 and 70-412 also making me a Microsoft Certified Solutions Associate (MCSA) in Windows Server 2012.

MCSA Windows Server 2012 reading
MCSA Windows Server 2012 reading

Happy reading I guess.

Error when creating new Site Collections via Central Administration

A customer recently reported that they were not able to create any new Site Collections within any Web Application in their SharePoint 2013 UAT environment. Instead of being able to create a new Site Collection they repeatedly received the error shown in the image below.

Provider must implement the class 'System.Web.Security.MembershipProvider'.
Provider must implement the class ‘System.Web.Security.MembershipProvider’.

I in order to troubleshoot this issue I tried creating a Site Collection myself while monitoring the ULS logs. An event with an ID of 8307 was appearing in the logs each time I tried to create a new Site Collection. This event had a message of “An exception occurred in Forms claim provider when calling SPClaimProvider.FillResolve(): Provider must implement the class ‘System.Web.Security.MembershipProvider’. (C:\inetpub\wwwroot\wss\VirtualDirectories\34596\web.config line 606)”.

ULS Viewer
ULS Viewer
Event 8307. SharePoint Foundation. Claims Authentication.
Event 8307, SharePoint Foundation, Claims Authentication.

This suggested a problem with the web.config for the Central Administration Web Application and an error with a Membership provider. Forms Based Authentication (FBA) has been used to configure FBA in this environment so I continued exploring this avenue further.

I reviewed the web.config at the line indicated from the event and noticed that there were multiple entries for FBA membership and role providers. I removed these duplicate entries and was able to create Site Collections without any problems then.

As the Forms Based Authentication in this environment was configured using the FBA Configuration Manager I can only think that this was at fault somehow – the odd thing is that the same tool was also used on to configure the production environment which I also confirmed was not also having the same issue.

I would suggest that after using the FBA Configuration Manager to configure FBA that you ensure you can create new Site Collections. It’s certainly something I am going to be including to my deployment checklist!