So here is a scenario. You have two domains (or more), you are trying to go through a domain consolidation onto one domain. So you have multiple user domains, an another (main) domain with enabled or disabled user accounts (stub accounts) that correspond to the users out in the user domains. Your Sharepoint 2010 environment exists in this “main” domain also. because of this scenario you configured SharePoint to use ADFS claims only (no windows authentication for users)


Domain1 – main domain, contains stub accounts and the SharePoint 2010 environment.

Domain2 – legacy user domains, contains user accounts actually used by the end users.

SharePoint 2010 – setup to use only ADFS claims for user authentication. (No windows auth for users)

It works, however after we had implemented it we found the following article.

Toward the bottom is a list of things that don’t work, or have limited functionality with SAML authentication (ADFS claims) in SharePoint 2010. A few examples are below.

  • Search Alerts
  • SharePoint Server 2010 Explorer View
  • Claims to Windows Token Service (C2WTS) – Not sure if this is just a statement that the service can’t run under a claims identity or that it just can’t do it’s job with SAML claims in use.
  • InfoPath Forms Services
  • Search crawling – does work you just have to extend every web application that uses ADFS claims, and set the extension to use NTLM claims. the crawler doesn’t support using trusted identity providers.
  • Audiences – can only work with user profile properties. No ad group based audiences.
  • mail enabled lists/libraries – they work however you must set any lists/libraries to accept mail from all users. It can’t security filter with ADFS claims. Also email that received by a list/library will get stamped with the metadata of the windows claims identity of the sending user, not the ADFS claim identity. So metadata in mail enabled lists/libraries may not match up with the profiles in the user profile service.
  • Secure store service – When you are using the Secure Store Service, SAML claims are not translated to Windows tokens, so other services will not detect the SAML identity; the identity will be the service account, an anonymous account, or an unattended account.
  • Information rights management – also works but requires a hotfox and some extra effort to make with with SAML claims.
We also had problems with a number of 3rd party applications and web parts that either needed to authenticate to SharePoint or that had to pass through the authentication from SharePoint. 

Because of these limitations, and some others annoyances we started investigating switching authentication methods for the impacted web applications. Amazingly enough this wasn’t as bad as I thought. thanks to the Move-SPUser cmdlet.

DISCLAIMER: I’ve run through this in our test environment and everything worked pretty well. I still don’t know how to preserve the user profiles since i’ll have to redo the UPS sync connection. ALWAYS run things like this in a separate test/dev environment to make sure they work for you before running in a production environment. The risk with making a bulk change like this is pretty high since it could break all permissions in the environment. Also take content database backups before running this. (Just in case). 🙂

I was able to come up with the following script. (note the comment at the begining of the script about granting rights to the UPS application. That step is important if you want to update the user profile when the move-spuser is run!)
#Converts all users identities to windows claims
#Pre-tasks: Grant the account, you are running this script as, full control rights in both the
#administrators list and the permissions list for the User Profile Service Application.

#Test site
$allwebs = get-SPSite -WebApplication -Limit ALL | get-SPweb -Limit ALL

$claimprefix = "i:0#.w|"

foreach ($web in $allwebs) {
	foreach ($user in $web.AllUsers) {
		#exclution list: superreader, superwriter, all authenticated users context, etc (add your exclusions as needed.)
		If ($user.UserLogin -Notlike "$claimprefix*" -and $user.Email -ne "" -and $user.UserLogin -ne "SHAREPOINT\system" -and $user.UserLogin -ne "NT AUTHORITY\LOCAL SERVICE" -and $user.UserLogin -ne "NT AUTHORITY\NETWORK SERVICE" -and $user.UserLogin -ne "c:0(.s|true") {
			#find user in domain
			##Save AD user info
            $OlduserID = $null ##added to clear last result
			$OlduserID = Get-ADUser -Filter {mail -like $user.Email} -Properties mail,msDS-SourceObjectDN

			$sourceDN = $null ##added to clear last result
			$sourceDN = $OlduserID | select msDS-SourceObjectDN

			#domain2. use their OU name to determine their home domain
			If ($sourceDN -match "DC=domain2,DC=net") {
				$domain = "domain2\"
				#create windows identity based on domain\username
				$newuserID = $null
				$NewuserID = $claimprefix + $domain + $OlduserID.samaccountname.ToString()

				Move-SPUser -Identity $user -NewAlias $NewuserID -Confirm:$false -IgnoreSID
				Write-Host "Moving:" $user.UserLogin "to" $NewuserID "on subweb" $web.URL

			#domain3. use their OU name to determine their home domain - add domains as needed
			If ($sourceDN -match "DC=domain3,DC=com") {
				$domain = "domain3\"
				#create windows identity based on domain\username
				$newuserID = $null
				$NewuserID = $claimprefix + $domain + $OlduserID.samaccountname.ToString()

				Move-SPUser -Identity $user -NewAlias $NewuserID -Confirm:$false -IgnoreSID
				Write-Host "Moving:" $user.UserLogin "to" $NewuserID "on subweb" $web.URL
Essentially this script gets all subweb objects in a web application and cycles through them. For ever user in every subweb, it will lookup the user’s AD object based on their mail attribute (also stored in SharePoint), and returns their msDS-SourceObjectDN and attributes. The msDS-SourceObjectDN attribute can be used to determine the users home domain which is done in the two IF statements. If the msDS-SourceObjectDN matches the IF statement condition it will change the users identity in SharePoint. The new identites are built off the samaccountname from the get-aduser command.

There are a few things that you will need to change in the script. Most noticeably are the domain names, and the $sourceDN comparisons in the IF statements. Also duplicate the IF statements for each domain that you have users in. You will also want to add all service accounts used with SharePoint to the exclusion statement and any others you deem necessary. (You really only need to add the superreader, super writer, and crawl service accounts to the exclusion list, but I though it would be good to add all managed accounts to be safe.

Before or after running the script (I did this before) change the authentication for the web application to NTLM or kerberos claims, (disabling the ADFS provider).

The script may take a long time to run depending on the size of your environment so i’d recommend running this after hours on a weekend. Also in our scenario we were trying to work toward consolidating domains, so we will likely have to do this kind of process for every-time we collapse a user domain into domain1.

I also felt it prudent to write a reversal script. The resversal script undoes the identity change only, it will basically do the same thing as the ADFS to windows script. It just changes back to an ADFS claim ID (which is WAY easier). Both scripts are linked below.


Migrate to Windows authentication

Migrate to ADFS authentication

UPDATE: I forgot to mention that if you have SIDhistory set in your stub account domain (domain1 in the example) then the people picker will have all kinds of problems with Windows authentication. (so will Exchange 2010 and granting access to shared mailboxes). I’d recommend this post. It explains the issue with SIDhistory very well. You can get around the SIDHistory issue by not using the people picker and just typing in users in the format domain2\username and then clicking the resolve button. Although I don’t think thats a realistic option.

Update 2012-4-16: we ran this in in production. It seems to have worked pretty well. I’ve updated the script though because of some bad programming on my part. Apparently it’s important to null out your variables if they are going to be reused in a for loop. 🙂 Needless to say there were some issues, but happily not as many as there could have been. I’ll updating the script to reflect these additions. I think I also need to add some logic to detect if the get-ADuser returns nothing exit the if statement. I’ll update the script once I get it figured out.