Follow me on Twitter @AntonioMaio2

Monday, November 6, 2017

Set a SharePoint Online Managed Metadata (Taxonomy) Field Value on a Document or Item

Just last week I had an interesting little project I was helping a client with where we needed to use PowerShell to set 2 metadata field values for a document in a SharePoint Online Document Library. I've done this before many times. However, the challenge here was that the metadata fields were managed metadata fields, configured as part of a corporate taxonomy using the Managed Metadata Service.

My preferred method to accomplish this would have been SharePoint PnP PowerShell module using Set-PnPTaxonomyFieldValue (reference: https://msdn.microsoft.com/en-us/pnp_powershell/setpnptaxonomyfieldvalue). Unfortunately, for various reasons that wasn't possible in my client's environment so we had to resort to writing the PowerShell script ourselves.

As many of you know, you cannot set managed metadata field values the same way you would a regular metadata field. In searching the web for some guidance on which methods to use, I found that out of the blogs and documentation available, much of it was either incomplete or incorrect. So, with the help of a few kind folks on Twitter, namely Erwin Van Hunen (@erwinvanhunen) and Chris Kent (@thechriskent), I was able to work out a solution. I'd like to share here how that was accomplished so that others might benefit from Erwin's and Chris' assistance and from my experience. I'll try to be as complete as possible here, so that you have a full solution.

An important step is to download and install the latest SharePoint Online Client Components SDK. At the time of publishing, Microsoft had recently released a new version for September 2017, which can be downloaded from here: https://www.microsoft.com/en-ca/download/details.aspx?id=42038. This must be installed on the computer that will be running this script. Now onto our PowerShell code:

First, we'll set some basic variables:
$UserCredentials = Get-Credential
$webUrl = "https://mytenant.sharepoint.com/sites/mySiteCol/mySubsite/"
$listName = "MyList"
$itemToEdit = "/sites/mySiteCol/mySubsite/MyList/MyDocument.docx"
$termGroupName = "My Term Group"
$targetField1Name = "Field 1"
$targetField2Name = "Field 2"
$targetField1Value = "Value 1"
$targetField2Value = "Value 2"

Now, we setup our paths to the SharePoint Online Client Components SDK. Specifically, notice that we are using Microsoft.SharePoint.Client.Taxonomy.dll. These are the default paths where these DLLs should be installed on your computer.
$sCSOMPath = "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI"
$sCSOMRuntimePath=$sCSOMPath +  "\Microsoft.SharePoint.Client.Runtime.dll"
$sCSOMTaxonomyPath=$sCSOMPath +  "\Microsoft.SharePoint.Client.Taxonomy.dll"
$sCSOMPath=$sCSOMPath +  "\Microsoft.SharePoint.Client.dll"
Add-Type -Path $sCSOMPath
Add-Type -Path $sCSOMRuntimePath
Add-Type -Path $sCSOMTaxonomyPath

Next, we create our context and authenticate:
$context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$context.AuthenticationMode = [Microsoft.SharePoint.Client.ClientAuthenticationMode]::Default
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserCredentials.UserName, $UserCredentials.Password)
$context.Credentials = $credentials

Now, we retrieve our managed metadata fields from our Document Library and create our Taxonomy fields:
#get the collection of lists in our site and find our list by name
$lists = $context.web.Lists
$context.Load($lists)
$list = $lists.GetByTitle($listName)

#get our target field objects
$field1 = $list.Fields.GetByInternalNameOrTitle($targetField1Name)
$field2 = $list.Fields.GetByInternalNameOrTitle($targetField2Name)
$context.Load($field1)
$context.Load($field2)
$Context.ExecuteQuery()

$txField1 =[Microsoft.SharePoint.Client.ClientContext].GetMethod("CastTo").MakeGenericMethod([Microsoft.SharePoint.Client.Taxonomy.TaxonomyField]).Invoke($Context, $field1)
$txField2 = [Microsoft.SharePoint.Client.ClientContext].GetMethod("CastTo").MakeGenericMethod([Microsoft.SharePoint.Client.Taxonomy.TaxonomyField]).Invoke($Context, $field2)

Next, we create a session with the Managed Metadata Service and retrieve the terms we wish to set. This allows us to validate that the term values we're trying to set actually do exist in the term store.
$session = $spTaxSession = [Microsoft.SharePoint.Client.Taxonomy.TaxonomySession]::GetTaxonomySession($context)
$session.UpdateCache();
$context.Load($session)

$termStores = $session.TermStores
$context.Load($termStores)
$Context.ExecuteQuery()

$termStore = $TermStores[0]
$context.Load($termStore)
$Context.ExecuteQuery()

$groups = $termStore.Groups
$context.Load($groups)
$Context.ExecuteQuery()

$groupReports = $groups.GetByName($termGroupName)
$context.Load($groupReports)
$context.ExecuteQuery()

$termSetField1 = $groupReports.TermSets.GetByName($targetField1Name)
$termSetField2 = $groupReports.TermSets.GetByName($targetField2Name)
$context.Load($termSetField1)
$context.Load($termSetField2)
$context.ExecuteQuery()

$termsField1 = $termSetField1.GetAllTerms()
$termsField2 = $termSetField2.GetAllTerms()
$context.Load($termsField1)
$context.Load($termsField2)
$context.ExecuteQuery()

foreach($term1 in $termsField1)
{
    if($term1.Name -eq $targetField1Value)
    {
        Write-Host "Found our term in the termset: $($term1.Name) with id: $($term1.id)"
        break
    }
}

foreach($term2 in $termsField2)
{
    if($term2.Name -eq $targetField2Value)
    {
        Write-Host "Found our term in the termset: $($term2.Name) with id: $($term2.id)"
        break
    }
}

if(($term1.Name -ne $targetField1Value) -or ($term2.Name -ne $targetField2Value))
{
    Write-Host "Missing term set values.  Double check that the values you are trying to set exit in the termstore. Exiting."
    exit
}

Finally, find the item we want to edit, check it out (if file checkout is required), update the taxonomy metadata fields and check the document back in:

#get all items in our list
$listItems = $list.GetItems([Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery())
$context.Load($listitems)
$context.ExecuteQuery()  
$itemFound = $false

foreach($item in $listItems)  
{        
    If($($item["FileRef"]) -eq $ItemToEdit)
    {
        Write-Host "Found our item..."
        $itemFound = $true

        $context.Load($item.File) 
        $context.ExecuteQuery();

        #Checkout the item and assign the content type to the document
        if($item.File.CheckOutType -eq "None")
        {
            $item.File.CheckOut();
            Write-Host "Item has been checked out"
        }      

        #create a brand new field and set our Year managed metadata field
        #you cannot simply reuse the term object you found above in the term store
        $txField1value = New-Object Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValue 
        $txField1value.Label = $term1.Name           # the label of your term 
        $txField1value.TermGuid = $term1.Id          # the guid of your term 
        $txField1value.WssId = -1                    # the default value

        $txField1.SetFieldValueByValue($item,$txField1value)

        #create a brand new field and set our Period managed metadata field
        #you cannot simply reuse the term object you found above in the term store
        $txField2value = New-Object Microsoft.SharePoint.Client.Taxonomy.TaxonomyFieldValue 
        $txField2value.Label = $term2.Name           # the label of your term 
        $txField2value.TermGuid = $term2.Id          # the guid of your term 
        $txField2value.WssId = -1                    # the default value

        $txField2.SetFieldValueByValue($item,$txField2value)

        #update the item with all changes
        $item.Update()
        $item.File.CheckIn("Item metadata values have been updated", 1)  

        Write-Host "Item has been checked in with updated metadata values"

        $context.ExecuteQuery();

        break;
    }
}

if($itemFound)
{
    Write-Host "Updating the item's metadata is complete."
}
else
{
    Write-Host "Item not found: $itemToEdit"
}

I'm sure there are ways to make some of this more efficient, and of course the most efficient method of all would be to use the SharePoint PnP PowerShell module using Set-PnPTaxonomyFieldValue (reference: https://msdn.microsoft.com/en-us/pnp_powershell/setpnptaxonomyfieldvalue) if you're environment allows it at the time. However, I wanted to paint a complete picture of what's involved in building such a script if you have to create it from scratch in PowerShell yourself.

Enjoy.
-Antonio

21 comments:

  1. Excellent post.I want to https://awriter.org/essay-writing-services/ thank you for this informative read, I really appreciate sharing this great post. Keep up your work.

    ReplyDelete
  2. I consider these three. Everybody needs a clean private place for living. Presently multi day's I'm chipping away at North region that is close-by you and furthermore I need comparative house for lease that you post here but now you can choose https://legitimate-writing-services.blogspot.com/2018/10/writingessayeastcom-review.html to manage your task. I'm exceptionally upbeat that you present valuable staff.

    ReplyDelete
  3. Its an incredible joy perusing your post.Its brimming with data I am searching for and I want to post a remark that "The substance of your post is marvelous" Great work. Arinda Managed IT

    ReplyDelete
  4. I came onto your blog while focusing just slightly submits. Nice strategy for next, I will be bookmarking at once seize your complete rises... Managed Websites

    ReplyDelete
  5. Whatever paper you are writing, you need a good title for it. With a great title generator https://advanced-writer.com/essay-title you will avoid a problem. Remember that it is better to come up with a creative essay title after the paper is written.

    ReplyDelete
  6. Thank you for sharing great advice! This guys will save your time for sure! This is professionals that will help even the most demanding customer. All those who need to overcome the problem of his homework, recommend you one service. https://www.paraphraseservices.com/article-paraphrase/ you are welcome here! Have a good day and good luck! Have a great day!

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. While I was studying, it was unrealistic to have free time, because the study takes a lot of time. But I found a way out. On the site https://custom-writing.co.uk/write-my-essay you can order the performance of any work. I think some of you will definitely need this.

    ReplyDelete
  9. I really like this essay writing service https://rankmywriter.com/payforessay-net-review because you can find an academic paper writer here. I also love the fact that you can find an assistant to write a dissertation that I really need now.

    ReplyDelete
  10. Hello! I would like to offer to all the users of this web site just to visit the link right here and to read all the detailed information in the web articles: https://www.nursingcapstone.net/writing-nursing-pico-questions-with-the-experts/

    ReplyDelete
  11. Placing an event in the center gives the author the opportunity to assemble a complex system relatively easily: the event acts as a foundation that does not allow it to crumble. Longread can be a complete reconstruction of the event or use it as a kind of basis from which additional plots are then deployed. papernow.org

    ReplyDelete
  12. Our writers can do the work as fast as possible and deliver it exactly on time. It will take a minimum of one to three hours to prepare your essay. The time will depend on the number of pages and difficulty. https://essaywriter.org/

    ReplyDelete
  13. Such articles with online help and step-by-step instructions are quite relevant among students. However, in our time it is quite difficult to contain really reliable information. Therefore, I refer only to verified sources https://essaysbank.com/buy-coursework-writing

    ReplyDelete
  14. Hello everybody . An essay is coming soon and I don't know how to write it correctly and pass it. And after a long search and thinking I found them https://essays-service.com/multiple-choice-questions.html Now I am sure that I will pass the essay well and my parents will buy me a new iPhone. I recommend

    ReplyDelete
  15. Good online gambling casino websites are credible. They even https://casinomaxi.ca/ publish audits of their payouts. With this reliability, more people are interested in joining and playing casino games online.

    ReplyDelete
  16. The second brand of casino gaming comes through Rival Gaming. Opponent Gaming has made and hence appropriated an extraordinary arrangement of games. mpo slot

    ReplyDelete
  17. This comment has been removed by the author.

    ReplyDelete
  18. Looking for a good deal on bulk glitter? Explore a wide range of the best bulk glitter on GlitterMall to find one that suits you! Besides good quality brands, you’ll also find plenty of discounts when you shop for bulk glitter during big sales. Don’t forget one crucial step - filter for items that offer bonus perks like free shipping & free return to make the most of your online shopping experience!

    ReplyDelete
  19. Compound Sulfamethoxazole Injection factory
    Compound Sulfamethoxazole Injection Wholesale Supplier Factory,Bulk Manufacturer

    The main indications of compound sulfamethoxazole injection are the following infections caused by sensitive strains: 1. Urinary tract infections caused by Escherichia coli, Klebsiella, enterobacter, Proteus mirabilis, Proteus vulgaris and Morganella. 2. Acute otitis media in children over 2 years old caused by Streptococcus pneumoniae or Haemophilus influenzae. 3. Acute attack of adult chronic bronchitis caused by Streptococcus pneumoniae or Haemophilus influenzae. 4. Intestinal infection and Shigella infection caused by sensitive strains of Shigella flexneri or sonnei. 5. This strain is the first choice for the treatment of Pneumocystis carinii pneumonia. 6. The prevention of Pneumocystis carinii pneumonia can be used in patients with at least one episode of Pneumocystis carinii or HIV infected adults, whose CD4 lymphocyte count is less than or equal to 200 / mm or less than 20% of the total lymphocyte count. 7. Diarrhea caused by enterotoxigenic Escherichia coli (ETEC).

    ReplyDelete
  20. I really appreciate this wonderful post that you have provided for us. I assure this would be beneficial for most of the people. casino bonus

    ReplyDelete