Tuesday, June 23, 2015

Share Local Term Store Across Multiple Site Collections - PowerShell Script

I was migrating a site that used a Local Term Store for some of their metadata fields.  This caused all sorts of issues when trying to migrate content, since that data couldn't come along to the new site collection.  So when you tried and edit the properties the fields would appear red and you couldn't save anything.  I found some posts that mentioned how to reset it from a backup restore, including:

http://blogs.msdn.com/b/bettertogether/archive/2014/10/04/site-collection-backup-restore-when-using-local-term-groups.aspx

and an article resurrected from the wayback machine by Sergey Zelenov:

http://web.archive.org/web/20111109050809/http://sharepoint.microsoft.com/Blogs/fromthefield/Lists/Posts/Post.aspx?ID=138

I expanded on this one a bit so that you can pass it the site collection url of the site with the local term store, and the site you want the "local" term store to appear in, and after you run this you'll be able to use the local term store across both site collections.

function Add-SPSiteLocalTermSetAccess
{
    [CmdletBinding()]


    param (
                 [parameter(Mandatory=$true,
                        ValueFromPipeline=$true)]
                 $originalSite,
[parameter(Mandatory=$true,
                        ValueFromPipeline=$true)]
                 $siteToAdd
              )
    
    begin
    {
        if (-not (Get-PSSnapin | Where-Object {$_.Name -eq "Microsoft.SharePoint.PowerShell"}))
        {
            Add-PSSnapin Microsoft.SharePoint.PowerShell;
        }
        
        ## Force the script to terminate on errors that would by default be treated as non-terminating
        $ErrorActionPreference = "Stop";        
    }
   
    process
    {
        if ($originalSite -isnot [Microsoft.SharePoint.SPSite])
        {
            $originalSite = Get-SPSite -Identity $originalSite;
            Write-Verbose -Message ("Bound to site collection {0} at {1}" -f $originalSite.Id, $originalSite.Url);
        }
       

        $ts = Get-SPTaxonomySession -Site $originalSite;
        
        ## Obtain the ID of the term set group from the root site property bag
        $sgroupid = $originalSite.RootWeb.AllProperties.Keys | 
            Where-Object `
            {
                $_ -like "SiteCollectionGroupId*"
            } | 
                Select-Object -Property @{n="GroupID";e={$originalSite.RootWeb.AllProperties[$_]}} |
                    Select-Object -ExpandProperty GroupID;
          
Write-Verbose -Message ("sgroupid: '{0}'" -f $sgroupid)
 

        $sgroup = $ts.TermStores[0].Groups[$sgroupid];
        if ($sgroup -eq $null)
        {
            throw "Target term store group could not be found!"
        }
        
        Write-Verbose -Message ("Found term set group: '{0}'" -f $sgroup.Name)

Write-Verbose -Message ("Group Access IDs: '{0}'" -f $sgroup.SiteCollectionAccessIds)
        
        ## Remove the 'old' (prior to backup/delete/restore) site collection ID from the group access list
        ## We don't want to lose the originalSite's association in this case
        #$sgroup.SiteCollectionAccessIds | 
        #    Foreach-Object `
        #    {
        #        $sgroup.DeleteSiteCollectionAccess($_);
        #        Write-Verbose -Message ("Removed ID '{0}' from the Site Collection Access List" -f $_);
        #    }
        
if ($siteToAdd -isnot [Microsoft.SharePoint.SPSite])
        {
            $siteToAdd = Get-SPSite -Identity $siteToAdd;
            Write-Verbose -Message ("Bound to site collection {0} at {1}" -f $siteToAdd.Id, $siteToAdd.Url);
        }

        ## Add the new site collection ID to the group access list
        $sgroup.AddSiteCollectionAccess($siteToAdd.Id);
        Write-Verbose -Message ("Added new site ID ('{0}') to the Site Collection Access List" -f $siteToAdd.Id);

        
        ## Persist the changes in the database - very important!!
        $sgroup.TermStore.CommitAll();
        Write-Verbose -Message ("Commited all changes to term store '{0}'" -f $sgroup.TermStore.Name);
        

## Get the siteToAdd SiteCollectionGroupId
## Obtain the ID of the term set group from the root site property bag
        $siteToAddGroupId = $siteToAdd.RootWeb.AllProperties.Keys | 
            Where-Object `
            {
                $_ -like "SiteCollectionGroupId*"
            } 

Write-Verbose -Message ("SiteToAddGroupID: ('{0}')" -f $siteToAddGroupId)

# Get the first of the collection (if multiple)
  # NOTE:  This targets the first one -- might need to loop through
  # this if multiple, or target the specific one.  
$siteToAddGroupId = $siteToAddGroupId[0]

$webProp = $web.GetProperty($siteToAddGroupId)

# cast to string
$stringGroupId = $sgroupid.ToString()

Write-Verbose "siteToAddGroupId: $siteToAddGroupId"
Write-Verbose "stringGroupId: $stringGroupId"
Write-Verbose "WebProp: $webProp"

If ($webProp -eq $null)
{
  # Add property
  Write-Verbose "Property is null..."
  $web.AddProperty($siteToAddGroupId, $stringGroupId)
  $web.Update()
}
Else
{
  # Property exists – remove/re-add the property   
  Write-Verbose "Property already exists, in else..."
  $web.DeleteProperty($siteToAddGroupId)
  $web.AddProperty($siteToAddGroupId, $stringGroupId)
  $web.Update()  
}

        Write-Output -InputObject ("Site collection's access to term store group '{0}' added successfully" -f $sgroup.Name);
    }
   
    end
    {}
}

Add-SPSiteLocalTermSetAccess http://mywebapp.com/sites/sitewithtermstore http://mywebapp.com/sites/newsitetosharetermstore -Verbose


Note that afterwards I had to re-inherit permissions at the hidden taxonomy list here:

http://mywebapp.com/sites/newsitetosharetermstore/Lists/TaxonomyHiddenList

before users could see the data in the columns.

No comments: