Customizing the SharePoint 2013 Suite Bar Branding using PowerShell


I recently stumbled across a great blog post by Wictor Wilen on how to customize the Suite Bar Branding Element HTML on the Central Administration Web Application in SharePoint 2013. If you’re not familiar with this, we’re basically talking about the area at the top left of the SharePoint 2013 user interface:

SuiteBarOOTB

By default, it will just say “SharePoint”. While that’s fine for out of the box folks, this can be a great spot for a little customization. It’s also possible to do this on content web applications, not just Central Administration – and I think this could be a good place to provide a description of the web application. It could also serve as a good place for a hyperlink to always allow the user to get back to the root site – sort of like the Portal Site Connection functionality…

While Wictor’s code was great as a starter point, I thought it would be cool to tweak this a little bit by making it a reusable function and also by allowing the HTML to include a hyperlink to the root site collection in the web application. I simply took his code and modified it to make it a little more reusable, and to also allow for the hyperlink functionality. I also included a custom CSS class name on the A tag to allow for easy branding in your custom solutions.

As for how it works, I’ve provided 3 parameters – 2 of which are required. The required parameters are WebAppUrl and Text; meaning you must provide the link to the web application you want to modify and you must provide the text value you want to replace the out of the box value with. Optionally, you can include a third switch parameter for SetTextAsHyperlink. By including this, you’re sipmly telling the PowerShell function to also make the text a hyperlink to the URL of the web application you are modifying.

Here is the PowerShell function:

function Set-SPSuiteBarBrandingElement {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$WebAppUrl,
[Parameter(Mandatory=$true)][System.String]$Text,
[Parameter(Mandatory=$false)][Switch]$SetTextAsHyperlink
)
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$webApp = Get-SPWebApplication $WebAppUrl
if($SetTextAsHyperLink)
{
    $html = "<div class='ms-core-brandingText'><a class='customSuiteLink' href='$WebAppUrl'>"+$Text+"</a></div>"
}
else
{
    $html = "<div class='ms-core-brandingText'>"+$Text+"</div>"
}
$webApp.SuiteBarBrandingElementHtml = $html
$webApp.Update()
}

To run it, first dot-source the function and then run it like so – example provided below is for my local VM:

Set-SPSuiteBarBrandingElement -WebAppUrl http://sp2013.intranet.adventureworks.com -Text 'AdventureWorks Intranet'

This should give you something like this:
SuiteBar1

Optionally, to make the text a hyperlink – run it like so. Notice that when hovering over it’s now a link – pretty cool!

Set-SPSuiteBarBrandingElement -WebAppUrl http://sp2013.intranet.adventureworks.com -Text 'AdventureWorks Intranet' -SetTextAsHyperlink

SuiteBar2

One last thing I wanted to mention is that in the function above, I’m setting the class of the Anchor tag to “customSuiteLink”. This means if you’re using custom branding, you can reference this CSS class to apply different branding to the link.

Thanks again to Wictor for sharing this!

RD

Advertisements

Remove ‘ReadOnlyField’ lock from columns created in InfoPath using PowerShell


Have you ever created an InfoPath Form Template and published fields from the template to SharePoint Columns in your content type?

I’m sure you have, otherwise you probably wouldn’t be reading this.

Essentially, the columns will be grayed out in the list settings:

And if you try to set the value of the field using SharePoint Designer, you won’t see it in your list of available columns:

However, luckily we have PowerShell – and we can simply edit the ReadOnlyField value from $true to $false – thus allowing us to edit this field. Here’s how!

$web = Get-SPWeb http://weburl
$list = $web.Lists["List Name"]
$field = $list.Fields["Field Name"]
$field.ReadOnlyField = $false
$field.Update()
$list.Update()
$web.Update()
$web.Dispose()

After doing so, the column is not only editable in the browser – we can choose it in Designer:

Add Print Page Functionality Using JavaScript


This morning I received a request from my current client which I’ve gotten before, but not in SharePoint 2010.

They wanted the ability to print page and list view content easily, and without the left and top navigation elements – basically just the main content zone.

I knew there was a way as I had done this in 2007, but I had to do a quick search for the exact JavaScript.  I found a Codeplex project that included a Content Editor Web Part with JavaScript and this worked almost perfectly for my scenario.

This solution works great if you want to print a single page, but I wanted reusability and something that I could do once and have it work for every page in a site.

I ended up copying the script verbatim into a PrintScript.js file which I saved under /_layouts/1033, here is the code of the file:

<!-- Web Part/region to print -->
var WebPartElementID = "ctl00_MSO_ContentDiv";


//Function to print Web Part
function PrintWebPart()
{
 var bolWebPartFound = false;
 //var currentPage = document.location.href;
 if (document.getElementById != null)
 {
  //Create html to print in new window
  var PrintingHTML = '<HTML>\n<HEAD>\n';
  //Take data from Head Tag
  if (document.getElementsByTagName != null)
   {
   var HeadData= document.getElementsByTagName("HEAD");
   if (HeadData.length > 0)
    PrintingHTML += HeadData[0].innerHTML;
   }
  PrintingHTML += '\n</HEAD>\n<BODY>\n';
  var WebPartData = document.getElementById(WebPartElementID);
  if (WebPartData != null)
  {
   PrintingHTML += WebPartData.innerHTML;
   bolWebPartFound = true;
  }
  else
  {
   bolWebPartFound = false;
   alert ('Cannot Find Web Part');
  }
 }
 PrintingHTML += '\n</BODY>\n</HTML>';
 //Open new window to print
 if (bolWebPartFound)
 {
  var PrintingWindow = window.open("","PrintWebPart", "toolbar,width=800,height=600,scrollbars,resizable,menubar");
  PrintingWindow.document.open();
  PrintingWindow.document.write(PrintingHTML);
  // Open Print Window
  PrintingWindow.print();
 }
}

Once I had the JavaScript file saved in the layouts directory, I could simply add a ScriptLink tag in the <head> section of my master page:

<SharePoint:ScriptLink name="PrintScript.js" runat="server"/>

That’s great, now my master page has the ability to print any page; but where do I put the link?  At first I thought of adding a new DIV in the footer area of my page, but I didn’t want the Print link to be included in the printed version of the page.

A quick search on how to add an item to the Site Actions menu gave me EXACTLY what I wanted – and since this is an Intranet solution, every user that needs to print will have at least Contribute permissions and therefore will have the Site Actions menu available to them.

In order to display what I wanted in the Site Actions menu, I added the following code under the <CustomTemplate> section:

<!--Print item added to Site Actions -->
<SharePoint:MenuItemTemplate runat="server" id="MenuItem_PrintPage"
	Text="Print this page"
	Description="This will launch a new window to print this page."
	ImageUrl="/_layouts/images/Print.png"
	MenuGroupId="100"
	Sequence="110"
	ClientOnClickNavigateUrl="javascript:PrintWebPart();"
	/>
<!--End print item-->

And finally, here is what I’m left with:

And clicking the Print Page option gives me a nice, clean window with no navigational elements:

Configuring Custom 404 Pages using PowerShell


I came across an interesting challenge while working on my current project; which is a migration from a classic HTML-based website to SharePoint 2010 For Internet Sites, Enterprise.  Custom error pages…

Out of the box, SharePoint likes to give the user a useless 404 error like this:

image

While there is out-of-the-box support for custom error pages in SharePoint 2010, it’s not completely obvious how you set the custom error pages for a web application.  First of all, SharePoint includes an sps404.html page in the /_layouts/{language} folder which by default includes an STSNavigate reference to handle the redirect.  That’s all well and good, but I want my own!

Here’s how I got what I wanted:

Copy the sps404.html page and rename it to sps404custom.html – leave the new file in the same location.  Open the file in your favorite HTML editor and look for the STSNavigate line – change the link to an appropriate page, example /Pages/Page-Not-Found.aspx.

This would replace the OOTB 404 behavior with an automatic redirect to a Publishing page under the root Pages library of my web application.  Cool!

Now I just have to create a page at /Pages/Page-Not-Found.aspx and add some text.  The page will inherit whatever branding elements I’ve applied to the rest of my site, leaving the user with a much cleaner and consistent experience.  Once I’ve done those two things, there’s a little PowerShell that must be done to actually set the custom 404 page:

$WebApp = Get-SPWebApplication http://url
$WebApp.FileNotFoundPage = "sps404custom.html"
$WebApp.Update() 

Once that’s done, try going to a bogus page in your site and you should be taken to your custom 404 page!

image

Set the Portal Site Connection settings using PowerShell


I’m sure everyone has used the Portal Site Connection settings in SharePoint to add a top-level portal site URL to the breadcrumb. I use it frequently to make sure that all site collections in a web application have a breadcrumb link to the top level/root site collection; however, until today I hadn’t put any thought into making a PowerShell Function to do this automagically to a single site collection or multiple site collections using PowerShell.

It was VERY easy to convert one of my many PowerShell Functions to accomplish this goal, and I started with something simple like:

$site = Get-SPSite http://intranet
$site.PortalUrl = "http://test"
$site.PortalName = "Test Site"
$site.Dispose()

Pretty simple, and certainly effective for a single site – however, I’m always thinking about bigger and better things. 🙂

By adding some logic, an if/else statement and a few parameters; I turned it into an advanced function which can either be used to set a single site collection or all site collections within a web application. Here’s the whole thing:

function Set-SPPortalSiteUrl {
<#
.Synopsis
	Use Set-SPPortalSiteUrl to set the Portal Site Connection Url using PowerShell.
.Description
	This advanced PowerShell function sets the PortalUrl Property of an SPSite Object or multiple SPSites in a SharePoint Web Application
	specified in the -Url parameter.
.Example
	C:\PS>Set-SPPortalSiteUrl -PortalWebAddress http://intranet -PortalName "Intranet Home" -Url http://intranet/hr
	This example sets the Portal Site Connection to http://intranet, with a name of Intranet Home on the http://intranet/hr Site Collection.
.Example
	C:\PS>Set-SPPortalSiteUrl -PortalWebAddress http://intranet -PortalName "Intranet Home" -Url http://intranet -AllSiteCollections
	This example sets the Portal Site Connection to http://intranet, with a name of Intranet Home on the entire http://intranet Web Application.
.Notes
	This function uses an SPSite Object to set the PortalUrl and PortalName properties of one or more SharePoint Site Collections.
.Link
	http://www.sharepointryan.com
 		http://twitter.com/SharePointRyan
.Inputs
	None
.Outputs
	None
.Parameter PortalWebAddress
	The URL to the Portal Site.
.Parameter PortalName
	The Name or Description of the Portal Site.
.Parameter AllSiteCollections
	A Switch parameter, if set - all sites in the web application will be set with the Portal Site Url and Name provided.
.Parameter Url
	The URL of the Site Collection or Web Application to set the Portal Site.
#>    
	[CmdletBinding()]
	Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
	[string]$PortalWebAddress,
	[Parameter(Mandatory=$true)]
	[string]$PortalName,
	[Parameter(Mandatory=$false)]
	[switch]$AllSiteCollections,
	[Parameter(Mandatory=$true)]
	[string]$Url
	)
Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
Start-SPAssignment -Global
	if ($AllSiteCollections) {
	$WebApp = Get-SPWebApplication $Url
	$AllSites = $WebApp | Get-SPSite
		foreach ($site in $AllSites) 
		{
		Write-Host "Setting Portal Web Address to $PortalWebAddress on $($Site.Url)..."
		$site.PortalUrl = $PortalWebAddress
		$site.PortalName = $PortalName
		$site.Dispose()
		}
	} 
	else {
	$AllSites = Get-SPSite -Identity $Url
	Write-Host "Setting Portal Web Address to $PortalWebAddress on $($AllSites.Url)..."
	$AllSites.PortalUrl = $PortalWebAddress
	$AllSites.PortalName = $PortalName
	$AllSites.Dispose()
	}
Stop-SPAssignment -Global
}

Happy PowerShelling!