Thursday, 21 April 2011

Managing Quick Launch (Current) navigation for SharePoint Publishing sites using PowerShell

A few weeks back I published an article on using PowerShell to manage the Quick Launch (otherwise known as “Current”) navigation on SharePoint Foundation sites – or sites in SharePoint Server 2010 where the “SharePoint Server Publishing Infrastructure” site collection feature is not activated.

In this article I will go through a similar scenario of managing headings and links in Quick Launch navigation, but this time where you are using SharePoint Server with the Publishing Infrastructure feature enabled on the site collection. There is also an extra scenario to mention here as well, where the sites within the site collection are actual publishing sites – i.e., sites with the “SharePoint Server Publishing” site feature activated.

First, to clarify, the “SharePoint Server Publishing Infrastructure” feature can be activated on the site collection from the Site collection features option in the Site Settings administration page on the root site of the site collection:

image

I’m not going to go into the exact specifics of what this feature does, but from a navigation point of view, it provides extra options for inheriting links from parent sites, automatic sorting, and additional options for headings and links, including setting a separate title and description, opening in a new window, and applying audience filtering.

Because of these additional options, the code for managing headings and links in PowerShell is also different. First, we need to get the Web, PublishingWeb and QuickLaunch objects and assign them to variables. For this example, I am modifying the root site of a site collection created at http://portal/sites/nav:

$web = Get-SPWeb http://portal/sites/nav
$pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
$qlNav = $pubWeb.Navigation.CurrentNavigationNodes

If you would like to see a list of headings already created on the site with their node ID’s, type the following:

$qlNav | select Title, ID

image

To make changes to a heading, we need to assign it to a variable first. There are methods to do this with the ID and link URL, but I prefer to use the heading Title as it’s more user friendly and will be the same across each site. For example, type this command to get the Libraries heading:

$qlHeading = $qlNav | where { $_.Title -eq "Libraries" }

If there is more than one heading with the same name, you will need to type the following command to select the correct one. Changing the number in the square brackets will be how you do this, with 0 being the first heading, 1 the second heading, 2 the third heading, etc.

$qlHeading = ($qlNav | where { $_.Title -eq "Libraries" })[0]

If you are looking to move the heading order, then you need to get the heading you wish to move, the heading that you wish it to appear under, and then apply the Move method. For example, to move the Lists heading to appear underneath the Discussions heading, type the following:

$qlHeading = $qlNav | where { $_.Title -eq "Lists" }
$qlNewPreviousSibling = $qlNav | where { $_.Title -eq "Discussions" }
$qlHeading.Move($qlNav, $qlNewPreviousSibling)

image

So far, this script has been almost the same as the script for managing Quick Launch navigation in SharePoint Foundation sites – however, here is where it is all about to change. Before I start creating new navigation items, I will assign the CreateSPNavigationNode method to a variable to make it easier to invoke later on in the script:

$CreateSPNavigationNode = [Microsoft.SharePoint.Publishing.Navigation.SPNavigationSiteMapNode]::CreateSPNavigationNode

To create a new heading or link, you have to specify the following information:

  • Display Name – Will appear in the Quick Launch as the name of the item
  • URL – Hyperlink address for the item. You can set this with double-quotes if you do not want to set a URL for the item
  • Node Type – This will specify the type of node available in SharePoint 2010 – e.g., Heading for a navigation heading and AuthoredLinkPlain for a generic link. You can get a full list of available node types from this article: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.nodetypes.aspx
  • SPNavigationNodeCollection to add the new node into

For example, the following lines of script will add a new heading called “External Links” under the existing “Libraries” heading:

$qlNewPreviousSibling = $qlNav | where { $_.Title -eq "Libraries" }
$headingNode = $CreateSPNavigationNode.Invoke("External Links", "", [Microsoft.SharePoint.Publishing.NodeTypes]::Heading, $qlNav)
$headingNode.Move($qlNav, $qlNewPreviousSibling)

image

To add links to a heading, we use the same CreateSPNavigationNode method as before, with the same properties. First, we get the heading that the links will appear under and then add them to the heading as children. In the example below I add one internal and two external links to our new External Links heading:

$qlHeading = ($qlNav | where { $_.Title -eq "External Links" }).Children
$linkNode = $CreateSPNavigationNode.Invoke("Get-SPScripts", "http://get-spscripts.com", [Microsoft.SharePoint.Publishing.NodeTypes]::AuthoredLinkPlain, $qlHeading)
$linkNode = $CreateSPNavigationNode.Invoke("Links", "/sites/nav/Lists/Links/AllItems.aspx", [Microsoft.SharePoint.Publishing.NodeTypes]::AuthoredLinkPlain, $qlHeading)
$linkNode = $CreateSPNavigationNode.Invoke("Follow me on Twitter", "http://twitter.com/phillipchilds", [Microsoft.SharePoint.Publishing.NodeTypes]::AuthoredLinkPlain, $qlHeading)

Because the $linkNode variable is being assigned as each link is created, you can use this opportunity to set additional properties, such as a Description, Target (i.e., Open link in new window), and Audience. Adding the section of script below directly after the “Follow me on Twitter” link has been created will set the options shown in the following screenshot:

$linkNode.Properties["Description"] = "Test description created with PowerShell"
$linkNode.Properties["Target"] = "_blank"
$linkNode.Properties["Audience"] = "All site users"
$linkNode.Update()

image

To view a list of these links after creation, type the following command:

$qlHeading | select Title, ID

image

Finally, to move the link order, you need to get the link you wish to move, the link that you wish it to appear under, and then apply the Move method. The link can be assigned to a variable by accessing the Children property of the heading. For example, to move the “Follow me on Twitter” link to appear underneath the “Get-SPScripts” link, type the following:

$qlNewPreviousLink = $qlHeading | where { $_.Title -eq "Get-SPScripts" }
$qlLink = $qlHeading | where { $_.Title -eq "Follow me on Twitter" }
$qlLink.Move($qlHeading, $qlNewPreviousLink)

image

The end result of all this scripting is that we now have a new heading and three links underneath that heading:

image

Configuring Quick Launch Options

As mentioned at the start of this article, activating the “SharePoint Server Publishing Infrastructure” site collection feature provides extra options for inheriting links from parent sites and automatic link sorting. To configure these in PowerShell, start by getting the Web and PublishingWeb objects and assigning them to variables. To show the inheritance options available, this example calls a sub-site to the root of the http://portal/sites/nav site used earlier:

$web = Get-SPWeb http://portal/sites/nav/subsite
$pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)

The following table shows the options available in the UI followed by the corresponding script to modify them using PowerShell:

image Display the same navigation items as the parent site:

$pubWeb.Navigation.InheritCurrent = $true
$pubWeb.Navigation.ShowSiblings = $false

Display the current site, the navigation items below the current site, and the current site’s siblings:

$pubWeb.Navigation.InheritCurrent = $false
$pubWeb.Navigation.ShowSiblings = $true

Display only the navigation items below the current site (shown left):

$pubWeb.Navigation.InheritCurrent = $false
$pubWeb.Navigation.ShowSiblings = $false

image Show subsites:

$pubWeb.Navigation.CurrentIncludeSubSites = $true

image

Show pages (publishing sites only):

$pubWeb.Navigation.CurrentIncludePages = $true

image Maximum number of 30 dynamic items to show within this level of navigation:

$pubWeb.Navigation.CurrentDynamicChildLimit = 30

image Sort manually:

$pubWeb.Navigation.OrderingMethod = "Manual"

image Sort automatically:

$pubWeb.Navigation.OrderingMethod = "Automatic"

Sort by Title (shown left):

$pubWeb.Navigation.AutomaticSortingMethod = "Title"

Sort by Created Date:

$pubWeb.Navigation.AutomaticSortingMethod = "CreatedDate"

Sort by Last Modified Date:

$pubWeb.Navigation.AutomaticSortingMethod = "LastModifiedDate"

Sort in ascending order (shown left):

$pubWeb.Navigation.SortAscending = $true

Sort in descending order:

$pubWeb.Navigation.SortAscending = $false

image Sort manually with automatic page sorting (publishing sites only):

$pubWeb.Navigation.OrderingMethod = "ManualWithAutomaticPageSorting”

Once you have chosen the options for the script, add the following lines at the end to apply the changes and dispose of the SPWeb object:

$pubWeb.Update()
$web.Dispose()

22 comments:

  1. Very nice post!

    I just wanna correct one thing:

    It chould be: $qlLink = $qlHeading.Children | where { $_.Title -eq "Follow me on Twitter" }

    (added Children).

    /David

    ReplyDelete
  2. Hi, I have tried lot of times but i have the below problem.
    Example
    1. I want to add links under the globalnavigation and as of now globalnavigation does not have any header/links. it is blank.
    2. In that case, I am not able to create the object of $qlHeading, which is required everytime when we create the link. can you help me with that.
    Thanks Labhesh

    ReplyDelete
  3. Hi, I have tried lot of times but i have the below problem.
    Example
    1. I want to add links under the globalnavigation and as of now globalnavigation does not have any header/links. it is blank.
    2. In that case, I am not able to create the object of $qlHeading, which is required everytime when we create the link. can you help me with that.
    3. the reason we can't create $qlHeading object because it will be blank/null. and it is giving error.
    Thanks Labhesh

    ReplyDelete
  4. Nice post. Helped me out a lot.
    I have a small problem with setting the "Audience" property though.
    The audience is set to a sharepoint group but the item will not show in the Quick Launch menu.

    If I then go to navigation under site settings and edit the newly created link, I can see that the audience is set correctly.

    After pressing OK the new link will show in the menu.
    Looks like the audience is not updated until you manually go in and press OK on the link.

    Any idea why this is?

    ReplyDelete
  5. Update. Found the answer.
    Since it's a Sharepoint group you need to put four semicolons (;;;;) in front of the group name.
    Ref: http://ruudheemskerk.net/archive/2010/02/07/set-the-audience-of-a-spnavigationnode-in-sharepoint.aspx

    ReplyDelete
  6. So would this be the script to update all Sorting to Automatic for http://portal? If so it doesn't seem to work for me. I am probably missing something. Please advise me on how to update my script to update all subsites under http://portal to Automatic Sorting.

    My Script:
    Sort automatically:
    $web = Get-SPWeb http://portal
    $pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($web)
    $qlNav = $pubWeb.Navigation.CurrentNavigationNodes
    $pubWeb.Navigation.OrderingMethod = "Automatic"
    $pubWeb.Update()
    $web.Dispose()

    ReplyDelete
  7. Thanks for the post. I used this and reworked it as a quick way to delete a link that got pushed out to all my sites from Central Admin. You can see my post at: http://derbium.wordpress.com/2011/10/19/running-a-script-on-all-sites-in-a-web-application/

    ReplyDelete
  8. Brilliant! Thanks for sharing!

    ReplyDelete
  9. What if I want a N-Level structure?
    -External Links
    > Links
    >> More Links
    >>> Link01
    >>> Link02
    >> Other Links
    > Follow me
    - Libraries
    ....

    ReplyDelete
  10. Hi,

    I am unable to set Audience property for the link created by powershell script above.
    Any suggestions ?

    Krutika

    ReplyDelete
  11. hi i am working on SharePoint 2013, i am facing problem in quick launch in current navigation

    problem:
    while navigating to site its generating an extra heading(suppose i am clicking any link inside "Investor" , its goes to sub site "investor" and showing addition heading with name "investor" having url welcome page )

    please help
    thanks

    ReplyDelete
    Replies
    1. I'm having the same issue in Sharepoint 2010.

      Did you find an answer?

      Delete