If you’ve managed, administered, or developed on SharePoint, chances are at some point you’ve already encountered or resisted working with the User Profile Service (UPS) Application. There is no secret that UPS is one of the more complicated service applications available in SharePoint to configure, but is the effort worth the reward? I’m here to say yes. UPS has a lot to offer (beyond required for My Sites) and this blog will hopefully give you some insight into one use case for UPS that you can relate to. This blog will be a 3-part blog series broken down into the following sections:
- Extending Active Directory with Custom Attributes (the current post)
- Configuring ADFS 3.0 with SharePoint 2013
- Configuring User Profile Services to support Custom Attributes
Let’s dive into the business scenario I was recently faced with and how we used UPS to address the challenge.
Business Case
You’re deploying a SharePoint extranet for the Contoso organization to share, collaborate, and collect information from their vendors and partners. The farm is deployed in Contoso’s perimeter network and by design has been completely partitioned from their internal network. As a result, the farm operates on its own domain. You’ve been asked to support a credentialing process and managing the life cycle around the identities you’re provisioning. In addition to the common attributes, your customer has some custom attributes they want to capture about the user during enrollment. They provide you a list of attributes which you’ve captured in the following format:
Building the Solution
On the Active Directory where your identities will live, you must first install the Active Directory Schema snap-in. It’s fairly simple enough. Open a command prompt in Administrator mode and type the following:
regsvr32 schmmgmt.dll
Running that command enables an option under MMC to add the Active Directory Schema snap-in.
With the snap-in enabled, add it to the console root and select OK.
Once you have the console open, you’ll see two folders: one for Classes and one for Attributes. We could jump right in and create our custom attributes here, but another approach is to create a custom class and associate the attributes to the custom class. This has several management advantages, providing some flexibility on what other auxiliary classes you may associate the attributes with. Below is a high level overview of creating the class and attributes, but for a detailed explanation, read this blog post by Panji Lasi.
Create a Class
Right click on class and select Create Class. You will get a Schema Object Creation warning prompt. The warning informs you that all schema changes are permanent and cannot be deleted. Select Continue.
Fill in the following information and click Next.
- Common Name: EDC-User
- LDAP Display Name: EDC-User
- Unique X500 Object ID: 1.2.840.03041979.1.5.9
Note: Making an OID can be any value so long as it’s unique. I happen to have created the OID above by choosing a family member’s birthday and some other number combinations. For generating an OID for production purposes, you can reference Omar Sinno’s Generate an Object Identifier Script. - Description: EDC Custom User
- Parent Class: <empty>
- Class Type: Auxiliary
On the following screen click Finish.
After following the above steps, you should have a new custom class in your Active Directory Schema.
Create An Attribute
Right click on Attributes and select Create Attribute. You will get a Schema Object Creation warning prompt. The warning informs you that all schema changes are permanent and cannot be deleted. Select Continue.
For each attribute, fill in the following information and click Next. Here is an example for one of our attributes:
- Common Name: EDC-Marital Status
- LDAP Display Name: EDC-Marital Status
- Unique X500 Object ID: 1.2.840.03041979.1.8000.2554.24631.796.50048.20317.37336.10938552.15796381.10.
- Description: Marital Status
- Syntax: Unicode String
- Minimum: <Empty>
- Maximum: <Empty>
Then click OK and your attribute will be created.
Repeat the steps for the following attributes, making sure to select the correct syntax for each.
Note: No IANA registry was entered for the usage of these OID since no integration of LDAP with external parties is anticipated |
Link Attributes and Class
Once your attributes have been created, you will want to associate them with your class. Open your class back up and follow these steps:
Right click EDC-User Class and select Properties.
On the Attributes tab, add the custom attributes you created.
Click Ok.
Once you’ve added the attributes to the custom class, we will associate it with the user class in the Active Directory Schema.
Find the user class. Rich click the user Class and select Properties.
Go to the Auxiliary Classes box and click Add Class.
Select EDC-User and select OK. The result should look like the following:
Click OK.
Updating the Schema
The final step in the process is to update the Schema in ADSI Edit. On the Active Directory server, go to start and type ‘adsiedit.msc.’ That will load the ADSI Edit console.
Rich click ADSI Edit and select Connect To…
It should be default connect to the “Default naming context.” Select OK.
Right click the default naming context and select Update Schema Now.
This will update the schema. Although it takes a few minutes, when you go back into Active Directory, you should be able to see the new attributes there.
Validating Active Directory Attributes
On the Active Directory server, start the Active Directory Users and Computers console to validate the new attributes.
On the top navigation bar, select View and Advanced Features. This will enable the ability to view attributes under user properties.
Select any user and right click the user and select Properties.
Go to the Attribute Editor tab and find your new attributes.
Supporting Script
The following script performs the steps above using PowerShell. Pay close attention to the OIDs being used along with making sure that you’ve mapped the attribute you are creating correctly to the oM and attribute syntax. Look here for a reference to the correct values.
WARNING: This script has not undergone in-depth testing and should be tested thoroughly before applying to a production environment.
Keep an eye out for the next two posts in this three part series:
- Configuring ADFS 3.0 with SharePoint 2013
- Configuring User Profile Services to support Custom Attributes
While you’re here, make yourself comfortable and check out our blog home page to explore other technologies we use on a daily basis and the fixes we’ve solved in our day to day work. To make your life even easier, subscribe to our blog to get instant updates sent straight to your inbox:
{{cta(‘33985992-7ced-4ebd-b7c8-4fcb88ae3da4’)}}
Import-Module ActiveDirectory
$schemaPath = (Get-ADRootDSE).schemaNamingContext $OMSyntaxStringUnicode = ’64’ $attributeSyntaxStringUnicode = ‘2.5.5.12’ $oMSyntaxStringUTCTime = ’23’ $attributeSyntaxStringUTCTime = ‘2.5.5.11’ $oMSyntaxStringGeneralizedTime = ’24’ $attributeSyntaxStringGeneralizedTime = ‘2.5.5.11’ $oMSyntaxBoolean = ‘1’ $attributeSyntaxBoolean = ‘2.5.5.8’ $className = ‘EDC-User’
#Create new custom class to store EDC attribtues $attributes = @{ objectClass = ‘classSchema’; subClassOf = ‘top’; lDAPDisplayName = $className; defaultSecurityDescriptor = ‘D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)’; objectClassCategory = “3”; #Auxillary Class Category adminDisplayName = $className; governsID = ‘1.2.840.3041979.1.5.9’; adminDescription = ‘EDC Custom Attribute Class’; } New-ADObject -Name $className -Type Structural -Path $schemapath -OtherAttributes $attributes -ErrorAction SilentlyContinue Function Update-Schema { [CmdletBinding(SupportsShouldProcess,ConfirmImpact=’High’)] param( [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] $Class, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] $Name, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] $OMSyntax, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] $attributeSyntax, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] [Alias(‘DisplayName’)] $LDAPDisplayName, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] [Alias(‘Description’)] $AdminDescription, [Parameter(Mandatory,ValueFromPipelinebyPropertyName)] [Alias(‘SingleValued’)] $IsSingleValued, [Parameter(ValueFromPipelinebyPropertyName)] [Alias(‘OID’)] $AttributeID )
BEGIN {} PROCESS { $schemaPath = (Get-ADRootDSE).schemaNamingContext $type = ‘attributeSchema’ switch ($isSingleValued) { ‘True’ {$IsSingleValued = $true} ‘False’ {$IsSingleValued = $false} default {$IsSingleValued = $true} } $attributes = @{ lDAPDisplayName = $Name; attributeId = $AttributeID; oMSyntax = $OMSyntax; attributeSyntax = $attributeSyntax; isSingleValued = $IsSingleValued; adminDescription = $AdminDescription; searchflags = 1 } $ConfirmationMessage = “$schemaPath. This cannot be undone” $Caption = ‘Updating Active Directory Schema for: ‘ + $Name if ($PSCmdlet.ShouldProcess($ConfirmationMessage,$Caption)) { New-ADObject -Name $Name -Type $type -Path $schemapath -OtherAttributes $attributes } } END {} } Update-Schema -Class $className -Name EDC-MaritalStatus -OMSyntax $OMSyntaxStringUnicode -attributeSyntax $attributeSyntaxStringUnicode -LDAPDisplayName ‘eDCMaritalStatus’ -AdminDescription ‘Marital Status’ -IsSingleValued $true -AttributeID ‘1.2.840.03041979.1.8000.2554.24631.796.50048.20317.37336.10938552.15796381.10.1’ Update-Schema -Class $className -Name EDC-PartnerId -OMSyntax $OMSyntaxStringUnicode -attributeSyntax $attributeSyntaxStringUnicode -LDAPDisplayName ‘eDCPartnerId’ -AdminDescription ‘Internal Partner Id’ -IsSingleValued $true -AttributeID ‘1.2.840.03041979.1.8000.2554.24631.796.50048.20317.37336.10938552.15796381.10.2’ Update-Schema -Class $className -Name EDC-PartnerSensitive -OMSyntax $oMSyntaxBoolean -attributeSyntax $attributeSyntaxBoolean -LDAPDisplayName ‘eDCPartnerSensitive’ -AdminDescription ‘Parnter Senstive’ -IsSingleValued $true -AttributeID ‘1.2.840.03041979.1.8000.2554.24631.796.50048.20317.37336.10938552.15796381.10.3’ Update-Schema -Class $className -Name EDC-LastProofDate -OMSyntax $oMSyntaxStringGeneralizedTime -attributeSyntax $attributeSyntaxStringGeneralizedTime -LDAPDisplayName ‘eDCLastProofDate’ -AdminDescription ‘Last Proof Check’ -IsSingleValued $true -AttributeID ‘1.2.840.03041979.1.8000.2554.24631.796.50048.20317.37336.10938552.15796381.10.4’
$newEDCClass = Get-ADObject -filter * -SearchBase $schemaPath -Properties * | where Name -like $className $newEDCClass.mayContain.Add(‘EDC-MaritalStatus’) $newEDCClass.mayContain.Add(‘EDC-PartnerId’) $newEDCClass.mayContain.Add(‘EDC-PartnerSensitive’) $newEDCClass.mayContain.Add(‘EDC-LastProofDate’)
Write-Host “DO NOT CLOSE THIS WINDOW” -ForegroundColor Green Write-Host “Waiting 5 minutes for schema changes to commit…” Start-Sleep -Seconds 300
$newEDCClass | Set-ADObject -Add @{mayContain = ‘EDC-MaritalStatus’,’EDC-PartnerId’,’EDC-PartnerSensitive’,’EDC-LastProofDate’}
#Add new EDC class to the user AD object $userSchema = Get-ADObject -filter * -SearchBase $schemaPath -Properties * | where Name -like “user” $userSchema.auxiliaryClass.Add($className) $userSchema | Set-ADObject -Add @{auxiliaryClass = $className} |