Friday, March 27, 2015

Deleted User Profile - How to Relink MySite (SharePoint 2010)

I've had a very interesting case on a SharePoint 2010 environment. A user's account was deleted accidentally by their internal AD team on Friday the 13th :) The account got recreated, but when the user tried to open MySite, they got "Access Denied" when clicking on "Contents".

I've made sure the user is the Site Collection Admin, checked every possible permission level and even re-added it just in case. No luck.

With the Farm Admin account, I was able to see the Contents of this user at all times.

I've come up with the following approach after a few hours of IIS / ULS logs reading that were simply showing 401 when this particular user tried to access their own MySite.

- Deleted the MySite (ensured we've got a fresh backup).
- The user then recreated a blank MySite.
- I've restored the backup with the Restore-SPSite command.

At this stage, I was able to see the contents with the Farm Admin account again, but when the user tried, he got the following error:

The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.

And the respective ULS log entry:

The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.
 at Microsoft.SharePoint.SPGlobal.HandleThrottleException(COMException comEx)    
 at Microsoft.SharePoint.Library.SPRequest.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)    
 at Microsoft.SharePoint.SPWeb.GetSiteData(SPSiteDataQuery query)    
 at Microsoft.SharePoint.WebPartPages.AggregationWebPart.RunQuery(SPSiteDataQuery query)    
 at Microsoft.SharePoint.WebPartPages.UserDocsWebPart.GetEligibleItems()    
 at Microsoft.SharePoint.WebPartPages.AggregationWebPart.RenderWebPart(HtmlTextWriter writer) Inner Exception: The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator.  
 at Microsoft.SharePoint.Library.SPRequestInternalClass.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)    
 at Microsoft.SharePoint.Library.SPRequest.CrossListQuery(String bstrUrl, String bstrXmlWebs, String bstrXmlLists, String bstrXmlQuery, ISP2DSafeArrayWriter pCallback, Object& pvarColumns)

Now... the list view treshold was set to 5000 for non-admins (default) and 20 000 for admins (again default). I've lifted it to 20 000 for non-admin users as well, just to find out it doesn't matter. No luck.

I've even decided to make the user a Farm Admin for a minute... again nothing changes.
Whenever he tried to access any of the libraries in "My Site", Unexpected error. The webpart "SharePoint Documents" still saying the stupid message about the List View Tresohld.

Maybe I should have mentioned that there are nowhere near 5000 items in that user's MySite in total.

So... next steps.

- Deleted the User Profile from SharePoint.
- Issued an Incremental Sync to import it - it didn't import.
- Issued a Full Sync - not imported again.
- Recreated the User Profile in SharePoint manually with all the properties

And still at the same stage...

Finally... I've decided to use the Export/Import instead of Backup and Restore and I did not use the -IncludeUserSecurity on purpose... as I am thinking that the old account is still referred to somewhere in the site permissions and that's causing all the headaches. Boom! All working fine now after the Import.

The only downside would be that the "SharePoint Documents" webpart which is the default one visible when you go to "Contents" under MySite will be showing no documents... as when I've used the Export method with the Farm Admin account now all documents show as modified by this account. Anyway once the user edits (or just check-out / check-in) a few documents, this webpart populates again and there's finally nothing more to worry about. Just be careful when deleting AD accounts :)

Monday, March 16, 2015

Yammer DirSync filtering by OU

This post might not be as helpful now as it would have been a year ago due to this improvement. Now Yammer DirSync could be used by organizations requiring Yammer SSO, previously it was used by each organization wanting to sync users from on-premise Active Directory to the Yammer network. More info on how to implement Yammer SSO, which is a different scenario can be found here.

I won't be trying to reinvent the wheel in this post, as there are plenty of good information sources on the Yammer DirSync implementation itself, like this one, but I'd rather share the limitations and issues I've faced when I had to meet a requirement to implement sophisticated filtering for the synchronization process.

The requirement seemed quite simple at a first sight - the customer wanted to synchronize users only from 5 specific OUs in their on-premise Active Directory domain.

Yammer DirSync (as well as the SharePoint User Profile Service) synchronization allows the use of LDAP queries. If you're new to those, you can read more about their syntax here.

The bad thing is, you have no option to query for a specific OU - and hence - no visible option to meet this requirement. The good thing is, there is a more advanced option to do this - partly a configuration cheat and partly modifications in the globalsettings.config.json file. 

The first part consists of adding more than one directory source, but if the OUs that you'd like to sync are in only one domain as in our scenario, you have two options:

- Sync from different domain controllers, add each one by hostname (better approach, straight forward)

You can't use a load-balanced name if you have created one (as per the installation guide).
- Sync from the same domain controller if you only have one (very rarely these days) or the requirement is to sync from one

In our scenario we needed to only sync from one DC, and the issue here arises from the fact that you can't add the same hostname in the configuration screen twice. It'll just tell you it already exists in the configuration.

The only ways to add the same DC again are to use the FQDN or the IP address in addition ot the NETBIOS hostname. Later on you can change that in the config files, but you have to go through the wizard first.

The configuration files you need then are stored in C:\ProgramData\Yammer\DirSync by default.

To locate the globalsettings.config.json file on your Yammer DirSync server, you need to go to the Yammer icon in the notifications tray and then click "About":

Then on the new pop-up window that you'll get, click on "Advanced Configuration":

Once you have the file open, you can implement some LDAP filters on each synchronization connection (I had to do this due to more specific requirements), but you still can't get the OU in the picture. The only way to do it is to use the "OverrideRootNamingContext" parameter which tells the sync tool which is the "root" container in the domain. So in our example, on each of the 5 synchronization connections that were created, we had to add the respective parameters. Let's say our domain name is contoso.local and we only want to sync users from the Test OU. We insert this in the first synchronization connection, and replace "Test" with the other OUs that we'd like to sync in the rest of the synchronization connections.

·   "OverrideRootNamingContext": "OU=Test,DC=contoso,DC=local”,

Friday, March 13, 2015

Cross-Farm Service Application Publishing

To start the process of cross farm service application publishing in SharePoint 2013, first look at the post about establishing STS trust between farms. You also need to have the farm IDs of the farms that are going to consume the service applications in hand.
So, let's assume the STS trust is established, now the steps to publish and then consume the services are:
1. On the source farm, go to Central Admin -> Application Management -> Manage service applications, select the one you want to publish (in this example Search) and click Publish from the top ribbon.
You could also achieve this with PowerShell:
Publish-SPServiceApplication -Identity <ServiceApplicationGUID>

If you do not know the GUID of the service application, you can use the following Windows PowerShell 3.0 cmdlet to list all service applications in the farm, together with their GUIDS:
2. Select the "Publish this Service Application to other farms" option. I recommend using https connection. 
Take a note of the Published URL and save it.
3. Grant permissions to the consuming farms on the source service application by using the consuming farm IDs. 
4. Now, go to the consuming farm(s) Central Admin -> Application Management -> Manage service applicatoins and click Connect. Now insert the address that you've saved in Step 2. The server hostname in the example screenshot is removed on purpose.
5. Now choose the service application that will be provided as a choice to you. In our example - Search Service.
Leave the option “Add this service application’s proxy to the farm’s default proxy list” ticked and click OK.
6. On the next screen, you can choose a name of the service application. Finally you'll get a confirmation that you've connected successfully.

If you're consuming remote Managed Metadata Service, there is an additional setting to be set that will prevent errors when trying to update some of the user profile properties through MySites:
Select this one as well (not related to the issue above), but needed if you want to map custom user profile properties to term sets: