Friday, June 6, 2014

SharePoint 2010 - Export and import global navigation

I was working on a script to import and export Global navigation including the navigation settings for SharePoint sites.
Here’s the full script.

The first script exports the global navigation settings to the GlobalNavigationSettings.xml file and the navigation nodes with the hierarchy to the GlobalNavigationNodes.xml file

param([string]$siteUrl, [string]$exportPath = 'C:\Temp') 
$ErrorActionPreference = 'Stop'

If ((Get-PsSnapin |?{$_.Name -eq "Microsoft.SharePoint.PowerShell"})-eq $null)
{
      Add-PsSnapin Microsoft.SharePoint.PowerShell - ErrorAction SilentlyContinue | Out-Null
}

function Export-GlobalNavigation-Settings
{
      param([Microsoft.SharePoint.Publishing.PublishingWeb]$publishingWeb, [string]$exportPath)
      if([System.IO.Directory]::Exists($exportPath-ne $true)
      {
            Write-Error "Export path " $exportPath " is not valid. Make sure that the directory exists"
      }
      $fileName = [System.IO.Path]::Combine($exportPath"GlobalNavigationSettings.xml")
      Write-Host "Exporting global navigation settings to " $fileName
      ($publishingWeb.Navigation | ConvertTo-Xml).Save($fileName)
      Write-Host -ForegroundColor Green "Successfully exported global navigation settings.."
}

function Add-To-XmlDocument
{
      param([Xml.XmlNode]$xnode, [Microsoft.SharePoint.Navigation.SPNavigationNodeCollection$nodes, [int$level)  
      foreach($node in $nodes)
      {
            Write-Host -ForegroundColor Blue "Adding new navigation node" $node.Title
            [Xml.XmlNode$navigationNodeElement = $siteNavigationDoc.CreateElement("NavigationNode")
            [System.Xml.XmlAttribute$titleAttribute = $siteNavigationDoc.CreateAttribute("title")
            $titleAttribute.Value = $node.Title
            [System.Xml.XmlAttribute$urlAttribute = $siteNavigationDoc.CreateAttribute("url")
            $urlAttribute.Value = $node.Url
            [System.Xml.XmlAttribute$isVisibleAttribute = $siteNavigationDoc.CreateAttribute("isVisible")
            $isVisibleAttribute.Value = [string]$node.IsVisible
            [System.Xml.XmlAttribute$idAttribute = $siteNavigationDoc.CreateAttribute("id")
            $idAttribute.Value = [string]$node.Id
            [System.Xml.XmlAttribute$levelAttribute = $siteNavigationDoc.CreateAttribute("level")
            $levelAttribute.Value = [string]$level
            $navigationNodeElement.Attributes.Append($titleAttribute)
            $navigationNodeElement.Attributes.Append($urlAttribute)
            $navigationNodeElement.Attributes.Append($isVisibleAttribute)
            $navigationNodeElement.Attributes.Append($idAttribute)
            $navigationNodeElement.Attributes.Append($levelAttribute)
           
            if($node.Properties.Count -gt 0)
            {          
                  foreach($property in $node.Properties.GetEnumerator())
                  {
                        [Xml.XmlNode$propertyNode = $siteNavigationDoc.CreateElement("Property")
                        [Xml.XmlAttribute$keyAttribute = $siteNavigationDoc.CreateAttribute("key")
                        $keyAttribute.Value = [string]$property.Key
                        [Xml.XmlAttribute$valueAttribute = $siteNavigationDoc.CreateAttribute("value")
                        $valueAttribute.Value = [string]$property.Value
                        $propertyNode.Attributes.Append($keyAttribute)
                        $propertyNode.Attributes.Append($valueAttribute)
                        $navigationNodeElement.AppendChild($propertyNode)
                  }
            }
           
            $xnode.AppendChild($navigationNodeElement)
           
            Write-Host -ForegroundColor Green "Successfully added new navigation node" $node.Title
            if ($node.Children.Count -gt 0)
        {
                  $newLevel = $level + 1
            Add-To-XmlDocument $navigationNodeElement $node.Children $newLevel
        }                          
      }
}

function Export-GlobalNavigation-Nodes
{
      param([Microsoft.SharePoint.Publishing.PublishingWeb]$publishingWeb, [string]$exportPath)
      if([System.IO.Directory]::Exists($exportPath-ne $true)
      {
            Write-Error "Export path " $exportPath " is not valid. Make sure that the directory exists"
      }
      $fileName = [System.IO.Path]::Combine($exportPath"GlobalNavigationNodes.xml")
      Write-Host "Exporting global navigation settings to " $fileName
     
    [System.Xml.XmlNode$declarationNode = $siteNavigationDoc.CreateXmlDeclaration("1.0""UTF-8"$null)
    $siteNavigationDoc.AppendChild($declarationNode)

    [System.Xml.XmlNode$globalNavigationNode = $siteNavigationDoc.CreateElement("NavigationNodes")
    $siteNavigationDoc.AppendChild($globalNavigationNode)
     
      Add-To-XmlDocument $globalNavigationNode $publishingWeb.Navigation.GlobalNavigationNodes $nodeLevel
      $siteNavigationDoc.Save($fileName)
      Write-Host -ForegroundColor Green "Successfully exported global navigation settings.."
}


$site = Get-SPSite $siteUrl
$rootWeb = $site.RootWeb
$pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($rootWeb)
$nodeLevel = 1
Export-GlobalNavigation-Settings $pubWeb $exportPath

[System.Xml.XmlDocument$siteNavigationDoc = New-Object System.XML.XMLDocument    
Export-GlobalNavigation-Nodes $pubWeb $exportPath

The script creates two xml files, one with the navigation settings and one with the node hierarchy.




The second script is used to import the settings from the GlobalNavigationSettings.xml file and create navigation nodes from the GlobalNavigationNodes.xml file

param([string]$siteUrl, [string]$exportPath = 'C:\Temp')
$ErrorActionPreference = 'Stop'

If ((Get-PsSnapin |?{$_.Name -eq "Microsoft.SharePoint.PowerShell"})-eq $null)
{
      Add-PsSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue | Out-Null
}

function Import-GlobalNavigation-Settings
{
      param([Microsoft.SharePoint.Publishing.PublishingWeb]$publishingWeb, [string]$exportPath)
      if([System.IO.Directory]::Exists($exportPath-ne $true)
      {
            Write-Error "Export path " $exportPath " is not valid. Make sure that the directory exists"
      }
      $fileName = [System.IO.Path]::Combine($exportPath"GlobalNavigationSettings.xml")
      if([System.IO.File]::Exists($fileName-ne $true)
      {
            Write-Error "Unable to find site navigation settings file " $fileName
      }
      [xml]$settings = Get-Content $fileName
      $root = $settings.DocumentElement  
     
      Write-Host "Updating global navigation settings"
      Write-Host $root.SelectSingleNode('descendant::Object/Property[@Name="InheritGlobal"]').'#text'
      $var = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="GlobalIncludeSubSites"]').'#text')
      Write-Host $var
     
      $publishingWeb.Navigation.InheritGlobal = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="InheritGlobal"]').'#text')
      $publishingWeb.Navigation.GlobalIncludeSubSites = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="GlobalIncludeSubSites"]').'#text')
      $publishingWeb.Navigation.GlobalIncludePages = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="GlobalIncludePages"]').'#text')
      $publishingWeb.Navigation.GlobalDynamicChildLimit = [int]$root.SelectSingleNode('descendant::Object/Property[@Name="GlobalDynamicChildLimit"]').'#text'

      Write-Host "Updating current navigation settings"
      $publishingWeb.Navigation.InheritCurrent = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="InheritCurrent"]').'#text')
      $publishingWeb.Navigation.ShowSiblings = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="ShowSiblings"]').'#text')
      $publishingWeb.Navigation.CurrentIncludeSubSites = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="CurrentIncludeSubSites"]').'#text')
      $publishingWeb.Navigation.CurrentIncludePages = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="CurrentIncludePages"]').'#text')
      $publishingWeb.Navigation.CurrentDynamicChildLimit = [int]$root.SelectSingleNode('descendant::Object/Property[@Name="CurrentDynamicChildLimit"]').'#text'

      Write-Host "Updating rootweb navigation sorting settings"
      $publishingWeb.Navigation.OrderingMethod = [Microsoft.SharePoint.Publishing.OrderingMethod]$root.SelectSingleNode('descendant::Object/Property[@Name="OrderingMethod"]').'#text'
      $publishingWeb.Navigation.AutomaticSortingMethod = [Microsoft.SharePoint.Publishing.AutomaticSortingMethod]$root.SelectSingleNode('descendant::Object/Property[@Name="AutomaticSortingMethod"]').'#text'
      $publishingWeb.Navigation.SortAscending = [System.Convert]::ToBoolean($root.SelectSingleNode('descendant::Object/Property[@Name="SortAscending"]').'#text')

      #Update the Publishing Web Navigation Settings
      $publishingWeb.Update()
      Write-Host -ForegroundColor Green "Successfully imported global navigation settings.."
}


function Populate-NavigationNodes
{
      param ([Microsoft.SharePoint.Navigation.SPNavigationNodeCollection$nodes, [Xml.XmlNodeList$xNodes, [int$level)
      $level = $level + 1;
      foreach($xNode in $xNodes)
      {
            $title = $xNode.Title
            $url = $xNode.Url
            $isVisible =[Boolean]$xNode.IsVisible    
            $CreateNavigationNodeMethod = [Microsoft.SharePoint.Publishing.Navigation.SPNavigationSiteMapNode]::CreateSPNavigationNode
                 
            $nodeTypePropertyElement = $xNode.SelectSingleNode('descendant::Property[@key="NodeType"]')
            $nodeType = [Microsoft.SharePoint.Publishing.NodeTypes]::AuthoredLinkPlain
            if($nodeTypePropertyElement -ne $null)
            {
                  $nodeType = [System.Enum]::Parse([Microsoft.SharePoint.Publishing.NodeTypes], $nodeTypePropertyElement.value)
            }
            Write-Host -ForegroundColor Blue "Creating navigation node " $title
            $spNavigationNode = $CreateNavigationNodeMethod.Invoke($title$url$nodeType$nodes)
            $spNavigationNode.IsVisible = $isVisible
            $spNavigationNode.Update()
            Write-Host -ForegroundColor Green "Successfully created navigation node " $title
           
            $xPath = 'descendant::NavigationNode[@level="' + [string]$level + '"]'
           
            $navigationNodeElements = $xNode.SelectNodes($xPath)
            if($navigationNodeElements.Count -gt 0)
            {
                  Populate-NavigationNodes $spNavigationNode.Children $navigationNodeElements $level
            }
      }
}

function Import-GlobalNavigation-Nodes
{
      param([Microsoft.SharePoint.Publishing.PublishingWeb]$publishingWeb, [string]$exportPath)
      if([System.IO.Directory]::Exists($exportPath-ne $true)
      {
            Write-Error "Export path " $exportPath " is not valid. Make sure that the directory exists"
      }
      $fileName = [System.IO.Path]::Combine($exportPath"GlobalNavigationNodes.xml")
      if([System.IO.File]::Exists($fileName-ne $true)
      {
            Write-Error "Unable to find site navigation nodes file " $fileName
      }
     
      Write-Host "Removing existing global navigation nodes"
      $sharePointGlobalNodes = @(1000, 1002, 1025)
      for($i = $publishingWeb.Navigation.GlobalNavigationNodes.Count-1; $i -ge 0; $i--)
      {
            $node = $publishingWeb.Navigation.GlobalNavigationNodes[$i]
            if(($sharePointGlobalNodes -contains $node.Id-ne $true)
            {
                  Write-Host -ForegroundColor Blue $node.Title
                  $node.Delete()
                  $node.Update
            }
      }    
      $publishingWeb.Update()
     
      [xml]$nodesContent = Get-Content $fileName
      $root = $nodesContent.DocumentElement
      $spNavigationNodeElements = $root.SelectNodes('descendant::NavigationNode[@level="1"]')
     
      Populate-NavigationNodes $publishingWeb.Navigation.GlobalNavigationNodes $spNavigationNodeElements 1
      $publishingWeb.Update()
}

$site = Get-SPSite $siteUrl
$rootWeb = $site.RootWeb
$pubWeb = [Microsoft.SharePoint.Publishing.PublishingWeb]::GetPublishingWeb($rootWeb)
Import-GlobalNavigation-Settings $pubWeb $exportPath
Import-GlobalNavigation-Nodes $pubWeb $exportPath


6 comments:

Greg R said...

This script is absolutely amazing! Thank you so much for saving countless hours. YOU ROCK!

Greg R said...

LOVE LOVE LOVE this script! Saved me many hours. Exactly what I was looking for and works perfect and extremely quick. Thanks again.

Festooned With Hussies said...

Wonderful script! It's going to make my 2013 upgrade a million time easier. Nice work!

Unknown said...

Fantastic !
I'm upgrading to 2013, and the upgrade process ruins my Global navigation.. These scripts are fantastic.

Prajeesh Prathap said...

Thanks guys, glad to know that it helped your work

Jason Lochan said...

Amazing work, recursive and neat -- thank you!