Daily Archives: August 21, 2018

Recursively update File metadata taxonomy field

In this blog you will find a CSOM PowerShell code to update Taxonomy field of a file. The script in the Github will recursively go through all the folders in a library and update the taxonomy field. The script update the field to the specific term you mention. To update the taxonomy field you will need the below details

$termValue.Label

$termValue.TermGuid

$termValue.WssId

To find the WSSID of the term you will need to navigate to the Site collection level Hidden Taxonomy List using the URL /Lists/TaxonomyHiddenList/AllItems.aspx. In the list you can find the term and get the Item ID.

In the above screenshot the wssid for the Presentation term is 2

The complete PowerShell below, you can also find in my github

Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.dll"
Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.Taxonomy.dll"

$global:CopiedCount = 0
$username = ""
$password = ""
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)

$destUrl = ""
$destLibrary = "Documents"
$destinationFolder = "/sites//Shared Documents//"
$termName= "MyTerm"
$termGUID = "TERM GUID HERE"
$termWssId = wssid ## wssid of the term, you can find it from hiddentaxonomy list and the ID of the term in that list /Lists/TaxonomyHiddenList/AllItems.aspx
$libFieldColumnName = "ColumnName"


########
function UpdateFileColumns
{
    param($sourceFileCopy, $fListItem)   
        try{
        $modDate = $fListItem["Modified"]
        $modUser = $fListItem["Editor"]
        
        $termValue = New-Object Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValue
        $termValue.Label = $termName #provide the term label here to change
        $termValue.TermGuid = $termGUID # term GUID here
        $termValue.WssId = $termWssId
        $taxField.SetFieldValueByValue($fListItem, $termValue)
        $fListItem["Modified"] = $modDate
        $fListItem["Editor"] = $modUser
        $fListItem.Update()
        $destContext.Load($fListItem)
        $destContext.ExecuteQuery()      
        $global:CopiedCount = $global:CopiedCount +1
        Write-Host "Updated the file. File Count: " $global:CopiedCount -ForegroundColor Cyan       
        }catch{
            $statusRemark = $statusRemark + "Creation error: " + $_.Exception.Message
            Write-Host $statusRemark -ForegroundColor Red
        } 
}

function CreateFolders
{ 
    param (
        [Parameter(Mandatory=$true)] $srcfolder        
        )

    $fileCol = $srcfolder.Files    
    $destContext.Load($fileCol)
    $destContext.ExecuteQuery()
    foreach ($f in $fileCol)
    {                          
        $ListItem = $f.ListItemAllFields                         
        $destContext.Load($f)
        $destContext.Load($ListItem)
        $destContext.ExecuteQuery()
        Write-Host "Updating file : " $f.ServerRelativeUrl                                                 
        UpdateFileColumns $f $ListItem

    } ## end of for each file
    $fL1FolderColl = $srcfolder.Folders
    $destContext.Load($fL1FolderColl);
    $destContext.ExecuteQuery();
    foreach ($myFolder in $fL1FolderColl)
    {
        $destContext.Load($myFolder)
        $destContext.ExecuteQuery()
        CreateFolders $myFolder
    }
} 

$destContext = New-Object Microsoft.SharePoint.Client.ClientContext($destUrl) 
$destContext.Credentials = $credentials
$destContext.RequestTimeout = 1000 * 60 * 10
try
{
    $destWeb = $destContext.Web
    $destList = $destWeb.Lists.GetByTitle($destLibrary)
    $destContext.Load($destWeb)
    $destContext.Load($destList)
    $field = $destList.Fields.GetByInternalNameOrTitle($libFieldColumnName) # column Name here 
    $destContext.Load($field)
    $destContext.ExecuteQuery()
}
catch{
    Write-Host $_.Exception.Message -ForegroundColor Red
    exit
}

$taxField = [Microsoft.SharePoint.Client.ClientContext].GetMethod("CastTo").MakeGenericMethod([Microsoft.SharePoint.Client.Taxonomy.TaxonomyField]).Invoke($destContext, $field)

$folder = $destWeb.GetFolderByServerRelativeUrl($destinationFolder)
$destContext.Load($folder)
$destContext.ExecuteQuery()    
CreateFolders $folder
$destContext.Dispose()
$now=Get-Date -format "dd-MMM-yyyy HH:mm"
Write-Host "Script End : '$($now)'"
##############

Create termset & terms using CSOM PowerShell

CSOM has the rich API to create and manage the Termset and terms within SharePoint. The PowerShell code in the Github uses the sample XML here to create a Termset with hierarchy.

The full PowerShell code below

Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.dll"
Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path ".\CSOM\Microsoft.SharePoint.Client.Taxonomy.dll"

$now=Get-Date -format "dd-MMM-yy,HH:mm:ss"
Write-Host "Script Start : '$($now)'" -ForegroundColor Yellow

$username = "user name"
$password = ""
$srcUrl = "SITE URL"
$xmlFilePath = "C:\Github\msisgreat\ps\ps\sample\CountriesTerm.xml" # change this to xml path with the termset defined

$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)

function CreateTerm($context, $termSet, $label, $lcid, $termXmlData)
{
  $terms = $termSet.Terms
  $context.Load($terms)
  $context.ExecuteQuery()
  $term = $terms | Where-Object {$_.Name -eq $label}
  if($term)
  {
    Write-Host "Term" $label   "already exists." -foregroundcolor Blue
    $termXmlData.Term | ForEach-Object { CreateTerm $context $term $_.Name $lcid $_ }
  }
  elseif($label)
  {
    Write-Host "Creating term " $label -foregroundcolor yellow
    $term = $termSet.CreateTerm($label, $lcid, [System.Guid]::NewGuid())
    try
    {
      $context.ExecuteQuery()
      Write-Host "Term" $label "Created successfully" -foregroundcolor Green
      $termXmlData.Term | ForEach-Object { CreateTerm $context $term $_.Name $lcid $_ }
    }
    catch
    {
      Write-Host "Error while creating Term" $label $_.Exception.Message -foregroundcolor Red
      return
    }
  }
}

function CreateTermSet($context, $group, $termSetXml, $lcid)
{
  $termSets = $group.TermSets
  $context.Load($termSets)
  $context.ExecuteQuery()
  $termSet = $termSets | Where-Object {$_.Name -eq $termSetXml.Name}  

  if($termSet)
  {
  Write-Host "Termset" $termSetXml.Name   "already exists."   -foregroundcolor Blue
  $termSet = $group.TermSets.GetByName($termSetXml.Name)
  $context.Load($termSet)
  $context.ExecuteQuery()
  }
  else
  {
    Write-Host "Creating term set" $termSetXml.Name -foregroundcolor yellow
    $termSet = $group.CreateTermSet($termSetXml.Name, [System.Guid]::NewGuid(), $lcid)
    try
    {
      $context.ExecuteQuery()
      Write-Host "Term set " $termSetXml.Name "Created successfully" -foregroundcolor Green
    }
    catch
    {
      Write-Host "Error while creating Term set" $termSetXml.Name $_.Exception.Message -foregroundcolor Red
      return
    }
  }
  $termSetXml.Term | ForEach-Object { CreateTerm $context $termSet $_.Name $lcid $_ }
}

function CreateTermSet($context, $group, $termSetXml, $lcid)
{
  $termSets = $group.TermSets
  $context.Load($termSets)
  $context.ExecuteQuery()
  $termSet = $termSets | Where-Object {$_.Name -eq $termSetXml.Name}  

  if($termSet)
  {
  Write-Host "Termset" $termSetXml.Name   "already exists."   -foregroundcolor Cyan
  $termSet = $group.TermSets.GetByName($termSetXml.Name)
  $context.Load($termSet)
  $context.ExecuteQuery()
  }
  else
  {
    Write-Host "Creating term set" $termSetXml.Name -foregroundcolor yellow
    $termSet = $group.CreateTermSet($termSetXml.Name, [System.Guid]::NewGuid(), $lcid)
    try
    {
      $context.ExecuteQuery()
      Write-Host "Term set " $termSetXml.Name "Created successfully" -foregroundcolor Green
    }
    catch
    {
      Write-Host "Error while creating Term set" $termSetXml.Name $_.Exception.Message -foregroundcolor Red
      return
    }
  }
  $termSetXml.Term | ForEach-Object { CreateTerm $context $termSet $_.Name $lcid $_ }
}

function Get-TermStoreInfo
 {
   Write-Host "Loading taxonomy session" -foregroundcolor yellow
   $session = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($context)
   $session.UpdateCache();
   $context.Load($session)
   $context.ExecuteQuery()
   Write-Host "Loading term stores" -foregroundcolor yellow
   $termStores = $session.TermStores
   $context.Load($termStores)
   try
   {
     $context.ExecuteQuery()
     $termStore = $termStores[0]
     $context.Load($termStore)
     Write-Host "Term store with the following id is loaded:" $termStore.Id -foregroundcolor Green
   }
   catch
   {
     Write-Host "Error detail while getting term store id" $_.Exception.Message -foregroundcolor Red
     return
   }
   return $termStore
 } 

 function CreateMetadata($context)
{

    Write-Host "Loading the terset xml..." -foregroundcolor Green
    [xml]$xmlContent = (Get-Content $xmlFilePath)
    if (-not $xmlContent)
    {
      Write-Host "Error loading the xml." -foregroundcolor Red
      return
    }
    $termStore = Get-TermStoreInfo $context
    Write-Host "Create Taxonomy group if it is not available" -foregroundcolor yellow
    $sitecollectiontaxonomyGroup = $termStore.GetSiteCollectionGroup($context.Site,$true)
    $context.Load($sitecollectiontaxonomyGroup)
    try
    {
      $context.ExecuteQuery()
      Write-Host "Site collection $url taxonomy group  "$sitecollectiontaxonomyGroup.Name" created or retrived successfully " -foregroundcolor Green
    }
    catch
    {
      Write-Host "Error while creating or getting site collection $url taxonomy group" $_.Exception.Message -foregroundcolor Red
      return
    }

    $xmlContent.TermSets.TermSet |
    ForEach-Object { CreateTermSet $context $sitecollectiontaxonomyGroup $_ $termStore.DefaultLanguage }
} 

### The script starts here to run ####
Write-Host "Authenticating ..." -ForegroundColor White
$context = New-Object Microsoft.SharePoint.Client.ClientContext($srcUrl)
$context.Credentials = $credentials
$web = $context.Web
$site = $context.Site
$context.Load($web)
$context.Load($site)
try {
    $context.ExecuteQuery()
}
catch {
    Write-Host "Error" + $_.Exception.Message -ForegroundColor Red
    exit
}

Write-Host "Connected to the web..." -ForegroundColor Cyan
#Provision Site collection taxonomy group, termset and terms based on SiteCollectionTermsets.xml configuration file
Write-Host "Provisioning Site collection terms started" -foregroundcolor yellow
CreateMetadata ($context)
Write-Host "Provisioning Site collection terms Completed" -foregroundcolor green
$context.dispose()

<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

Sample XML file for input

Output of the PowerShell