Friday, January 25, 2019

PowerShell to create SharePoint online managed metadata terms from xml file

Our company started to SharePoint online governance plan and design the information architecture. One topic is to provide a global term for tagging and categorization. There are few good article to use PowerShell or C# to create terms from input file, however none of them can satisfy the requirement to create terms from Powershell with multiple levels of terms, and multiple termSet, and mutiple term groups.

I've modified the script we used previously for SharePoint on-premises and here is the code you could use for SPO.

#################################################################################
# Tod: Please update the following paremeters:
# $user        SharePoint admin user account like "harryc@mycompany.onmicrosoft.com"
# $siteUrl     SahrePoint onloine admin site url like "https://mycompany-admin.sharepoint.com/"
# Please install the SharePoint client components SDK - http://www.microsoft.com/en-us/download/details.aspx?id=35585 prior to running this script.

# Input Arguments
param([string]$userName,[string]$siteUrl)

[System.Net.ServicePointManager]::SecurityProtocol =[System.Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy -Scope Process -Confirm:$False -ExecutionPolicy Bypass -Force

#Add references to SharePoint client assemblies and authenticate to Office 365 site - required for CSOM
Add-Type -Path "../Assembly\Microsoft.SharePoint.Client.dll"
Add-Type -Path "../Assembly\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "../Assembly\Microsoft.SharePoint.Client.Taxonomy.dll"

#Specify tenant admin and URL
#$user = "harryc@mycompany.onmicrosoft.com"
#$siteUrl = "https://mycompany-admin.sharepoint.com/"
$user = $userName
$siteUrl = $siteUrl
$password = Read-Host -Prompt "Please enter your password" -AsSecureString

# Import term xml file
[xml]$importxml = Get-Content "..\Config\InputTerms.xml" -Encoding UTF8
#$Import.InnerXml
if ($importxml -eq $null) {
  write-host "Term creation file content is empty!"
  return

}

try{
        #Bind to MMS
        $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
        $creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($user,$password)
        $ctx.Credentials = $creds
        $mms = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($ctx)
        $ctx.Load($mms)
        $ctx.ExecuteQuery()

        #Retrieve Term Stores
        $termStores = $MMS.TermStores
        $ctx.Load($termStores)
        $ctx.ExecuteQuery()

        #Bind to Term Store
        $termStore = $termStores[0]
        $ctx.Load($termStore)
        $ctx.ExecuteQuery()


        Foreach ($groupName in $importxml.Group.Name)
        {
            #Create Groups
            $group = $termStore.CreateGroup($groupName,[System.Guid]::NewGuid().toString())
            $ctx.Load($group)
            $ctx.ExecuteQuery()
            Write-Host "Create group - " $groupName;

            Foreach ($termSet in $importxml.Group.TermSet){
                #Create Term Sets
                $newTermSet = $group.CreateTermSet($termSet.Name,[System.Guid]::NewGuid().toString(),1033)
                $ctx.Load($newTermSet)
                $ctx.ExecuteQuery()
                Write-Host "Create termSet - " $termSet.Name;

                Foreach ($term in $termSet.Term){
                    #Create Terms
                    $newTerm = $newTermSet.CreateTerm($term.Name,1033,[System.Guid]::NewGuid().toString())
                    $ctx.Load($newTerm)
                    $ctx.ExecuteQuery()
                    Write-Host "Create term - " $term.Name;
                    if($term.Term -ne $null){
                        CreateChildTerms $ctx $newTerm $term
                    }
                }
          }
        }
}
catch [System.Exception]

    Write-Host "Exception:"  + $_.Exception.Message -foregroundcolor black -backgroundcolor yellow  
}


#############################################################
# Function to create sub-terms recursively
# $ctx        ClientContext
# $rootTerm   Parent term to create sub-term 
# $term       xml sub-term need to be created
#############################################################
function CreateChildTerms([Microsoft.SharePoint.Client.ClientContext]$ctx, [Microsoft.SharePoint.Client.Taxonomy.Term]$rootTerm, [System.Xml.XmlNode]$term)
{

       foreach ($childnode in $term.Term)
       {
             $addedTerm = $rootTerm.CreateTerm($childnode.Name, 1033, [System.Guid]::NewGuid().toString());
             $ctx.Load($addedTerm);
             $ctx.ExecuteQuery();
             Write-Host "Create child term - " $childnode.Name;

             # If sub-term need to be created, create recursively
             if($childnode.Term -ne $null){
                CreateChildTerms $ctx $addedTerm $childnode
             }
       }

}

There are many things we might need to development around terms like we did for SharePoint on-premises. Here is the list of the scripts in order to provide disaster recovery capability for terms.

1. Script to export the tenant term groups, termSets, and terms along with object GUID in xml file
2. Script to import the tenant term groups, termSets, and terms along with object GUID in xml file

We will keep you posted the progress on these scripts.

No comments:

Post a Comment