2

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"

  • You trying to update user profiles via PowerShell, While updating profiles one of the Properties i.e. CustBusinesUnit which is custom and bound to a TermSet - CustBusinesUnit throws an error. Correct me if I am wrong. Also if possible share your code. – Asad Refai Aug 12 '15 at 9:40
  • You might have seen this already but anyway, see if this helps: byteloom.blogspot.in/2012/09/… – Akhoy Aug 12 '15 at 9:43
  • Asad, you are correct. When I try to update 3,500 profiles with PowerShell. About 2,000 success and 1,500 fail. Most of fail cases report for error in title. – Mark L Aug 12 '15 at 9:54
  • 1
    uberz91, thanks I have read this article. It is quite close to my error but all the terms I update is Chinese and no "&" characters. Also, as you see my code, I never try to "create term" directly. All I did is update the userprofile and terms are created in custBusinessUnit automatically. – Mark L Aug 12 '15 at 10:15
  • 1
    @AsadRefai Finally I can reproduce the error! I generate a CSV with 10 records have same CustBusinessUnit value "ABC unit". "ABC unit" is not existing in the termset. Once I run the code, the first user updated successfully but all other users update fail with same error. The term "ABC unit" is created in termset when checking in CA. So I think I need to do some "recalculate" after each user update however I don't know how to. – Mark L Aug 13 '15 at 4:08
1

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" 
    } 

} 
  • After I check the termset exist or not than what should my script do? In either way I have to update the user profile (in same way I believe?) It suppose not a problem to have 10,000 users have same termset value in his profile. – Mark L Aug 13 '15 at 6:12
  • @Mark : You will have to change your approach for updating user profiles. You should have create terms through your code rather than automatically, this will give you more control. – Asad Refai Aug 13 '15 at 6:17
  • In my test, I create a new term with UI and then run my script. All user fail to update. It seems related with the status "IsAvailableforTagging". It seems non-sense to me but I will dig more. Thanks. – Mark L Aug 13 '15 at 6:41
  • @Mark I hope your problem is solved with given suggestions – Asad Refai Aug 18 '15 at 13:23
  • 1
    Thanks for your suggestion. However it is not the true reason for my case. I will write down the fix below. – Mark L Aug 21 '15 at 2:58
1

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.