AD Connector Profile Cleanups – The Real Story

When will I learn? After implementing SharePoint 2013 and the AD Connector for Profile Imports, things were going great. Incremental sync times were under 30 minutes, no more SyncDB corruptions, no more hassle with Services not starting, life seemed rosy.

Then I started to get calls about users that had left the company showing up in PeopleSearch. Hmmm, I wonder what’s up? Looking into the issue, when using the AD Connector and selecting the option to Filter Out disabled accounts, it really filters them out. By that I mean the Sync ignores them. Forever. And ever.

“That’s OK”, thought I, as soon as the accounts are deleted from AD, the sync will remove the profile. Right? Right?!?!

Not so fast there, it would appear that while running through test scenarios for the AD Connector and profile syncs, our buddies in Redmond missed one very important scenario. If you disable an account in AD, then delete the account, the incremental profile sync will never remove the profile. The only way to clean those up is to run a full. Kind of a pain, since you can’t schedule a full, but nonetheless, that is the fix. I mean, really, who out there actually disables accounts before they remove them? Ummm, everyone.

So, and here’s the wonky thing, if you just delete an AD account without disabling it, the incremental sync will remove the profile.
If you disable an account in AD, then re-enable the account in AD, then delete the account in AD, and run an incremental sync, the profile will be removed.

It’s only if you disabled an account in AD, then delete the account in AD will the profile never be removed (without a Full).

Thought you might like to know… I sure didn’t.

Update: Microsoft confirmed via a support call that this is indeed broken, and they are not going to fix it. The workaround is to write a PowerShell script to remove the profiles of disabled accounts, or execute a Full Sync each night to clean up the disabled profiles. Or, they said, I could use FIM. Yeah, right….

Host Header Site Collections and SSL

Something I ran into just the other day; say you have a bunch of Host Header Site Collections running in a non-SSL webapp, and someone comes along and asks you to enable SSL on these site collection, as well as keeping non-SSL access functioning (I know, I thought it was a weird request as well).

Here’s the steps I had to go through to get this working:

1. Generate a Subject Alternate Name certificate that contains the DNS names of each of the HHSC you wish to enable SSL on. Install that cert through IIS Admin on each server.

2. Extend your non-SSL webapp to support SSL using the following PowerShell command:

Get-SPWebApplication <WebappURLToExtend> | New-SPWebApplicationExtension -Name "<NewSSLWebAppName>" -Zone "Extranet" -HostHeader "<OriginalWebappName>" -Path "<NewPathforIISFiles>" -Port "443" -url "https://<WebappName>:443" -SecureSocketsLayer

3. Once that is complete, launch IIS Admin on each SharePoint server and edit the binding for the extended webapp, and add the certificate to the extended webapp binding.

4. While in IIS Admin, go ahead and add a https binding to the extended webapp for each HHSC you need SSL access to.

5. On each SharePoint server, copy the web.config file from the non-SSL folder to the new SSL folder (this will ensure that any customizations you made to the webapp will be available in the SSL webapp).

6. Finally, you need to tell SharePoint that the SSL HHSC URLs need to be in the Extranet Zone (where you created the extended webapp). Execute this command for each HHSC you want to access via SSL:

Set-SPSiteUrl (Get-SPSite "http://<HHSCURL>") -Url "https://<HHSCURL>" -Zone Extranet

And that’s about it, your HHSC URLs will be available on port 80 and port 443.

(Now would be a great time for you to contact your load-balancer guys and remind them you have the physical load balancers start listening on port 443 as well as port 80).

SharePoint 2013 AD Connector Import Property Issues

If you’re like me, and you need to import a large number of users and groups into SharePoint, you were ecstatic with the release of SharePoint 2013 and the AD Connector. No more issues with FIM, no crazy start-up issues, no Sync DB issues, finally I get to take a vacation and not worry.

Or so I thought…after testing the AD Connector, it would appear that both the Manager and Assistant property are skipped during a Full Sync. After a week or so of testing, I gave up and called Microsoft for help, and looking at the issue, and reproducing it there, they have explained that this is a bug in the AD Connector. Great. It only happens on a Full Sync, or if a new user is added to AD and imported to the Profile DB. Incrementals do not remove the property data.

So, if you’re using the AD Connector (and you should be), and you’re not seeing Manager or Assistant being populated, fear not, you are not crazy (or maybe you are, it’s not my place to judge).

Is there a fix? Maybe (involves some nutty work with a sproc, jabber jabber jabber). Is there a workaround? Of course.

I wrote this script to run as a scheduled task after the profile sync is complete. It will parse through your profiles, and for each profile where Manager or Assistant are blank, will make a look-up in AD to see if there is supposed to be something there, and add it to the Profile.

If you want to use the script, feel free (At least PowerShell 3.0 please, I’m using the Active Directory snapins, and it kinda expects you to be running it from the E:\Scripts folder, so change up the log file location if needed):

# Description of Function:  This script will compare each profile and determine if the manager and assistant property
#				is missing by checking Active Directory.  If the manager or assistant propery is missing, 
#				but is valid in AD, the profile will be updated with the correct Manager and Assistant.
#				This corrects a known issue in the SharePoint 2013 AD Connector Profile Import
# Version History:  1.0
# Input parameters (if any)
# Creates a function to dispose of all variables that are disposable

function Dispose-All {
	Get-Variable -exclude Runspace | Where-Object {$_.Value -is [System.IDisposable]} | 
		Foreach-Object {$_.Value.Dispose()}
Import-Module Activedirectory

# Load up the SharePoint cmdlets if they are missing
if (!(Get-PsSnapin | Where-Object {$_.Name -match "Microsoft.SharePoint.PowerShell"}))
{Add-PsSnapin Microsoft.SharePoint.PowerShell}

$outputFile = "E:\Scripts\FixNullProperties.txt"
if (test-path $outputFile) {Remove-Item $outputFile -force}

# Grab the Central Admin webapp and connect to the Profile System
$url = Get-SPWebApplication -IncludeCentralAdministration | where {$_.IsAdministrationWebApplication}
$site = Get-SPSite $url.url
$context = Get-SPServiceContext $site
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
$AllProfiles = $ProfileManager.GetEnumerator()

foreach($profile in $AllProfiles){
	Set-Variable profileCommit,adAccount,adManagerAccount,adassistantAccount,Manager,Account,distinguishedName,Assistant -value $null
	$Manager = $profile['Manager'].Value
	$Account = $profile[[Microsoft.Office.Server.UserProfiles.PropertyConstants]::AccountName].Value
	$distinguishedName = $profile['SPS-DistinguishedName'].Value
	$Assistant = $profile['Assistant'].Value

		If((!$Manager) -OR (!$Assistant)){
		$adAccount = (get-aduser -Filter 'distinguishedName -eq $distinguishedName' -Properties Manager,Assistant -ErrorAction SilentlyContinue)
		If($adAccount.Manager -AND (!$Manager)){
			$adManagerAccount = (get-aduser -Filter 'distinguishedName -eq $adAccount.Manager' -ErrorAction SilentlyContinue)
			$adManagerID = ($adManagerAccount | select -expand UserPrincipalName).Split("@")
			$MgrhomeDomain = $adManagerID[1].Split(".")[0]
			$finalMgrData = $MgrhomeDomain + "\" + $adManagerID[0]
			$profile['Manager'].Value = $finalMgrData
			If($MgrhomeDomain){$profileCommit = "1"}
			Add-Content $outputFile "Added Manager $finalMgrData to Profile $Account"
		If($adAccount.Assistant -AND (!$Assistant)){
			$adAssistantAccount = (get-aduser -Filter 'distinguishedName -eq $adAccount.Assistant' -ErrorAction SilentlyContinue)
			$adAssistantID = ($adAssistantAccount | select -expand UserPrincipalName).Split("@")
			$assistantHomeDomain = $adAssistantID[1].Split(".")[0]
			$finalAssistantData = $assistantHomeDomain + "\" + $adAssistantID[0]
			$profile['Assistant'].Value = $finalAssistantData
			If($assistantHomeDomain){$profileCommit = "1"}
			Add-Content $outputFile "Added Assistant $finalAssistantData to Profile $Account"

When is a BDC not a BDC?

After standing up my SharePoint 2013 farm, I thought “Awesome!, time to try connecting some of the 2013 Service Apps to my 2010 Farm”. It’s fully supported, right? I spun up the trust between the farms, and began connecting the 2013 Service Apps to my 2010 farm. After each one was connected, I dropped the 2010 Service App.

Everything seemed to be working, but then an issue with the BDC surfaced. It appears that you cannot create a new BDC model, or edit an existing one, if your content is still on 2010. I asked Microsoft about this, seems to be a “Working as designed” kind of thing. You can consume existing BDC models from the 2010 farm, just not change or create new ones in Designer. So, like me, if you brought your 2010 BDC database over and used it to create the 2013 BDC Service App, it’ll work, but no editing.

So, if you’re out there trying this like I did, and the BDC isn’t working, you’re not crazy (well, you might be crazy, but not about the BDC). No word if this will be fixed, or even if Microsoft believes it’s broken. Guess you’ll have to keep that 2010 BDC service around until you migrate your content to 2013.

(And please, let’s not have the BCS vs BDC argument…)

UPDATE: Microsoft may or may not have confirmed that this is working as designed. I have been told that the new 2013 BDC uses oAuth to communicate while created External Content Types. Guess they didn’t think of 2010 farms consuming the 2013 BDC. Soooo, it won’t work.