Question

I am using SP2013 on-premise standard edition and we tried to update the user profile with a PowerShell script. Unfortately, part of profiles cannot be updated. The exception is "There is already a term with the same default label and parent term".

The update field is a custom field named CustBusinesUnit (String - single value). The field is bind to a custom termset CustBusinesUnit. The field's value is not coming from AD sync. The value is updated by PowerShell half year ago. It was updated successfully. However, when we update again today exception is threw.

I have no idea what the error message mean and how to get around it. Is it means the new value is same as old value? The PowerShell read a CSV in UTF8 format. Most of the content are in Chinese.

I tried to reproduce in a test environment but not success reproduce. In my test environment, if I update 'CustBusinesUnit' field with a value not exist in 'CustBusinesUnit' termset, it will auto create a new term. Otherwise, it will auto match 'CustBusinesUnit' field with the existing term in 'CustBusinesUnit' termset. Whatever I tried the update go smooth. It never return exception. The problem only exist in production environment and the titled error is the only hint.

I understand it is a rare case. Any brainstorming is welcome. Thanks.

Here is part of PowerShell (it may contains syntax error because I cut off some sensitive information):

$userDetails = Import-Csv -Path $csv
$upProperties = "SPS-PhoneticDisplayName","StaffID","Title","CustCompany","CustBusinessUnit","Manager","Assistant","SPS-Location","WorkPhone","CellPhone","CustDepartment"

foreach ($user in $userDetails){
    if ($upm.UserExists($user.AccountName))
    {  
        try {
             $profileproperty = $upm.GetUserProfile($user.AccountName)
             $upProperties | foreach-object {
                 if ($user.$_ -ne $null) {                   
                    if ($profileproperty[$_].Value -eq $user.$_  -or ($profileproperty[$_].Value -eq $null -and $user.$_ -eq '')) {
                            # don't update
                     } else { 
                        $profileproperty[$_].Value = $user.$_
                         $profileproperty.Commit()
                    }
                 }
             }
        } catch [System.Exception]{
        $ErrorMessage = $_.Exception.Message
        # log down the message somewhere.
          }
}

Addition information: I found some of the terms in CustBusinessUnit are being marked as "reuse term". I tested in my test farm and cannot reproduce error due to "reuse term"

Was it helpful?

Solution 2

After many tests, finally I can reproduce the error "There is already a term with the same default label and parent term"

In my custom termset 'CustBusinesUnit', the "IsAvailableforTagging" is unchecked. It means:

  1. User profile cannot REUSE the existing terms in the termset
  2. User profile can ADD NEW terms in the termset and use it as the profile value

When my script trying to update user profile with a value EQUAL TO existing terms in the termset 'CustBusinessUnit', the error is threw.

The solution is simply check the "IsAvailableforTagging". We can do it in Term store manager interface or update with PowerShell. Here is part of my code:

$termSet = $termGroup.termSets["CustBusinessUnit"]
if ($termSet -ne $null) {
                if (!$termSet.IsAvailableForTagging) {
                    $termSet.IsAvailableForTagging = $true
                    $termStore.CommitAll()                
                }

Thanks for all the comments esp Asad =D

OTHER TIPS

Since you are passing values from csv file and all the users are getting updated in a loop. I can think of a below possible way to trace the problem and a possibility to crack a problem.

Trace the problem: It might be possible that, for 2 users you are saving same value in CustBusinessUnit. So in first iteration of loop, while you update the user profile, the term got created successfully. But in next iteration it failed as you already have a term with same Default Label from the previous iteration.

Solution: Before you update a user profile, you can make a check into Term Set whether a term exists or not. As in a loop you certainly receive Terms from a csv.

Go through below code, it has slightly different approach than yours'. I am having a csv file which contains the Properties and Values defined.

Code to update user profiles iterate through csv lines. But before actually updating a profile we call a function to create a term which has a check if it already exists or not.

Note: You may need to make some changes to suit your requirement.

My Sample CSV:

user,SPS-Responsibility,CustBusinessUnit
domain\asad,SharePoint,Europe
domain\mark,PowerShell,China

Sample Code:

Add-PSSnapin Microsoft.Sharepoint.Powershell -ErrorAction SilentlyContinue
[reflection.assembly]::LoadWithPartialName("Microsoft.SharePoint") | out-null
[reflection.assembly]::LoadWithPartialName("Microsoft.Office.Server") | out-null
[reflection.assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles") | out-null


function CreateTerm([Parameter(Mandatory=$true)][string]$term)
{
    #Connect to the Metadata Service with central admin url
    $taxSite = get-SPSite "http://Prod.YourSite.com"
    $taxonomySession = Get-SPTaxonomySession -site $taxSite
    $termStore = $taxonomySession.TermStores["Managed Metadata Service"]

    #Check if Group already exists
    if($termStore.Groups["MyGroup"] -eq $null)
    {
        $termStoreGroup = $termStore.CreateGroup("MyGroup")
        $termStoreGroup.Description = "My Termstore"
        $termStoreGroup.AddGroupManager("domain\user")
        $termStoreGroup.AddContributor("domain\user")
    }
    else
    {
        $termStoreGroup = $termStore.Groups["MyGroup"]
        write-host "Group exists already"
    }
    if($termStoreGroup.TermSets["MyTermSet"] -eq $null)
    {
        $termSet = $termStoreGroup.CreateTermSet("MyTermSet")
    }
    else
    {
        $termSet = $termStoreGroup.TermSets["MyTermSet"]
        write-host "TermSet exists already"
    }

    #Create the Terms out of this list
    $termsList = "Value1"
    $termsArray = $termsList.Split(";")

    foreach($termAdd in $termsArray)
    {
        #Create Term
        if($termSet.Terms[$termAdd] -eq $null)
        {
            $term = $termSet.CreateTerm($termAdd, 1033)
            #$term.SetDescription(“This is a test”, 1033)
            #$term.CreateLabel(“This is a test synonym”, 1033, $false)
            write-host "Term $termAdd was added"
            return $true
        }
        else
        {
            write-host "Term $termAdd was already added"
            return $false
        }
    }
    #Update the Term Store
    $termStore.CommitAll()
}


$mySiteUrl = "http://Prod.YourSite.com" 
$upAttribute = "SPS-Responsibility" 
$site = Get-SPSite $mySiteUrl 
$context = Get-SPServiceContext $site 
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context) 
$csvData = Import-Csv "C:\Users\Asad\Desktop\up.csv" 
foreach ($line in $csvData)
{ 
    CreateTerm($line.CustBusinessUnit)
    if ($profileManager.UserExists($line.user)) 
        { 
            $up = $profileManager.GetUserProfile($line.user) 
            $up['SPS-Responsibility'].Value = $line.'SPS-Responsibility' 
            $up.Commit() 
        } 
    else 
    { 
        write-host $line.username " profile not found" 
    } 

} 
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top