SharePoint: Profile Sync and the Domain Users group - the Primary Group problem

 

This problem manifests itself in a few different ways:

  • You create an Audience based on "Member Of" the "Domain Users" group. You notice there are only a couple (or maybe even zero) members shown, whereas you may have hundreds or thousands of users in that group.

 

  • You have a SharePoint Add-In (previously known as Apps) that uses OAuth to connect to SharePoint sites and pull data. When the sites are permissioned using the Domain Users group, the Add-In fails with Access Denied, or if it's a Search-based Add-In, the search results are security trimmed.

     

  • Other OAuth / Server-to-Server (S2S) authentication and claims augmentation scenarios like workflows utilizing Workflow Manager and Office Web Apps may fail with Access Denied when you depend on the Domain Users group to provide access to the SharePoint content.

 

This is known as the Primary Group Problem.

All of these issues occur because SharePoint User Profile Synchronization (FIM Sync, AD Import, etc) does not include a users Primary Group within their group memberships.

 

What is this "Primary Group"?

In an Active Directory domain, each user will have a "Primary Group" listed. By default, it's the "Domain Users" group. All users in the domain automatically have membership in this group when they are created.

 

 

Seems like something called "Primary Group" is important. Why doesn't SharePoint Profile Sync include it with a users group memberships?

The Primary Group is different. It is more of an "implicit" group membership. It shows on the users "Member Of" tab in Active Directory, but is not actually listed within their MemberOf attribute. Instead it's stored in the users PrimaryGroupID attribute (in relative ID form). You can see that for yourself using this PowerShell:

#UserInfoFromAD

$userName = "test1"

$account = ([adsisearcher]"samAccountName=$($userName)").FindOne()

"SamAccountName: " + $account.Properties.samaccountname

"DisplayName: " + $account.Properties.displayname

"UPN: " + $account.Properties.userprincipalname

"DN: " + $account.Properties.distinguishedname

"Primary Group ID: " + $account.Properties.primarygroupid

"Group Membership: " + $account.Properties.memberof

 

During Profile Sync, the users MemberOf attribute is used to determine group membership. Since their Primary Group is not listed in MemberOf, it's not included. The result is that the SharePoint User Profile Service Application (UPA) does not think the user is a member of their Primary Group, which in-turn creates the potential for the symptoms listed above.

 

Possible Solutions:

For the Audience issue, it's probably best to just pick some other domain group to use for the audience. One could argue that with audience targeting, using a group that contains all members of an entire domain is not exactly "targeting".

For the other scenarios, the solution is to secure the SharePoint content with something other than the users Primary Group (by default "Domain Users").

You can either change the SharePoint permissions, or change the Primary Group for all users in Active Directory. However, it's unknown which other applications may rely on "Domain Users" being the Primary Group, so that's probably not a great solution.

 

Workaround:

If you're using Domain Users all over the place to give users access to content, and replacing that with some other security group would be a monumental task, then I have a workaround. You can use the below PowerShell script to manually add group membership to "Domain Users" for all of your user profiles within the User Profile Service App.

Caveats:

  • The script assumes you have one User Profile Service App. If you have multiple, it must be adjusted to grab the correct UPA.
  • It assumes you have a single domain. If you import profiles from multiple domains, it would need to be adjusted to only add a Domain Users membership for the domain the user belongs to.
  • While Incremental Imports do not seem to affect it, a Full Profile Import will wipe out and then recalculate all group memberships for all users. In that case, you'll need to run the script again. To be thorough, it's probably best to run the script daily, or certainly after any Full import.
  • Most of the testing I did with this script was using SharePoint 2016 with AD Import. It has not been tested for scalability / performance.

#Title: Add-DomainUsersMembership

#Author: Joroar

#Date: 5/23/18

#This script is provided as-is with no warranties expressed or implied. Use at your own risk.

#Synopsis: Use this to add all user profiles to a group in the User Profile Service App

#Inputs: Just set the top variable: $groupDN

 

$groupDN = "CN=Domain Users,CN=Users,DC=contoso,DC=com" #The Distinguished Name for the AD group

### Change nothing below this line ###

Add-PSSnapin *sharePoint*

$source= "A88B9DCB-5B82-41E4-8A19-17672F307B95" #This is a constant for AD security groups in SP 2013 and 2016. No need to change.

#Get the default UPA from the default proxy group

$profileManager = [Microsoft.Office.Server.UserProfiles.UserProfileManager]([Microsoft.Office.Server.ServerContext]::Default)

#Get the group from the UPA

$DU = $profileManager.GetMemberGroups().GetMemberGroupBySourceAndSourceReference($source, $GroupDN)

#Loop through every user profile and add them to the group

$profiles = $profileManager.GetEnumerator()

foreach($profile in $profiles)

{

try{

Write-host "Adding Domain Users membership for: " $profile.AccountName

$profile.Memberships.Create($DU, "DistributionList", "Domain Users", "Public")

}

catch [system.Exception] {Write-host "Member add fail for: " $profile.AccountName "Probably already a member"}

}

 

Other Tips:

You can use this PowerShell to query the UPA and list out all group memberships that it is currently aware of for the given user:

#List group memberships according to the UPA

$user = "contoso\test1" #specify the user

Add-PSSnapin *sharePoint*

$profileManager = [Microsoft.Office.Server.UserProfiles.UserProfileManager]([Microsoft.Office.Server.ServerContext]::Default)

$up = $profileManager.GetUserProfile($user)

Write-Host "Account: " $up.AccountName

Write-Host "Name: " $up.DisplayName

Write-Host "Groups:"

$groups = $up.Memberships.GetItems()

$groups | select id, title, group | sort title | ft -AutoSize