Friday, July 28, 2017

SharePoint export and import terms

SharePoint has a great feature to set terms which can be used to tag contents and enable terms based navigation and several other interesting purposes.

Often times we need to migrate terms from one environment to the other and there is not OOB option to export terms in SharePoint 2013. This is not very difficult with powershell however, and this excellent article makes the scripts available for us:

https://blogs.msdn.microsoft.com/thirusrinivasan1/2015/09/28/sharepoint-exportimport-managed-metadata-terms-through-csv/

While trying to use the above scripts I noticed that the import script checks for IsPinned property on the term to be added and in our environment this property was null rather than false. So I have modified that script slightly and reposting both the script for future reference.

Export Terms




# Outputs CSV of the specified termset from the specificed termstore/group
# Example call:
# .\ExportMMStoCsv.ps1 "https://contoso.com:12345" "Managed Metadata Service"
param ([string]$centralAdminUrl = "https://contoso.com:12345",
[string] $termStoreName = "Managed Metadata Service"
)
Add-PSSnapin microsoft.sharepoint.powershell

$maxLevels = 5

function Export-SPTermStoreGroupTerms()
{

    $isValid = $true;
    $message = "";

    if ($centralAdminUrl.Length -eq 0) { $message = "Please provide a central admin URL"; $isValid = $false; }

    if ($isValid -eq $false)
    {
        write-host "ERROR OCCURRED`t$message"
        write-host "NAME`tExport-SPTermStoreGroupTerms"
        write-host "SYNOPSIS`tReturns a CSV file containing a listing of term names and identifiers from the supplied term set."
        write-host "SYNTAX`tExport-SPTermStoreGroupTerms centralAdminUrl termStoreName termGroupName termSetName outPutDir"
        write-host "EXAMPLES Export-SPTermStoreGroupTerms ""http://sp2010"" ""Managed Metadata Service"" ""Enterprise Metadata"" ""Business Units"""
        return;
    }

    try
    {
        $ErrorActionPreference = "Stop";

        try
        {
            $site = Get-SPSite $centralAdminUrl;
            $taxSession = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site, $true);

            try
            {
                $termStore = $taxSession.TermStores[$termStoreName];

                if ($termStore -ne $null)
                {
                    try
                    {
                        $filename = $centralAdminUrl.Replace("https://","").Replace("/","").Replace(":","")
                        $time = (Get-Date).tostring("ddMMyyyy_hhmmss")
                        $outPutFile =  (Get-Location).Path + [string]::Format("\{0}_{1}.csv", $filename,$time);
                        $sb = new-object System.Text.StringBuilder;
                        $sb.Append("TermGroup, TermSet,Term,Level2, Level3,Level4,Level5,UpdatedTitle,Url,FriendlyUrl,CatalogTargetUrl,CatalogChildTargetUrl,TargetUrl,ChildTargetUrl,LastModified,Action,Status");

                        [Byte[]] $ampersand = 0xEF,0xBC,0x86;

                        foreach ($termGroup in $termStore.Groups)
                        {
                            $termgroupName =  $termGroup.Name.Replace([System.Text.Encoding]::UTF8.GetString($ampersand), "&")

                            if ($termgroupName.equals("system", [stringcomparison]::OrdinalIgnoreCase) -eq $false)
                            {
                                try
                                {
                                    foreach($termSet in $termGroup.TermSets)
                                    {
                                        $termsetName  = $termSet.Name.Replace([System.Text.Encoding]::UTF8.GetString($ampersand), "&")

                                        foreach ($term in $termSet.Terms)
                                        {
                                            write-host $termgroupName ","$termsetName","$termName
                                            $termName = $term.Name.Replace([System.Text.Encoding]::UTF8.GetString($ampersand), "&")

                                            $custProp1 = $term.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
                                            $custProp2 = $term.LocalCustomProperties["_Sys_Nav_FriendlyUrlSegment"]
                                            $custProp3 = $term.LocalCustomProperties["_Sys_Nav_CatalogTargetUrl"];
                                            $custProp4 = $term.LocalCustomProperties["_Sys_Nav_CatalogTargetUrlForChildTerms"];
                                            $custProp5 = $term.LocalCustomProperties["_Sys_Nav_TargetUrl"];
                                            $custProp6 = $term.LocalCustomProperties["_Sys_Nav_TargetUrlForChildTerms"];
                                            $custProp7 = $term.LastModifiedDate.ToString("MM/dd/yyyy HH:mm:ss");

                                            $sb1 = new-object System.Text.StringBuilder;
                                            addOutPutField -sb1 $sb1 -field $termgroupName
                                            addOutPutField -sb1 $sb1 -field $termsetName
                                            addOutPutField -sb1 $sb1 -field $termName
                                          
                                            $path = $sb1.ToString();
                                            addEmptyFields -sb1 $sb1 -count 5
                                           
                                            addOutPutField -sb1 $sb1 -field $custProp1
                                            addOutPutField -sb1 $sb1 -field $custProp2
                                            addOutPutField -sb1 $sb1 -field $custProp3
                                            addOutPutField -sb1 $sb1 -field $custProp4
                                            addOutPutField -sb1 $sb1 -field $custProp5
                                            addOutPutField -sb1 $sb1 -field $custProp6
                                            addOutPutField -sb1 $sb1 -field $custProp7
                                            addEmptyFields -sb1 $sb1 -count 2

                                            $sb.AppendLine();
                                            $sb.Append($sb1.ToString());
                                            $sb1.Clear()
                                            GetChildTerms -term $term -path $path -sb $sb
                                        }                                   
                                    }
                                }
                                catch
                                {
                                    "Unable to acquire the termset from the term group"
                                }
                            }
                        }

                        $sw = new-object system.IO.StreamWriter($outPutFile);
                        $sw.Write($sb.ToString());
                        $sw.close();
                        write-host "Your CSV has been created at $outPutFile";
                    }
                    catch
                    {
                        "Unable to acquire term store group"
                    }
                }
            }
            catch
            {
                "Unable to acquire term store"
            }
        }
        catch
        {
            "Unable to acquire session for the site $centralAdminUrl"
        }
    }
    catch
    {

    }
    finally
    {
        $ErrorActionPreference = "Continue";
    }
}

function addOutPutField($sb1, $field){
    $val = "";
    if ($field)
    {
        $val = $field;
    }

    if($sb1.Length -gt 0)
    {
        $sb1.AppendFormat(",{0}",$val);
    }
    else
    {
        $sb1.Append($val);
    }
}

function addEmptyFields($sb1, $count){
    for($i=1; $i -le $count; $i++)
    {
        $sb1.Append(",");
    }
}

function GetChildTerms($term, [object]$path, $sb){
    if ($term.TermsCount -gt 0)
    {
        foreach ($childterm in $term.terms)
        {
            $termName = $childterm.Name.Replace([System.Text.Encoding]::UTF8.GetString($ampersand), "&")
            $custProp1 = $childterm.LocalCustomProperties["_Sys_Nav_SimpleLinkUrl"]
            $custProp2 = $childterm.LocalCustomProperties["_Sys_Nav_FriendlyUrlSegment"]
            $custProp3 = $childterm.LocalCustomProperties["_Sys_Nav_CatalogTargetUrl"];
            $custProp4 = $childterm.LocalCustomProperties["_Sys_Nav_CatalogTargetUrlForChildTerms"];
            $custProp5 = $childterm.LocalCustomProperties["_Sys_Nav_TargetUrl"];
            $custProp6 = $childterm.LocalCustomProperties["_Sys_Nav_TargetUrlForChildTerms"];
            $custProp7 = $childterm.LastModifiedDate.ToString("MM/dd/yyyy HH:mm:ss");

            $sb11 = new-object System.Text.StringBuilder;
            addOutPutField -sb1 $sb11 -field $path
            addOutPutField -sb1 $sb11 -field $termName
            [object] $childpath = $sb11.ToString();
            $fields = $sb11.ToString().split(',')
            addEmptyFields -sb1 $sb11 -count ($maxLevels - $fields.length + 3)
            addOutPutField -sb1 $sb11 -field $custProp1
            addOutPutField -sb1 $sb11 -field $custProp2
            addOutPutField -sb1 $sb11 -field $custProp3
            addOutPutField -sb1 $sb11 -field $custProp4
            addOutPutField -sb1 $sb11 -field $custProp5
            addOutPutField -sb1 $sb11 -field $custProp6
            addOutPutField -sb1 $sb11 -field $custProp7
            addEmptyFields -sb1 $sb11 -count 2

            $sb.AppendLine();
            $sb.Append($sb11.ToString());
            write-host $childpath;
            $sb11.Clear()
            #$sw.writeline($towrite);
           
            GetChildTerms -term $childterm -path $childpath -sb $sb
        }
    }

    $path = "";
}

Export-SPTermStoreGroupTerms



Import Terms

# Outputs CSV of the specified termset from the specificed termstore/group
# Example call:
# .\ImportCsvtpMMS.ps1 "https://contoso.com:12345" "Managed Metadata Service"
param ([string]$centralAdminUrl = "https://contoso.com:12345",
[string] $termStoreName = "Managed Metadata Service",
[string]$configpath = "G:\Deployment\Artifacts\CommonScripts\contosocom12345_28042015_070531.csv"
)
Add-PSSnapin microsoft.sharepoint.powershell

$maxLevels = 5

$actions = @("add","update","delete")
$csvDictionary = New-Object 'system.collections.generic.dictionary[int,object]'

$caSite = get-spsite -Identity $centralAdminUrl
$taxSession = Get-SPTaxonomySession -Site $caSite
$termStore = $taxSession.TermStores[0]
$termGroups= $null;

if ($termStore -eq $null)
{
       $termStore = $taxSession.DefaultSiteCollectionTermStore
    $termGroups = $termStore.Groups
}

function ImportCsv()
{
    $id = 0;
    Import-Csv -Delimiter "," -Path $configpath | % {
        $obj = @{};
        $obj.Id = ++$id;
        $obj.TermGroup = $_.TermGroup
        $obj.TermSet = $_.TermSet
        $obj.Term = $_.Term
        $obj.Level2 = $_.Level2
        $obj.Level3 = $_.Level3
        $obj.Level4 = $_.Level4
        $obj.Level5 = $_.Level5
        $obj.UpdatedTitle = $_.UpdatedTitle
        $obj.Url = $_.Url
        $obj.FriendlyUrl = $_.FriendlyUrl
        $obj.CatalogTargetUrl = $_.CatalogTargetUrl
        $obj.CatalogChildTargetUrl = $_.CatalogChildTargetUrl
        $obj.TargetUrl = $_.TargetUrl
        $obj.ChildTargetUrl = $_.ChildTargetUrl
        $obj.LastModified = $_.LastModified
        $obj.Status = ""
        $obj.Action = $null;

        if ($_.Action -ne $null)
        {
            $obj.Action = $_.Action.tostring().tolower()
        }

        $object = new-object -TypeName PSObject -Property $obj
        $csvDictionary.Add($id, $object);
    }
}

function ProcessCsv()
{
    $csvDictionaryFiltered = $csvDictionary.Values | Where-Object {$_.Action -ne ""}
   
    foreach($obj in $csvDictionaryFiltered)
    {
        if (([string]::IsNullOrEmpty($obj.Action) -eq $false -and $actions.Contains($obj.Action)))
        {
            $action = $obj.Action.ToString().ToLower()

            switch($action)
            {
                "add"
                {              
                    addNewTerm -termobj $obj
                    break;
                }
                "update"
                {
                    updateExisitngTerm -obj $obj
                    break;
                }
                "delete"
                {
                    $_.Action
                    break;
                }
            }
        }
     }
}

function addNewTerm($termobj)
{       
       [String]$group = $obj.TermGroup
       [String]$set = $obj.TermSet
       [String]$Level1 = $obj.Term
       [String]$Level2 = $obj.Level2
       [String]$Level3 = $obj.Level3
       [String]$Level4 = $obj.Level4
       [String]$Level5 = $obj.Level5
         
                        
        $termgroup = $termstore.Groups | where { $_.Name -eq $group }
        if ($termgroup -eq $null)
        {
            $termgroup = $termstore.CreateGroup($group)
        }
   
        $termset = $termgroup.TermSets | where { $_.Name -eq $set }
        if ($termset -eq $null)
        {
            $termset = $termgroup.CreateTermSet($set)
        }

        if($Level1)
        {
           $level1term = createTerm -currentlevelTerm $termset  -levelName $Level1

            if($Level2)
            {
                $level2term = createTerm -currentlevelTerm $level1term  -levelName $Level2

                if($Level3)
                {
                    $level3term = createTerm -currentlevelTerm $level2term  -levelName $Level3

                    if($Level4)
                    {
                        $level4term = createTerm -currentlevelTerm $level3term  -levelName $Level4

                        if($Level5)
                        {
                          $level5term = createTerm -currentlevelTerm $level4term  -levelName $Level5
                        }
                    }
                }
            }
        }
    
}


function createTerm($currentlevelTerm,$levelName)
{
    $nextLevelTerm = $currentlevelTerm.Terms | Where { $_.Name -eq $levelName }
    if($nextLevelTerm -eq $null)
                            {
                                if($currentlevelTerm.IsPinned -eq $null -or $currentlevelTerm.IsPinned -eq $false)
                                {
                                    Write-Host "Createing Term-"$levelName
                                    $nextLevelTerm = $currentlevelTerm.CreateTerm($levelName, 1033)
                                    $termStore.CommitAll();
                                    $termStore.UpdateCache();
                                    $termStore.FlushCache();
                                }
                            }

   
                               
    return $nextLevelTerm
}

function updateExisitngTerm($obj)
{
   
    [String]$group = $obj.TermGroup
       [String]$set = $obj.TermSet
       [String]$Level1 = $obj.Term
       [String]$Level2 = $obj.Level2
       [String]$Level3 = $obj.Level3
       [String]$Level4 = $obj.Level4
       [String]$Level5 = $obj.Level5
       [String]$UpdatedTitle = $obj.UpdatedTitle

       $termgroup = $termstore.Groups | where { $_.Name -eq $group }
        if ($termgroup -eq $null)
        {
            $termgroup = $termstore.CreateGroup($group)
        }
   
        $termset = $termgroup.TermSets | where { $_.Name -eq $set }
        if ($termset -eq $null)
        {
            $termset = $termgroup.CreateTermSet($set)
        }

        if($Level1)
        {
           $level1term = createTerm -currentlevelTerm $termset  -levelName $Level1

            if($Level2)
            {
                $level2term = createTerm -currentlevelTerm $level1term  -levelName $Level2

                if($Level3)
                {
                    $level3term = createTerm -currentlevelTerm $level2term  -levelName $Level3

                    if($Level4)
                    {
                        $level4term = createTerm -currentlevelTerm $level3term  -levelName $Level4

                        if($Level5)
                        {
                          $level5term = createTerm -currentlevelTerm $level4term  -levelName $Level5
                        }
                    }
                }
            }
        }

        Write-Host "Updating Term-"$UpdatedTitle
        if($Level5)
        {           
           updateTermProperties -term $level5term -obj $obj;          
           
        }elseif($Level4)
        {
            updateTermProperties -term $level4term -obj $obj;          
        }
        elseif($Level3)
        {
             updateTermProperties -term $level3term -obj $obj;          
        }
        elseif($Level2)
        {
            updateTermProperties -term $level2term -obj $obj;          
        }
        elseif($Level1)
        {
             updateTermProperties -term $level1term -obj $obj;          
        }
}

function updateTermProperties($term,$obj)
{      
        if($term.IsPinned -eq $false)      
        {
            $term.Name = $obj.UpdatedTitle
        }
        $term.SetLocalCustomProperty("_Sys_Nav_SimpleLinkUrl",$obj.Url)
        $term.SetLocalCustomProperty("_Sys_Nav_FriendlyUrlSegment",$obj.FriendlyUrl)
        $term.SetLocalCustomProperty("_Sys_Nav_CatalogTargetUrl",$obj.CatalogTargetUrl)
        $term.SetLocalCustomProperty("_Sys_Nav_CatalogTargetUrlForChildTerms",$obj.CatalogChildTargetUrl)
        $term.SetLocalCustomProperty("_Sys_Nav_TargetUrl",$obj.TargetUrl)
        $term.SetLocalCustomProperty("_Sys_Nav_TargetUrlForChildTerms",$obj.ChildTargetUrl)

        try
        {
            $termStore.CommitAll();
            $termStore.UpdateCache();
            $termStore.FlushCache();
        }catch [Microsoft.SharePoint.Taxonomy.TermStoreOperationException]
        {
            Write-Host "Term already present - "$term.Name
        }
}

function deleteExisitngTerm()
{
}

function Main
{
    ImportCsv
    ProcessCsv   
}

Main

No comments:

c# httpclient The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch

 If we get this error while trying to get http reponse using HttpClient object, it could mean that certificate validation fails for the remo...