Tuesday, February 26, 2013

Find the Source of SharePoint Workflow Email

Occasionally I have had someone approach me with a request to figure out why they are receiving an email from SharePoint.  Usually I can figure it out quickly from context clues (such as the message sender’s display name, which is the same as the sending site’s title). But sometimes I have been thrown for a loop and couldn’t figure out the source off the site title alone.  Luckily, SharePoint often gives all the necessary clues in the message header:

image

In exchange if you open the email, then click File => Properties the Internet headers show the pertinent info:

  • The first line in the headers will be “Received: from SharePointServerName” – This will tell you what farm. (I have had occasion where a content database was restored to another environment and that was why I wasn’t figuring out the source.)
  • Often there will also be headers like:
    • x-sharing-itemid: 1569 – this is the item id of the list item associated with the workflow
    • x-sharing-remote-uid: {CD66E7CA-688C-4A39-870F-C9B93D4C88E7} – this is the list id of the parent list.
    • x-sharing-wssbaseurl: http://sharepoint/sites/collection/website – this is the url of the website hosting the list.

Thursday, January 3, 2013

SharePoint bookmark: This control is currently disabled.

 

I noticed on a SharePoint wiki library that the bookmark functionality was disabled.  When I hovered over the textbox for the control it provided the following prompt:

“This control is currently disabled.  You might not have the right permission level to use this, you might need to select an object or item, or the control might not work in this context.” 

image

I had used this functionality on other sites, and was puzzled why it was disabled in this instance.  The answer, luckily, ended up being simple.  The “Bookmark” functionality as part of creating links is apparently dependent on the site collection feature: SharePoint Server Publishing Infrastructure.

image

It is also dependent on the SharePoint Server Publishing site feature:

image

Once these features are enabled on the target site, then the control is also enabled:

image

Thursday, December 27, 2012

Using jQuery Deferred object with SharePoint Javascript Object Model

One of the common problems with using the SharePoint client object model is the asynchronous nature of the object property calls. For example, if I want to retrieve a current user’s name, I would run code something like this:

context = new SP.ClientContext.get_current();
web = context.get_web();
currentUser = web.get_currentUser();
currentUser.retrieve();
context.load(web);
context.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceeded),
Function.createDelegate(this, this.onQueryFailed)
);


The executeQueryAsync method, after it retrieves the current user information, calls the onQuerySuceeded function that then completes the processing of that request. For example, something like this would be a simple example of that callback



function onSuccessMethod(sender, args) {
var userObject = web.get_currentUser();
alert('User name:' + userObject.get_title());
}


In between the time that the executeQueryAsync is called and the callback to the onSuccessMethod function occurs any other code that was downstream executes. This makes for awkward logic and flow in client object model programs. This is especially true when building larger applications that may want to reuse, let’s say, a function called getUserInformation which returns the current user as an object. This is where a little jQuery magic can come in handy. jQuery supports using what it refers to as Deferreds. Deferreds are based on a CommonJS Promises/A design. At the bottom of this post I will provide a link to documentation on Deferreds and the CommonJS Promise/A design, but for now let’s look at an example of how we can use this.


Let’s say I wanted to build a function like I mentioned above. A function that retrieves the current user’s information and returns that as an object. Since this request is asynchronous, this could normally be very problematic, but with a Deferred object it can be done simply. First, the initial function:

 

function getUserInformation() {
var dfd = $.Deferred(function(){
context = new SP.ClientContext.get_current();
web = context.get_web();
currentUser = web.get_currentUser();
currentUser.retrieve();
context.load(web);
context.executeQueryAsync(
function(){
var userObject = web.get_currentUser();
dfd.resolve(userObject);
},
function(){
dfd.reject(args.get_message());
}
);
});
return dfd.promise();
}

This function creates a Deferred object, then it runs the same code as above to request the current user. The callback functions have been embedded into the executeQueryAsync method so that I can easily reference my existing Deferred object. Notice that the function itself does not return the user object. This is because when the function completes processing the user object has not yet returned. It will be return later asynchronously. Instead, the function returns a promise; a contract that there will be a return value in the future. When the callback does occur then the Deferred object is resolved and any code waiting for the object to return can execute. For illustration purposes here is a simple call to this function that creates a popup message box with the current user’s name (via the title property).

 

getUserInformation().done(function(user){ 
alert('User name:' + user.get_title());
});

The nice feature with this is that if later I want to return that same user’s email address I can just as easily do that reusing the same function:

getUserInformation().done(function(user){ 
alert('Email address:' + user.get_email());
});

To learn more about promises and Deferred objects visit these link

Tuesday, December 18, 2012

Using JsRender with the SharePoint JavaScript Object Model

Are you getting tired of writing a lot of JavaScript to manipulate the DOM while doing client side SharePoint development? This is simple tutorial about using templates with client side SharePoint development to avoid writing a lot of JavaScript to manipulate the DOM.  The template engine used in this tutorial is JsRender, which replaced jQuery templates.  Check out these links for more information on JsRender:

The following example was created in a content editor web part.

Create the HTML:
 
<div id="TasksTable">
<table id="taskTbl" cellpadding="5" cellspacing="5" border="1">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Priority</th>
</tr>
</thead>
<tbody id="taskTblBody">

</tbody>
</table>
</div>


Create the Template Block:
<script id="taskTemplate" type="text/x-jsrender">
<tr>
<td>{{:#data.get_id()}}</td>
<td>{{:#data.get_item('Title')}}</td>
<td>{{:#data.get_item('Status')}}</td>
<td>{{:#data.get_item('Priority')}}</td>
</tr>
</script>
Be sure to include all the files needed:


<script 
type="text/javascript"
src="/sites/Bwarfson/CScripts/jquery-1.7.1.min.js">
</script>
<script
type="text/javascript"
src="/sites/Bwarfson/CScripts/jsrender.js">
</script>


And the JavaScript:
$(document).ready(function() {
if (typeof(_spBodyOnLoadWrapper) != 'undefined')
{_spBodyOnLoadWrapper();} //fix google chrome
ExecuteOrDelayUntilScriptLoaded(function ()
{ retrieveListItems() }, "sp.js");
});

function retrieveListItems() {
var clientContext = new SP.ClientContext.get_current();
var oList = clientContext
.get_web()
.get_lists()
.getByTitle('Tasks');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><RowLimit>500</RowLimit></View>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(
collListItem,
'Include(Id, Title, Status, Priority)'
);
clientContext.executeQueryAsync(
Function.createDelegate(this, function() {
//This is where the magic happens
$( "#taskTblBody" ).append(
$( "#taskTemplate" ).render( collListItem.get_data() )
);
}), Function.createDelegate(this, function(sender, args) {
$('.message').append('<p>Error loading tasks</p>');
$('.message').append('<p>'+args.get_message()+'</p>');
$('.message').append('<p>'+args.get_stackTrace()+'</p>');
}));

}

The final result:

image

Monday, November 5, 2012

Using JavaScript to asynchronously update a xsltlistview webpart

 

In SharePoint 2010 there is an option to “Enable Asynchronous Update”

image

This option exists on each SharePoint 2010 xsltlistview web part.  I had some custom JavaScript that was embedded in a custom action and changed list item values.  I wanted to be able to use this feature to do a no-refresh list view reload.  If you enable the “Show Manual Refresh Button” option you will see the default code that forces a refresh.  It looks something like this:

javascript: __doPostBack('ctl00$m$g_d9ea718d_b0cd_42e5_b4cf_4182334b6861$ctl02','cancel');return false;

Now I just needed a good way to get that same id that is being passed into the __doPostBack function.  Luckily, this value is similar to the GUID of the view for the list.  For example, the view guid of this webpart is {D9EA718D-B0CD-42E5-B4CF-4182334B6861}.  To build the __doPostBack I need to transform the guid to match the format of the ID.  Here is the code I wrote to perform this operation:

var selectedViewId = ctx.view;
var controlId = 'ctl00$m$g_' + selectedViewId.toLowerCase().replace(/-/g, "_").replace(/{|}/g, "") + '$ctl02';
__doPostBack(controlId);

The controlId variable is: the view guid, converted to lowercase, replacing the dashes with underscores, removing the curly braces, attaching ctl00$m$g_ to the front, and $ctl02 to the end.  This seems to work on any xsltlistview web part (whether part of a list view or embedded in a web part page). 

Monday, October 22, 2012

Creating SharePoint Custom List Columns in PowerShell

 

I needed to create a sizable test in SharePoint using a custom list.  I did not want to manually configure each column so I build a tab delimited text file that held the column configuration options and a PowerShell script to read it.  The first column of the file provides the field name, the second provides the options (they were separated by a pipe delimiter), and the third column is the field description.  I wanted all of the questions to be Radio Button choice fields so those options were hard coded.  I also wanted a letter and appended to each answer so I created an array of letters up to G. 

$w = get-spweb http://spsite
$l = $w.lists["MyTest"]

$letters = "A|B|C|D|E|F|G"
$lttr = $letters.split("|")
$spFieldType = [Microsoft.SharePoint.SPFieldType]::Choice

$file = Get-Content c:\Questions.txt

foreach ($line in $file) {
  
    $fields = $line.ToString().Split("`t")
    $fName = $l.Fields.Add($fields[0],$spFieldType,$True)   
    write-host $fName
    $f = $l.Fields[$fName]
    $choices = $fields[1].split("|")

    for ($i=0; $i -lt $choices.count; $i++)
    {
        $choiceValue = $lttr[$i] + ". " + $choices[$i]
        $f.Choices.Add($choiceValue)
    }
    $f.description = $fields[2]
    $f.EditFormat = "RadioButtons"
    $f.update()

}

The script works like a champ, and I saved myself a little time and frustration of repetitively clicking the same options over and over again.

PowerShell to display SPN and Delegation Information for SharePoint Accounts

 

In troubleshooting Kerberos issues it is sometimes helpful to see the all the SPNs and delegate to settings for my various SharePoint accounts.  Since our SharePoint accounts are named in a consistent way this ended up being quite easy.  I set a filter that looks for accounts that start with the name PRD-SP and looked in the proper container in the Active Directory.  I piped the output to a file and I had a useful listing of all the SPNs and their delegate to settings.

$strFilter = "(&(objectCategory=User)(sAMAccountName=PRD-SP*))"

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = "LDAP://OU=SharePoint,OU=Special Accounts,DC=domain,DC=com"
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"

$colProplist = "sAMAccountName","name","msDS-AllowedToDelegateTo","servicePrincipalName"

foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults) {
    #$objResult.Properties
    $objResult.Properties["name"]
    $objResult.Properties["samaccountname"]
    "================================================"
    "msDS-AllowedToDelegateTo"
    "------------------------------------------------"
    $objResult.Properties["msds-allowedtodelegateto"]
    "------------------------------------------------"
    "servicePrincipalName"
    "------------------------------------------------"
    $objResult.Properties["serviceprincipalname"]
    ""
    ""
}