Second Life of a Hungarian SharePoint Geek

February 9, 2016

Display Closed Risks Using Strikethrough Text on Project Server

As you probably have already seen, the name of the closed tasks (the ones having 100% completeness) is displayed using a strikethrough text in the All Tasks view of a task list in SharePoint. For example, from the tasks below, only Task 2 is 100 % complete.

image

Our users would like to have the same functionality in the Risks list on Project Server project sites, but out of the box, the title of the closed risks (ones having Status = "(3) Closed") is displayed without strikethrough, using the same formatting as any other risks:

image

Note: I assume you are familiar with client-side rendering. If not, and would like to understand how our solution works, I suggest you to read about it first, for example in the excellent post of Chris O’Brien.

After a short research, I found that this functionality of the Task lists is implemented in 15\TEMPLATE\LAYOUTS\hierarchytaskslist.debug.js. See the CompletedTitleTemplate template in that .js file.

Based on that template it was easy to implement the required functionality:

  1. (function () {
  2.     if (typeof window.CompletedRiskTitleTemplate == "object") {
  3.         return;
  4.     }
  5.     window.CompletedRiskTitleTemplate = {
  6.         RenderTitleField: function (inCtx, field, listItem, listSchema) {
  7.             var titleHtml = ComputedFieldWorker[field.Name](inCtx, field, listItem, listSchema);
  8.  
  9.             var result = (listItem["Status"] == "(3) Closed") ?
  10.                  '<span style="text-decoration: line-through">' + titleHtml + '</span>' :
  11.                  titleHtml;
  12.  
  13.             return result;
  14.         }
  15.     };
  16.     function _registerCompletedRiskTitleTemplate() {
  17.         var TitleFieldContext = {
  18.             Templates: {
  19.                 Fields: {
  20.                     'LinkTitle': {
  21.                         'View': window.CompletedRiskTitleTemplate.RenderTitleField
  22.                     }
  23.                 },
  24.                 ListTemplateType: 1101
  25.             }
  26.         };
  27.  
  28.         SPClientTemplates.TemplateManager.RegisterTemplateOverrides(TitleFieldContext);
  29.     }
  30.     ExecuteOrDelayUntilScriptLoaded(_registerCompletedRiskTitleTemplate, 'clienttemplates.js');
  31. })();

Note, that in this case we are using ListTemplateType 1101 for the Risks list instead of the value 171 for the original Task list type (Tasks with Timeline and Hierarchy to be exact). We get this list template value using the BaseTemplate property of our Risks list.

To ensure that the script is loaded on all views that include the Title field, we should set the JSLink property of the field with InternalName LinkTitle”.

Assuming you deployed your .js file to a path under the layout folder as /YourHive/js/strikeThroughClosedRisks.js, you can register your script using the following PowerShell code:

$web = Get-SPWeb http://YourProjServer/PWA/Proj1
$list = $web.Lists["Risks"]

$field = $list.Fields.GetFieldByInternalName("LinkTitle")
$field.JSLink = "~sitecollectionlayouts/YourHive/js/strikeThroughClosedRisks.js"
$field.Update()

Of course, this script affects only the web site of the project Proj1. If you would like to deploy it to all of your projects, you should iterate through the project web sites, but even better, you can prepare a project web site template based on this PWS in advance as described in my post last year, and use this template for your projects.

After successfully deploying our script, the text of the Title field of the closed risk is display using a strikethrough:

image

January 31, 2016

December 1, 2015

Delete a SharePoint List Template Programmatically

Filed under: PowerShell, SP 2013 — Tags: , — Peter Holpar @ 01:08

Last week I had to “reproduce” a custom list having a rather complex structure from a root web site into a sub web site. I mean, I had to create another list having the same fields and views like the original one, but located in another web site.

I fulfilled the requirements via a PowerShell script by creating a temporary list template (without including content), creating a list based on the template, and finally deleting the list template (as the title of this post promises), since we didn’t want to allow others to create the same list in the webs they have write access to.

Note: There are several alternative ways to copy a list from one site to another, for example via the SharePoint Content Deployment and the Migration API (see samples here, here and here), or via the Export-SPWeb and Import-SPWeb PowerShell Cmdlets. as illustrated in this example. Of course, each of these solutions has its own pros and cons, and it really depends on the exact requirements (do you need to copy the content, or just the structure; do you need to copy security or not; do you need to copy the versions or not, etc.) which way we may or should choose. The comparison of these methods is beyond the scope of the current post, but it is useful to know these alternatives.

But back to the deletion of the list template. The solutions I found on the web after a quick search were IMHO a bit complicated as it should be (see this and this one for example), as they iterate through the list items in the List Template Gallery list to find the file / list item that corresponds to our template.

Based on my experience, we can find the template directly via the indexer of the SPListTemplateCollection by name. It results in solution that is so simple:

$listTemplates = $web.Site.GetCustomListTemplates($web)
$listTemplate = $listTemplates[$listName]
$listTemplateFile = $web.GetFile("_catalogs/lt/" + $listTemplate.InternalName)
$listTemplateFile.Delete()

If you need the full code we used to copy the list, it is here as well:

$url = "http://YourSharePointSite&quot;

$targetWebUrl = "/SubSite"

$listName = "CustomListName"

$site = Get-SPSite $url
$sourceWeb = $site.RootWeb
$targetWeb = Get-SPWeb ($url + $targetWebUrl)

$list = $sourceWeb.Lists[$listName]
# create a temporary list template
# we copy the list without data, so the last param is 0
$list.SaveAsTemplate($listName, $listName, $listName, 0)

$listTemplates = $site.GetCustomListTemplates($sourceWeb)
$listTemplate = $listTemplates[$listName]
# create the list in the target web
# get the list description from the source list
$targetWeb.Lists.Add($listName, $list.Description, $listTemplate)

# delete the temporary list template, we don’t need it anymore
$listTemplateFile = $sourceWeb.GetFile("_catalogs/lt/" + $listTemplate.InternalName)
$listTemplateFile.Delete()

November 24, 2015

Recovering Passwords for SharePoint Managed Accounts

Filed under: PowerShell, Reflection, Security, SP 2013 — Tags: , , , — Peter Holpar @ 23:47

We have a SharePoint 2013 farm on a Windows 2008 R2 server. Recently we found this error in the Windows event logs in relation with the web application pool account:

Event ID 1511 – Windows cannot find the local profile and is logging you on with a temporary profile. Changes you make to this profile will be lost when you log off.

We tried to solve the issue based on the information we found in this post, but at the step below we faced the problem, that the password stored for the web application pool account (in this case we assumed domain\wa_pool_account) in our password repository does not work any more.

runas /u:domain\wa_pool_account /profile cmd

The web application pool account is registered as a managed account in SharePoint, at the original password has been already automatically changed by the system.

We could reset the password for the managed account as described in this article, but before changing the password I wanted to be sure there is no way to recover the current password from the system. I found a blog post and the related PowerShell code in TechNet Gallery, but I found the method described there (creating a new web application, and using an external tool, appcmd.exe) a bit overkill.

Instead of this I came up with an alternative solution that query the password directly from the SPManagedAccount object, via its private m_Password field (of type SPEncryptedString) that we can access by using Reflection. The public SecureStringValue property of the SPEncryptedString class returns an instance of the System.Security.SecureString class, and as illustrated here, we can “decode” its value to a simple string via Marshaling.

Using this approach, recovering the managed account password is so simple:

$ma = Get-SPManagedAccount domain\wa_pool_account
$maType = $ma.GetType()

$bindingFlags = [Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance

$m_Password = $maType.GetField("m_Password", $bindingFlags)
$pwdEnc = $m_Password.GetValue($ma)

$ssv = $pwdEnc.SecureStringValue
$ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($ssv)
[System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)

NullReferenceException in the Content Editor Web Part when Trying to Upload Images

Filed under: CEWP, SP 2013 — Tags: , — Peter Holpar @ 23:16

Recently a user complained, that when he tries to upload a photo in a Content Editor Web Part (CEWP)…

image

… an error is displayed.

image

We found the following relevant line in the ULS logs:

11/16/2015 12:46:45.29     w3wp.exe (0x21FFC)                          0x2185C    SharePoint Foundation             Runtime                           tkau    Unexpected    System.NullReferenceException: Object reference not set to an instance of an object.    at ASP._layouts_15_upload_aspx.__Render__control29(HtmlTextWriter __w, Control parameterContainer) in c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\upload.aspx:line 81     at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)     at Microsoft.SharePoint.WebControls.ScriptBlock.Render(HtmlTextWriter writer)     at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)     at ASP._layouts_15_upload_aspx.__Render__control27(HtmlTextWriter __w, Control parameterContainer) in c:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\TEMPLATE\LAYOUTS\upload.aspx:line 61     at Sy…    b324429d-5597-507f-40b1-b3a2b68192e5

In upload.aspx at line 81 there is a reference for CurrentList.ID:

function LaunchOpenInExplorer()
{
    vCurrentListID = "<%= CurrentList.ID %>";
    vCurrentListUrlAsHTML = "<%= Web.Url + "/" + (CurrentList.RootFolder.Url.Length > 0 ? CurrentList.RootFolder.Url + "/" : "") %>";

}

We got the NullReferenceException, because the CurrentList object is null.

In our case, the CurrentList was null, because somebody has deleted all document libraries from the site where the page with the CEWP was located, so there was no place the user could upload the image.

However, we should not delete all of the libraries if you want to reproduce the issue. The GetActionableDocumentLibraries method of the Microsoft.SharePoint.ApplicationPages.UploadPage class is responsible for populating the list of document libraries of the upload page that are candidates for image upload. We can find the following loop and conditions in this method:

List<SPDocumentLibrary> list = new List<SPDocumentLibrary>();
foreach (SPList list2 in web.Lists)
{
  …
  SPDocumentLibrary item = list2 as SPDocumentLibrary;
  if ((((item != null) && !item.Hidden) && ((SPBaseType.DocumentLibrary == item.BaseType) && (SPListTemplateType.WebPageLibrary != item.BaseTemplate))) && (!item.IsCatalog && (!requireAddListItemsPermissions || (requireAddListItemsPermissions && list2.DoesUserHavePermissions(SPBasePermissions.AddListItems, false)))))
  {
    list.Add(item);
  }

}

As you can see, the library should not be a hidden one, should not be the Site Pages library or any of the standard catalog libraries (like Web Part Catalog), and the user must have the permission to add items to the list. For example, if there are no document libraries the user is allowed to add items to, we have the same issue with the CEWP.

Re-creating the deleted document library solved the issue for the user.

October 19, 2015

Displaying Notifications and Status Messages from a SharePoint-based AngularJS Application Including a FormController

Assume the following requirements: We should create a Single Page Application (SPA) (no SharePoint App!) that reads data from SharePoint using the JavaScript client object model, allows the user to edit the values, displays if a field value was changed (if it is “dirty” vs. “pristine”), performs data validations (if it is “valid” vs. “invalid”) and lets the user to save the changes. AngularJS was selected as the presentation framework for the SPA. On data save, we should give the users feedback on the progress (like “Saving changes…”, “Save completed” or “Error during the save operation”) via standard SharePoint notifications and status messages.

Challenge 1:  The FormController of the AngularJS framework is based on the form HTML element. That means, if we would like to use the features of the FormController, like dirty / pristine, validation, etc., we should include a form element in our HTML application. However, our SharePoint page is an ASP.NET page, that already contains a form element, and it does not like to include multiple ones.

Solution 1: Although there are tricks to bypass this limitation (like this or this one), I chose another way to go. I’ve included a Page Viewer Web Part that displays a “pure” HTML page that is stored in a document library in SharePoint, as well as any other non-standard artifacts of the application (.js and .css files, etc.). This HTML page – displayed in an IFRAME by the Page Viewer Web Part – contains the form element, that does not interfere with the form element on the ASP.NET page.

You can display a notification by calling the SP.UI.Notify.addNotification method, similarly a status message is displayed via the SP.UI.Status.addStatus method. Both of these Notify and Status classes are defined in the SP.UI namespace in the sp.js (and its debug version in sp.debug.js). This JavaScript file is typically referenced in the standard SharePoint pages, however you should add a reference to it in your custom pages, like in the case of our HTML page. If you forget to add the reference, you will get an error like this one:

TypeError: Unable to get property ‘addNotification’ of undefined or null reference

Challenge 2:  There is no notification / status message displayed, even if you add the reference to the sp.js. The reason of the problem is, that the HTML elements required by these methods are defined in the master page of the standard SharePoint sites. Obviously, these elements are not found in our custom page in the IFRAME, so the messages are not displayed.

Solution 2: I’ve found two similar blog posts (this one and this one) describing a similar issue with IFRAME and notification messages in the case of Client App Parts. The first of this two posts states that the problem is the IFRAME itself, that prohibits the communication between the parent page and the IFRAME. Of course, that is wrong. The real reason is the different domain names in the URL of the app part (IFRAME) and the host page, as correctly stated in the second post. If we have the same domain name (and we do have in this case), we do not need the rather complex approach described by the posts(that is still valid for the Client App Parts).  Displaying a notification / status message from the script included in the HTML page in the IFRAME in our case is so simple as to prepend the text ‘parent.’ before the method invocation, for example:

var notifyId = parent.SP.UI.Notify.addNotification("Saving…", true);

Of course, in this case you are using the JavaScript and HTML objects on the parent page, so you don’t need to reference the sp.js in your HTML page.

October 12, 2015

Waiting for Project Server Queue Operations in Server Side Code

Filed under: PS 2013 — Tags: — Peter Holpar @ 23:48

Recently we found a bug in our server-side Project Server code. Our goal was to set some project-related enterprise custom field values. Before setting the values, we tested, if the project is checked-out (to another user), and if so, we forced a a check-in, to be able to check out again to ourselves. After setting the values, we updated the project and published it, including check-in.

  1. if (proj.IsCheckedOut)
  2. {
  3.     proj.Draft.CheckIn(true);
  4. }
  5. DraftProject draftProj = proj.CheckOut();
  6. // set some custom field values
  7. draftProj.SetCustomFieldValue("customFieldName", "customFieldValue");
  8. draftProj.Update();
  9. draftProj.Publish(true);

If the project was not checked-out, the code worked as expected. However, if the project was checked-out to a use, we got an exception despite of the test on the line

DraftProject draftProj = proj.CheckOut();

The exception was:

Microsoft.ProjectServer.PJClientCallableException was unhandled
  _HResult=-2146233088
  _message=CICOCheckedOutInOtherSession
  HResult=-2146233088
  IsTransient=false
  Message=CICOCheckedOutInOtherSession
  Source=Microsoft.ProjectServer
  PSErrorCode=10103
  PSErrorName=CICOCheckedOutInOtherSession
  StackTrace:
       at Microsoft.ProjectServer.PublishedProject.CheckOut()
       at SPGeneral.Program.Main(String[] args) in c:\projects\PSTest\Program.cs:line 37
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException:

The message “CICOCheckedOutInOtherSession” suggested, that the project is not yet checked-in, although our traces showed that the line proj.Draft.CheckIn(true) was executed.

To understand the source of the problem, we should first understand how the CheckIn / CheckOut and Publish methods are executed:

Both of the CheckIn and Publish methods of the DraftProject class are executed asynchronously. These methods return a QueueJob object. The actual job is performed by the queue subsystem of Project Server.

The CheckOut method of the PublishedProject class is executed synchronously, it returns a DraftProject instance immediately.

In the above sample it means, that proj.CheckOut() is called, before the project would be effectively checked-in as a result of executing proj.Draft.CheckIn(true).

How to solve the problem, keeping our code readable if possible?

If you are working with client-side object model of Project Server, you know probably, that there is a solution for such issues: the WaitForQueue method of the ProjectContext object.Unfortunately, the equivalent of this method is not implemented in the server-side object model. It’s pretty strange, as usually its opposite is the case: methods and properties available on the server-side are many times missing on the client-side OM.

No problem, we can implement a similar method for ourselves!

The WaitForQueue method “wait for the specified queue job to complete, or for a maximum number of seconds”. It returns a JobState object, that should be JobState.Success if the queue job succeeded. If we have a look at the implementation of the method, we can see, that it calls the internal IsPendingJob method of the ProjectContext object to compare the current state of the job with the expected values, the refresh the job status by polling the server side objects. The wait time is decremented by 2 seconds in every iteration, the IsPendingJob method is responsible to sleep the thread for this two seconds.

Note: It means that the maximum wait time specified when calling WaitForQueue method is only an approximate value, as it does not include the send / response time of the server requests involved in the refreshing the job status, for example a one-minute wait time means 30 iterations, that is 30 requests / responses. So don’t be surprise if your wait times are considerably longer than specified if you have a slow network or busy server.

After this theory, lets see our own implementation:

  1. public static bool IsPending(this QueueJob job, out QueueConstants.JobState state)
  2. {
  3.         state = job.JobState;
  4.         switch (state)
  5.         {
  6.             case QueueConstants.JobState.Unknown:
  7.             case QueueConstants.JobState.ReadyForProcessing:
  8.             case QueueConstants.JobState.SendIncomplete:
  9.             case QueueConstants.JobState.Processing:
  10.             case QueueConstants.JobState.ProcessingDeferred:
  11.             case QueueConstants.JobState.OnHold:
  12.             case QueueConstants.JobState.Sleeping:
  13.             case QueueConstants.JobState.ReadyForLaunch:
  14.                 Thread.Sleep(new TimeSpan(0, 0, 2));
  15.                 return true;
  16.         }
  17.     state = QueueConstants.JobState.Success;
  18.     return false;
  19. }
  20.  
  21. public static QueueConstants.JobState WaitToFinish(this QueueJob job, int timeoutSeconds)
  22. {
  23.     QueueConstants.JobState state = QueueConstants.JobState.Unknown;
  24.     while ((timeoutSeconds > 0) && job.IsPending(out state))
  25.     {
  26.         timeoutSeconds -= 2;
  27.     }
  28.     return state;
  29. }

As you can see, instead of extending the PSContext object with a WaitForQueue method, I decided to extend the QueueJob object itself with a WaitToFinish method. It seems to me simply more appropriate.

Note: As you probably know, and as I mentioned in my former posts, the server-side object model is based on the PSI infrastructure. It means, that the extra wait time mentioned above may apply to this solution as well.

Note 2: To be able to use the JobState enumeration value in your code, you should reference the Microsoft.Office.Project.Server.Library assembly in your project.

The modified logic in our application is displayed below:

  1. var timeOutInSec = 60; // wait max a minute
  2. bool canCheckOut = !proj.IsCheckedOut;
  3. if (!canCheckOut)
  4. {
  5.     // Project is checked out. Forcing check-in.
  6.     var job = proj.Draft.CheckIn(true);
  7.     var jobState = job.WaitToFinish(timeOutInSec);
  8.     if (jobState == QueueConstants.JobState.Success)
  9.     {
  10.         canCheckOut = true;
  11.     }
  12.     else
  13.     {
  14.         // WARNING Time-out on project check-in, or job failed
  15.     }
  16. }
  17.  
  18. if (canCheckOut)
  19. {
  20.     DraftProject draftProj = proj.CheckOut();
  21.     // set some custom field values
  22.     draftProj.SetCustomFieldValue("customFieldName", "customFieldValue");
  23.     draftProj.Update();
  24.  
  25.     // Publishing project (incl. check-in!)
  26.     var job = draftProj.Publish(true);
  27.     var jobState = job.WaitToFinish(Constants.DefaultPSJobTimeOut);
  28.     if (jobState == QueueConstants.JobState.Success)
  29.     {
  30.         // Project checked-in + published.
  31.     }
  32.     else
  33.     {
  34.         // WARNING Time-out on project publish / check-in or job failed
  35.     }
  36. }
  37. else
  38. {
  39.     // WARNING Project can not be checked-out / processed
  40. }

October 1, 2015

Change in the User Resolution in SharePoint 2013 People Picker

Filed under: Active Directory, People Picker, PowerShell, SP 2013 — Tags: , , , — Peter Holpar @ 22:31

After a SharePoint 2010 to SharePoint 2013 migration our users complained, that in the multiple Active Directory domain environment they have (I wrote about it recently) the People Picker does not resolve the users the same way it did earlier. Only a subset of the users was resolved, users from a few domains were not included in the results at all.

The reason of this issue is a change in the GetTrustedDomains method of the Microsoft.SharePoint.Utilities.SPUserUtility class. Now (in SP 2013) it includes an extra condition, checking the value of  SPWebService.ContentService.PeoplePickerSearchInMultipleForests.

If you need the same behavior as in the SP 2010 version, you should set the value of  the PeoplePickerSearchInMultipleForests property to true.

You can achieve it using PowerShell:

$cs = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$cs.PeoplePickerSearchInMultipleForests = $true
$cs.Update()

or via C#:

SPWebService.ContentService.PeoplePickerSearchInMultipleForests = true;
SPWebService.ContentService.Update();

The SharePoint Time Machine

Filed under: SP 2013, Tips & Tricks — Tags: , — Peter Holpar @ 22:06

Assume you have a SharePoint list with a lot of items. The list supports versioning and you should provide a snapshot of the items at a given time in the past.

As you know, the Versions property (of type SPListItemVersionCollection) of the SPListItem class contains the item versions. One can access a specific version via the indexer property of the collection, by the ID of the version (where the ID = 512 * major version number + minor version number), or by the version number (a.k.a. label, for example, 2.3), but there is no direct support to get the actual version at a specific time in the past.

To achieve my goal, I’ve implemented the GetVersionFromDate extension method, that iterates through the method, and returns the version we need based on its creation date:

  1. public static SPListItemVersion GetVersionFromDate(this SPListItemVersionCollection versions, DateTime localDate)
  2. {
  3.     SPListItemVersion result = null;
  4.  
  5.     if (versions != null)
  6.     {
  7.         DateTime date = versions.ListItem.Web.RegionalSettings.TimeZone.LocalTimeToUTC(localDate);
  8.  
  9.         SPListItemVersion prevVersion = null;
  10.  
  11.         // versions[0] – current item version
  12.         // versions[versions.Count – 1] – first item version created
  13.         for (int i = versions.Count – 1; i >= 0; i–)
  14.         {
  15.             SPListItemVersion version = versions[i];
  16.             if (version.Created > date)
  17.             {
  18.                 result = prevVersion;
  19.                 break;
  20.             }
  21.             // if it is the last (actual) version and there is no result yet,
  22.             // then the date specified should be greater than the creation date of the last version
  23.             // we take the last version
  24.             else if (i == 0)
  25.             {
  26.                 result = version;
  27.             }
  28.  
  29.             prevVersion = version;
  30.         }                
  31.  
  32.     }
  33.  
  34.     return result;
  35. }

Note, that the Created property stores the creation date as UTC time, that we should convert first.

Using this method accessing the specific version is so simple as:

  1. SPList list = web.Lists["Your List"];
  2. SPListItem item = list.Items.GetItemById(1);
  3.  
  4. DateTime date = DateTime.Parse("2015/06/29 13:40");
  5. SPListItemVersion version = item.Versions.GetVersionFromDate(date);
  6. Console.WriteLine(version["APropertyName"]);

If you go through the items in the list and get the version of the specific time, you already have the required snapshot.

September 29, 2015

People Picker is very slow when searching users

Filed under: Active Directory, People Picker, SP 2010 — Tags: , , — Peter Holpar @ 22:12

The environment of a customer of us consists of several Active Directory domains, a few of them were recently migrated from former domains.

Users of the SharePoint sites complained that when they try to look up users via the People Picker, the result is displayed only after a delay of  30-40 seconds, instead of the former 3-5 seconds.

I’ve tried to catch the problem using Wireshark, filtering for the LDAP protocol, as described in this post. However, I found no problem with the requests / responses, except for a delay of about 30 seconds, although no request using this protocol was sent in this time lag. Obviously, the sender process waited for a response sent using another protocol.

Removing the LDAP filter in Wireshark, I found these retransmission attempts:

No.     Time            Source                        Destination   Protocol Length  Info
3241    44.218621000    IP of the SharePoint Server   IP of the DC    TCP    66    53607 > msft-gc [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
3360    47.217136000    IP of the SharePoint Server   IP of the DC    TCP    66    [TCP Retransmission] 53607 > msft-gc [SYN] Seq=0 Win=8192 Len=0 MSS=1460 WS=256 SACK_PERM=1
3791    53.221414000    IP of the SharePoint Server   IP of the DC    TCP    62    [TCP Retransmission] 53607 > msft-gc [SYN] Seq=0 Win=8192 Len=0 MSS=1460 SACK_PERM=1

The msft-gc is an LDAP-like protocol used to query the Global Catalog (GC) in the Active Directory (uses port 3268). The retransmission timeout (RTO) value of the packet 3360 was 3 sec., the RTO of the packet 3791 was 9 sec., both causing delay in the user search process.

The source IP was the address of the SharePoint server, the IP address in the destination is the address of a former Domain Controller (DC). The server, that acted as DC of a domain that was already migrated was online, but the DC-role was already demoted on it . The IP address of the server was registered in DNS, so the server could be PINGed, but it did not respond to LDAP requests (including msft-gc) anymore.

The entries in the ULS logs has provided further evidence, that there is an issue with the Global Catalog in the AD forest (see the SearchFromGC method in the stack trace below):.

08/06/2015 13:26:34.08     w3wp.exe (0x66BC)                           0x9670    SharePoint Foundation             General                           72e9    Medium      Error in resolving user ‘UserName‘ : System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.       at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)     at System.DirectoryServices.DirectoryEntry.Bind()     at System.DirectoryServices.DirectoryEntry.get_AdsObject()     at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)     at Microsoft.SharePoint.WebControls.PeopleEditor.SearchFromGC(SPActiveDirectoryDomain domain, String strFilter, String[] rgstrProp, Int32 nTimeout, Int32 nSizeLimit, SPUserCollection spUsers, ArrayList& rgResults)     at Microsoft.SharePoint.Utilities.SPUserUtility.ResolveAgainstAD(String input, Boolean inputIsEmailOnly, SPActiveDirectoryDomain globalCatalog, SPPrincipalType scopes, SPUserCo…    04482a74-c00f-4005-9cd3-11f765eca7a0
08/06/2015 13:26:34.08*    w3wp.exe (0x66BC)                           0x9670    SharePoint Foundation             General                           72e9    Medium      …llection usersContainer, TimeSpan searchTimeout, String customFilter)     at Microsoft.SharePoint.Utilities.SPActiveDirectoryPrincipalResolver.ResolvePrincipal(String input, Boolean inputIsEmailOnly, SPPrincipalType scopes, SPPrincipalSource sources, SPUserCollection usersContainer)     at Microsoft.SharePoint.Utilities.SPUtility.ResolvePrincipalInternal(SPWeb web, SPWebApplication webApp, Nullable`1 urlZone, String input, SPPrincipalType scopes, SPPrincipalSource sources, SPUserCollection usersContainer, Boolean inputIsEmailOnly, Boolean alwaysAddWindowsResolver).    04482a74-c00f-4005-9cd3-11f765eca7a0

Removing the orphaned DC entry from the AD  resolved the People Picker problem as well.

Older Posts »

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 61 other followers