Mittwoch, 10. Juni 2015

Disabled users in SharePoint


Problem:
Do you have disabled users from active directory appear in SharePoint?

There are scenarios you might observe disable person's details will appear in SharePoint people search, they will still show in the organization chart webpart in my site etc. In the configuration of the user profile service you can filter the disabled user accounts from active directory to SharePoint.

Solution:
Filter the disabled user accounts in user profile service

Go to [Central administration] [Application Management] [Manage Service Applications] [User Profile Service Application]

Click on Configure Synchronization Connections

From the connections you are using click on Edit Connection Filters menu.


It will open the Edit Connection Filters screen from that you can see Exclusion filter for users. In Exclusion filter for users enter the below values.

Attribute : userAccountControls (Select from dropdown)
Operator: Bit on Equal (Select from dropdown)
Filter : 2

Once you enter the required values click on Add button and it will show the below details in Exclusion filter for users section.
Finally click on ok button to submit the Edit connection filters details. Once you are done do a full synchronization run.

Problem 2:
This does not filter users in the SharePoint address book.

Solution 2:

By configuring the settings for the control, you can filter and restrict the results that are displayed when a user searches for a user, group, or claim. Those settings will apply to every site within the site collection.

The following example filters out user accounts that do not have e-mail addresses, or that are disabled. Because security groups do not always have e-mail addresses associated with them, an OR statement is used to ensure that security groups are still included in the query results:

stsadm -o setproperty -pn peoplepicker-searchadcustomfilter -pv "(|(&(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))(objectcategory=group))" -url http://ServerName

Freitag, 17. April 2015

Flatten dictionary to string

Problem:
How to save the content of a dictionary into a string?

Solution:

Dictionary<string, string> testDic = new Dictionary<string, string>();
testDic.Add("key1", "value1");
testDic.Add("key2", "value2");
testDic.Add("key3", "value3");

// flatten dictionary
string resultStr = string.Join(";", testDic.Select(y => y.Key + "=" + y.Value));

// reverse
Dictionary<string, string> resultDic = resultStr.Split(';').Select(x => x.Split('=')).ToDictionary(x => x[0], y => y[1]);


             
How to do it with a nested dictionary?

Solution:
Dictionary<string, Dictionary<string, double>> testDic = new Dictionary<string, Dictionary<string, double>>();

testDic.Add("key1", new Dictionary<string, double>());
testDic["key1"].Add("key11", 11);
testDic.Add("key2", new Dictionary<string, double>());
testDic["key2"].Add("key21", 21);
testDic["key2"].Add("key22", 22);
testDic.Add("key3", new Dictionary<string, double>());
testDic["key3"].Add("key31", 31);

// flatten dictionary
string resultStr = string.Join("|", testDic.Select(x => x.Key + ":" + string.Join(";", testDic[x.Key].Select(y => y.Key + "=" + y.Value))));

// reverse
Dictionary<string, Dictionary<string, double>> resultDic = new Dictionary<string, Dictionary<string, double>>();
Dictionary<string, string> tmpDic = resultStr.Split('|').Select(x => x.Split(':')).ToDictionary(x => x[0], y => y[1]);
tmpDic.ToList().ForEach(t => resultDic.Add(t.Key, t.Value.Split(';').Select(x => x.Split('=')).ToDictionary(x => x[0], y => Convert.ToDouble(y[1]))));
 

Montag, 30. März 2015

ExecuteOrDelayUntilScriptLoaded not working

Problem:
ExecuteOrDelayUntilScriptLoaded in a page or specifically in a publishing page does not work.
This might be also the case when a user who has only read/view access to the site, sp.js refuses to load when ExecuteOrDelayUntilScriptLoaded is used.

Solution:
In SharePoint 2013, the correct way to execute a function after script is loaded is to use SP.SOD class and not ExecuteOrDelayUntilScriptLoaded.
For example I needed to use it in:
 
function openInDialog(dlgWidth, dlgHeight, dlgAllowMaximize, dlgShowClose, pageUrl ) {
      var options = {
          url: pageUrl,
          width: dlgWidth,
          height: dlgHeight,
          allowMaximize: dlgAllowMaximize,
          showClose: dlgShowClose
      };

      options.dialogReturnValueCallback = Function.createDelegate(null, CloseDialogCallback);
      SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.showModalDialog', options);
  }


  function CloseDialogCallback(dialogResult, returnValue) {
      if (dialogResult == SP.UI.DialogResult.OK) { // refresh parent page
          SP.SOD.execute('sp.ui.dialog.js', 'SP.UI.ModalDialog.RefreshPage', SP.UI.DialogResult.OK);
      }
      // if user click on Close or Cancel
      else if (dialogResult == SP.UI.DialogResult.cancel) { // Do Nothing or add any logic you want
      } else { //alert("else " + dialogResult);
      }
  }

Sonntag, 22. März 2015

Create client-side email using mailto before server postback

Problem:
So it looks like it isn't a good idea to set the window.location.href before a postback.

 I tried a few options, like using the setTimeout function to force setting window.location.href slightly later in the JS thread lifecycle. But that didn't work; it seemed that any alteration of the DOM's location was causing issues with the postback.

So how can we get the browser to call the mailto link without affecting the postback?
Use an iframe, as the source of the iframe would be separate from the current document and should not interfere with any postbacks.
I modified my CreateEmail function so it would create a new iframe with its src attribute set to the mailto link, append it to the document body so the browser would execute the mailto link, and then remove it again from the DOM:
Solution:

<script type="text/javascript">

  function CreateEmail() {
    var mailto =  'mailto:?to=any@anydomain.com';

    $('<iframe />')
       .prop('src', mailto)
       .css('display', 'none')
       .appendTo('body')
       .remove();
  }
</script>

Montag, 16. März 2015

Setting EventFiringEnabled property from Powershell

You would like to upload documents to a document library via Powershell and disable events that might be fired or don't start workflows on this item change?

How to set the EventFiringEnabled property from Powershell?

Solution:
Actually this is not really something you generally do from PowerShell. The purpose of EventFiringEnabled is to prevent an event receiver from triggering the same event recursively.
However,  you can switch it off for the thread upon which your PowerShell code is running:

$myAss = [Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint");
$type = $myAss.GetType("Microsoft.SharePoint.SPEventManager");
$prop = $type.GetProperty([string]"EventFiringDisabled",[System.Reflection.BindingFlags] ([System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static));
$prop.SetValue($null, $true, $null);
#code to update list goes here!

Donnerstag, 3. Juli 2014

SharePoint ThreadAbortException

Problem: If you are doing a SPSite.OpenWeb() (or maybe its done for you, when you request the profile service) and you do not have the permissions to the site there is an UnauthorizedAccessException being thrown. But if you are trying to catch it, immediately after the catch an ThreadAboardException is thrown and you code does not continue. That is because of access denied exceptions inside page requests are explicitly handled by the platform. For example, when Forms-based authentication is used, anonymous users are redirected to the login page. If the user is already authenticated, he may be redirected to an error message page such as _layouts/AccessDenied.aspx.
When you are developing web parts that behavior is okay but running such code in a timer job or WCF webservice is problematic.

Solution: You should turn off that behaviour by setting the following flag:

bool originalCatchValue = SPSecurity.CatchAccessDeniedException;
SPSecurity.CatchAccessDeniedException = false;

try
{
   // your code

}
finally
{
   SPSecurity.CatchAccessDeniedException = originalCatchValue;
}


Within the try statement you are able to catch the UnauthorizedAccessException as usual.


2nd Problem: Another reason you get a ThreadAbortException could be that your request could not be validated by SharePoint. This could be the case if you are developing a WCF webservice within SharePoint context. In the exception stacktrace you should see  Microsoft.SharePoint.SPWeb.ValidateFormDigest()

Solution:
In this case SPContext.Current is not null, Sharepoint tries to verify requests using security validation digest provided by FormDigest Class. According to msdn:
"To make posts from a Web application that modify the contents of the database, you must include the FormDigest control in the form making the post. The FormDigest control generates a security validation, or message digest, to help prevent the type of attack whereby a user is tricked into posting data to the server without knowing it. The security validation is specific to a user, site, and time period and expires after a configurable amount of time. When the user requests a page, the server returns the page with security validation inserted. When the user then submits the form, the server verifies that the security validation has not changed".
In WCF service you don't have security digest. To avoid this check try to set HttpContext.Current to null temporary when you call siteCollection.Add() method:

var ctx = HttpContext.Current;
try
{
    HttpContext.Current = null;
    // your code
}
finally
{
    HttpContext.Current = ctx;
}

Donnerstag, 19. Juni 2014

UserProfile Sync problem:Could not connect to http://(server):5725/ResourceManagementService/MEX

Problem: You are trying to sync user profiles from active Directory and get an error:

Could not connect to :5725/ResourceManagementService/MEX. TCP error code 10061: No connection could be made because the target machine actively refused it


Solution: Verify that windows service "Forefront Identity Manager Service" and "Forefront Identity Manager Synchronization Service" are started. If not, please start them and then check the effect.