SharePoint: Profile Sync with MIM – Managers and Group memberships are not updated

Update 6/9/19: It was found that the name of the membership processing timer job changed between SP 2016 and SP 2019, so the PowerShell to find it was updated.

 

I want to thank my colleague Dhiren for doing most of the leg work to figure this one out.

Spoiler alert: Turns out it has the same root cause as this issue: https://joshroark.com/sharepoint-2016-active-directory-import-timer-job-does-not-run-allowservicejobs/

 

Consider the following scenario:

In the User Profile Service Application (UPA), you configure SharePoint 2013, 2016, or 2019 to use an “External Identity Manager”.

You use Microsoft Identity Manager (MIM) to synchronize user profiles from Active Directory (AD) into SharePoint (SP).

You configure your AD and SP management agents and run a Full Sync.

You see that user profiles are successfully imported, but you also notice some of the following problems:

  • Manager to direct report relationships are not updated. They may remain stale (show the “old” manager), or not show a manager at all.
  • Audiences that utilize a “member of” rule become stale (new users added to the group are not reflected in the audience).
  • When trying to create a new “member of” audience, the Active Directory group cannot be found.
  • OAuth / Server-to-Server (S2S) authentication and claims augmentation scenarios like Workflows utilizing Workflow Manager and Office Web Apps may fail with 401 – Unauthorized (Access Denied) when you depend on AD groups to provide access to SharePoint content.

 

So… users were imported, why not groups?

Group memberships and manager references are a little trickier because they are not really imported objects. Instead, they are relationships between two objects. Both managers and groups are imported during the initial Sync. However, the relationships between them are built during the post-import processing task. This post-import processing is done by a timer job. In this scenario, the timer job has never run because none of the servers in the farm have the AllowServiceJobs flag set. Therefore, there are no servers in the farm that can run the job. Exactly which timer job is used for the post-import processing depends on your build number, as detailed below.

 

SharePoint 2016

Pre – Feb 2017 PU (build < 16.0.4498.1002) = “User Profile ActiveDirectory Import Job” (UserProfileADImportJob).

You’ll need to use the NoILMUsed workaround to get this to work. Reference: https://thesharepointfarm.com/2016/04/sharepoint-server-2016-audiences-mim/

Run this PowerShell to check on the timer job:

Get-SPTimerJob | ? {$_.displayname -match “ActiveDirectory”}

If the “NoILMUsed” flag is set, but it looks like the timer job has never ran, move on to the “Solution” section below.

 

Post – Feb 2017 PU (build >= 16.0.4498.1002) = “Updates Profile Memberships and Relationships Job” (ExternalIdentityManagerMembershipsAndRelationshipsJob)

Run this PowerShell to check on the timer job:

Get-SPTimerJob | ? {$_.displayname -match “memberships”} | fl

 

If it doesn’t return any timer job at all, it may not have been created yet. Reference: https://thesharepointfarm.com/2017/02/microsoft-identity-manager-noilmused-bug-fixed/

You can provision the timer job like this:

$sa = Get-SPServiceApplication | ?{$_.TypeName -match “Profile”}

$sa.Provision()

 

If your farm shows the “Updates Profile Memberships and Relationships Job” timer job exists, but has never ran, move on to the “Solution” section below.

 

SharePoint 2019:

“Updates Profile Memberships and Relationships Job” (UpdateMembershipsAndRelationships)

See “Post – Feb 2017 PU” section above.

Note: in SharePoint 2019, the “name” of the timer job has changed slightly, but the “displayName” is the same, so the same PowerShell should find it:

Get-SPTimerJob | ? {$_.displayname -match “memberships”} | fl

 

Solution:

Run the following PowerShell script to make sure all timer instances are online, and that at least one of your User Profile servers is set to “AllowServiceJobs”:

 

#This will check to make sure there is at least one User Profile Service instance in the farm,

#and that the AllowServiceJobs property is set to true for the timer instance on those server(s)

Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue

#Check the timer instances. They should all be online:

$Farm = Get-SPFarm

$FarmTimers = $Farm.TimerService.Instances

foreach ($FT in $FarmTimers){write-host “Server: ” $FT.Server.Name.ToString(); write-host “Status: ” $FT.status; write-host “Allow Service Jobs: ” $FT.AllowServiceJobs; write-host “Allow Content DB Jobs: ” $FT.AllowContentDatabaseJobs;”`n”}

$disabledTimers = $farm.TimerService.Instances | where {$_.Status -ne “Online”}

if ($disabledTimers -ne $null)

{foreach ($timer in $disabledTimers)

{Write-Host -ForegroundColor Red “Timer service instance on server ” $timer.Server.Name ” is NOT Online. Current status:” $timer.Status

Write-Host -ForegroundColor Green “Attempting to set the status of the service instance to online…”

$timer.Status = [Microsoft.SharePoint.Administration.SPObjectStatus]::Online

$timer.Update()

write-host -ForegroundColor Red “You MUST now go restart the SharePoint timer service on server ” $timer.Server.Name}}

else{Write-Host -ForegroundColor Green “All Timer Service Instances in the farm are online. Moving on to checking AllowServiceJobs…”}

#Make sure AllowServiceJobs is set on servers running the User Profile Service:

$SIs = Get-SPServiceInstance | ?{$_.typename -match “profile service”}

$1onLine = $false

foreach ($SI in $SIs)

{If($SI.Status -eq “Online”)

{$1onLine = $true

foreach ($FT in $FarmTimers)

{if($SI.Server.Address.ToString() -eq $FT.Server.Name.ToString())

{if($FT.AllowServiceJobs -eq $false)

{write-host -ForegroundColor Red “Service jobs are NOT enabled on User Profile server” $FT.Server.Name.ToString()

write-host -ForegroundColor green “Enabling service jobs on server: ” $FT.Server.Name.ToString()

$FT.AllowServiceJobs = $true

$FT.Update()}

else{write-host -ForegroundColor green “Service Jobs already enabled on server: ” $FT.Server.Name.ToString()}

}}}}

If($1onLine -eq $false ){write-host -ForegroundColor red “No instances of User Profile Service online in this farm!”}

 

Note: The above script is a combination of scripts from two of my other blog posts:

https://joshroark.com/sharepoint-all-about-one-time-timer-jobs/

https://joshroark.com/sharepoint-2016-active-directory-import-timer-job-does-not-run-allowservicejobs/

 

 

That didn’t do it?

There are a number of reasons why group memberships and manager relationships might not be updated. You should go back and doublecheck for the common issues. Ideally, you would do that first, but I didn’t want that to get in the way of explaining the specific issue noted above.

Make sure that the AD containers that store the users, their managers, and any group that you want to use for audiences are selected within the Sync connection (or AD Management Agent in this case). If you make any changes to container selection, you’ll need to run a Full Sync for it to take effect.

Since the post-import processing job processes both manager relationships and group memberships, and it’s done in the same way (minus the timer job that manages it) whether you’re using AD Import or an External Identity Manager (MIM), much of an earlier blog post I wrote is applicable here as well.