{"id":1871,"date":"2013-04-19T05:29:11","date_gmt":"2013-04-19T05:29:11","guid":{"rendered":"https:\/\/poiseddevelopers.com\/reality-tech\/?p=1871"},"modified":"2024-05-06T12:24:25","modified_gmt":"2024-05-06T12:24:25","slug":"how-to-fix-bad-taxonomy-terms-in-sharepoint-automatically","status":"publish","type":"post","link":"https:\/\/poiseddevelopers.com\/reality-tech\/fixing-bad-sharepoint-taxonomy-term-references\/","title":{"rendered":"How to Fix Bad Taxonomy Terms in Sharepoint Automatically"},"content":{"rendered":"<h2>Fixing bad SharePoint taxonomy term references<\/h2>\n<p>A given document using managed metadata can have a term orphaned from the termset. This can happen due to bad references to the intermediary site collection cached terms list, which is in each site collection and hidden, under the list name \u201cHiddenTaxonomyList\u201d, here\u2019s how to recreate this URL: [siteurl]\/Lists\/TaxonomyHiddenList\/AllItems.aspx<\/p>\n<p>While it\u2019s easy to extend this to check the health of each document term, for simplicity let\u2019s imagine we want to fix a single document, and have the URL and know the name of the taxonomy field in the\u00a0<a href=\"https:\/\/reality-tech.com\/secure-store-master-key-error\/\" target=\"_blank\" rel=\"noopener\" aria-label=\"microsoft secure store - open in a new tab\" data-uw-rm-ext-link=\"\"><strong>microsoft secure store<\/strong><\/a>. Let\u2019s set the basics before we really get started:<\/p>\n<pre lang=\"php\">$docurl = \"http:\/\/WebApp\/path\/lib\/doc.xlsx\" #URL to correct\r\n$site = New-Object Microsoft.SharePoint.SPSite($docurl)  #grab the SPSite\r\n$web = $site.OpenWeb() #grab the SPWeb\r\n$item = $web.GetListItem($docurl) #grab the SPItem\r\n$targetField = \"MMS Field Name\" # let's establish the name of the field\r\n$TermValueToReplace = $item[$targetField].label;  #this is the termset value we want to re-assign correctly\r\n<\/pre>\n<p>Now let\u2019s get a taxonomy session, with proper error detection:<\/p>\n<pre lang=\"php\">try\r\n{\r\n    Write-Host \"getting Tax Session for $($Site.url)...\" -NoNewline\r\n    $taxonomySession = Get-SPTaxonomySession -Site $site  #get one session per site collection you are in\r\n    $termStore = $taxonomySession.TermStores[0]  #We need to move the  get Termset to above the lib level too!\r\n    Write-Host \"Got Tax Session. \"\r\n}\r\ncatch\r\n{\r\n    Write-Host \"Tax session acquisition problem for $($site.url)\"\r\n    $ok=$false;\r\n}\r\n<\/pre>\n<p>Given the field, let\u2019s get the correct termset.<\/p>\n<pre lang=\"php\">[Microsoft.SharePoint.Taxonomy.TaxonomyField]$taxonomyField = $item.Fields.GetField($targetField)  \r\n$termSetID=$taxonomyField.TermSetId\r\n \r\n$termSet = $termStore.GetTermSet($taxonomyField.TermSetId)  #if we ever loop, move to outside item loop, this takes a long time!\r\n<\/pre>\n<p>Now we do a lookup for the term in the Managed Metadata Service. We expect precisely one match, but we\u2019ll check for that later<\/p>\n<pre lang=\"php\">#\"true\" parameter avoids untaggable terms, like parent term at higher tier that should not be selected\r\n[Microsoft.SharePoint.Taxonomy.TermCollection] $TC = $termSet.GetTerms($TermValueToReplace,$true)  \r\n<\/pre>\n<p>Now let\u2019s populate a TaxonomyFieldValue, and assign it to the SPItem, and save it without changing timestamp or author by using SystemUpdate()<\/p>\n<pre lang=\"php\">$taxonomyFieldValue = new-object Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue($taxonomyField)\r\n$t1=$TC[0]  #use the first result\r\n$taxonomyFieldValue.set_TermGuid($t1.get_Id())  #this assigns the GUID\r\n$taxonomyFieldValue.set_Label($TermValueToReplace)  #this assigns the value\r\n$taxonomyField.SetFieldValue($Item,$taxonomyFieldValue)  #let's assign to the SPItem\r\n$item.systemupdate()\r\n<\/pre>\n<p>That\u2019s the meat of it. Let\u2019s put it all together with error handling:<\/p>\n<pre lang=\"php\">$ok=$true;\r\n$docurl = \"http:\/\/WebApp\/path\/lib\/doc.xlsx\" #URL to correct\r\n \r\n$site = New-Object Microsoft.SharePoint.SPSite($docurl)\r\n$web = $site.OpenWeb()\r\n$item = $web.GetListItem($docurl)\r\n$targetField = \"FieldName\"\r\n$TermValueToReplace = $item[$targetField].label;\r\n \r\ntry\r\n{\r\n    Write-Host \"getting Tax Session for $($Site.url)...\" -NoNewline\r\n    $taxonomySession = Get-SPTaxonomySession -Site $site  #get one session per site collection you are in\r\n    $termStore = $taxonomySession.TermStores[0]  #We need to move the  get Termset to above the lib level too!\r\n    Write-Host \"Got Tax Session. \"\r\n}\r\ncatch\r\n{\r\n    Write-Host \"Tax session acquisition problem for $($site.url)\"\r\n    $ok=$false;\r\n}\r\n \r\n[Microsoft.SharePoint.Taxonomy.TaxonomyField]$taxonomyField = $item.Fields.GetField($targetField)  \r\n$termSetID=$taxonomyField.TermSetId\r\n$termSet = $termStore.GetTermSet($taxonomyField.TermSetId)  #Move to outside item loop, this takes a long time!     \r\n[Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue]$taxonomyFieldValue = New-Object Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue($taxonomyField)  \r\n \r\n[Microsoft.SharePoint.Taxonomy.TermCollection] $TC = $termSet.GetTerms($TermValueToReplace,$true)  #true avoids untaggable terms, like parent company at higher tier\r\n \r\nif ($TC.count -eq 0)\r\n    {\r\n        Write-Host -ForegroundColor DarkRed \"Argh, no Taxonomy entry for term $($TermValueToReplace)\"\r\n         \r\n        $ok=$false;\r\n    }\r\n    else\r\n    {\r\n        if ( $TC.count -gt 1)\r\n        {\r\n            Write-Host -ForegroundColor DarkRed \"Argh, $($TC.count) Taxonomy entries for Claim term $($TermValueToReplace)\"\r\n             \r\n            $ok=false; #we can't be sure we got the right claim!\r\n        }\r\n \r\n        $taxonomyFieldValue = new-object Microsoft.SharePoint.Taxonomy.TaxonomyFieldValue($taxonomyField)\r\n \r\n        $t1=$TC[0]\r\n \r\n \r\n        $taxonomyFieldValue.set_TermGuid($t1.get_Id())\r\n        #$taxonomyFieldValue.ToString()\r\n        #$targetTC.add($taxonomyFieldValue)\r\n    }\r\n \r\ntry\r\n{\r\n    $taxonomyFieldValue.set_Label($TermValueToReplace)\r\n    $taxonomyField.SetFieldValue($Item,$taxonomyFieldValue)  \r\n}\r\ncatch\r\n{\r\n    Write-Host -ForegroundColor DarkRed \"Argh, can't write Tax Field for $($Item.url)\"\r\n    $ok=$false;\r\n}\r\n \r\nif ($ok)\r\n{\r\n    $item.systemupdate()\r\n    write-host \"Fixed term for item\"\r\n}\r\nelse\r\n{\r\n    Write-Host -ForegroundColor DarkRed \"Did not fix term for item\"\r\n}\r\n<\/pre>\n<p>Each TaxonomyFieldValue has three important properties; these appear often as pipe separated values:<br \/>\nLabel : It is the property of the Label selected by the user from the Labels property of the Term object<br \/>\nTermGuid : it is the Id (Guid) property of the Term (inherited from TaxonomyItem)<br \/>\nWssId : Reference back to the TaxonomyHiddenList, actually ID of the list entry in the site collection<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Additional Read<br role=\"presentation\" data-uw-rm-sr=\"\" \/><\/strong><a style=\"color: #1f6799;\" href=\"https:\/\/reality-tech.com\/your-complete-sharepoint-migration-guide-step-by-step\/\" target=\"_blank\" rel=\"noopener\" aria-label=\"Your Complete SharePoint Migration Guide (Step-By-Step) - open in a new tab\" data-uw-rm-ext-link=\"\">Your Complete SharePoint Migration Guide (Step-By-Step)<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fixing bad SharePoint taxonomy term references A given document using managed metadata can have a term orphaned from the termset. This can happen due to bad references to the intermediary site collection cached terms list, which is in each site collection and hidden, under the list name \u201cHiddenTaxonomyList\u201d, here\u2019s how to recreate this URL: [siteurl]\/Lists\/TaxonomyHiddenList\/AllItems.aspx [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":1872,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1871","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"_links":{"self":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/1871","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/comments?post=1871"}],"version-history":[{"count":3,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/1871\/revisions"}],"predecessor-version":[{"id":3547,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/1871\/revisions\/3547"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/media\/1872"}],"wp:attachment":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/media?parent=1871"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/categories?post=1871"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/tags?post=1871"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}