SPSTCDC 2011 Recap

It was a privilege to attend and be part of SharePoint Saturday-The Conference last week. I am always humbled by how much I have yet to learn about this dynamic and exciting platform. As a developer by trade, I made a point to branch out and try to learn as much as I possibly could on the administrative side of things (while staying true to my developer roots and attending a few developer sessions as well). I also got to take part in a blogging project in conjunction with the conference for Engage in SharePoint. I have listed the sessions I attended during the conference with some brief thoughts on each below. Where I contributed a blog post for Engage in SharePoint for a particular session, I have linked to that post as well.

Day 1 – Thursday, August 11

On Thursday, I attended the all-day workshop on SharePoint and Windows Azure Development. Sahil Malik and Girish Raja really know their stuff and deliver their knowledge in a very compelling manner. Although I don’t currently get to do much “in the cloud” for my current job, I am hopeful to leverage this platform a lot more in the future.

SUGDC – Thursday night

Thursday evening, I presented a session on Claims-Based Identity in SharePoint 2010 at the SharePoint Users Group of Washington, DC, which held their August meeting at the conference venue. I want to extend my sincere thanks to everyone who stayed around to watch and ask questions during my presentation. For those who were unable to attend, here are my slides:

Day 2 – Friday, August 12

Session 1 – My first session was Setting up Kerberos configuration in a SharePoint farm with L. Carlos Rodriguez. Carlos really knows his stuff and delivered an energetic, knowledgeable, and lively discussion of the trials and tribulations of setting up Kerberos. I really enjoyed this session and wish it could have been a half or full-day workshop to give this subject the depth of attention it deserves.

Session 2 – The second session I attended was Accelerate Your SharePoint Development & Testing, led by my good friends Chris Riley and Zvi Guterman at CloudShare. I have been a fan of CloudShare for a couple months now, and after this presentation, I’m even more psyched about what the future holds. I’m sure there will be many more posts on this blog showing off the cool new things I can do with CloudShare in the future.

Session 3 – After lunch, I attended Mike Oryszak’s session on Getting the Most from User Profiles. Mike provided some great information about user profiles in SharePoint 2010 along with some valuable tips on how best to manage custom attributes and the synchronization of profile attributes with other line-of-business systems.

Session 4 – The next session I attended was Liam Cleary’s Are you who you say you are? SharePoint Authentication and Authorization. Liam is a rock star who really knows his stuff. The knowledge I gained about Claims-Based Identity and Trusted Identity Providers will greatly improve any future presentations I give on the subject.

Session 5 – My final session of the day was Beyond Approval: Intro to Creating Custom Workflow Actions with Ben Jones. Ben showed us just how easy it really is to define, implement, and deploy custom workflow actions that can be leveraged by end users in defining SharePoint Designer workflows. This is sure to be a time saver for a lot of developers out there!

Of course, no discussion of Friday would be complete without a discussion of SharePoint Got Talent. A big thank you to my friends who stuck around to watch me perform, and thanks to everyone who voted for me. A big congratulations to Marcy Kellar, the winner, and Tiffany Songvilay, the runner-up. Videos of most of the evening’s thoroughly entertaining performances (including my own) can be found here.

Day 3 – Saturday, August 13

Session 1 – My first session was Business Connectivity Services Explained by Example with Kirk Evans. Kirk blew our collective minds when he told us that using the native SQL Server method of connecting to SQL Server data was not the best approach. I will be following Kirk’s advice and using WCF services or .NET types from now on!

Session 2 – The next session I attended was Integrating SSRS 2008R2 with SharePoint 2010 with Kevin S. Goff. Kevin provided a lot of great insight on how to set up and configure SQL Server Reporting Services 2008 R2 with SharePoint 2010 and gave some very cool demos. I will definitely be setting this up in my development environment soon.

Session 3 – After lunch, I attended a great deep dive session called SharePoint Federation: Leveraging ADFSv2 and Claims Based Authentication to integrate with Partners with Pirooz Javan. Pirooz led a great discussion with a very engaged audience. I gained a lot of valuable real-world perspective from the many relevant questions asked by folks who are leveraging these technologies in the real world every day.

Session 4 – The next session I attended was Becky Isserman’s Epic SharePoint Battle: HTML 5 vs. Silverlight 5. Besides the awesome free mustache and candy, I learned a lot about the state-of-the-art with current browsers and two emerging technologies: HTML 5 and Silverlight 5 (currently in beta). Walking in to this session, I would have thought Silverlight stood no chance, but after seeing Becky’s demos and hearing her perspective, I’m not ready to write Silverlight off just yet.

Session 5 – The final session I attended was Johnathan Lightfoot’s So You Want Your Name in Print. I have gone back and forth in my own mind about whether I would ever want to invest the time and effort to become a published author in the SharePoint world. Johnathan provided tons of valuable advice from his own experiences as an author that has given me a lot more insight into the process of writing and publishing a book. It will certainly help influence any decisions I make about becoming an author in the future.

Summary

The conference was an outstanding experience overall. I cannot say enough great things about all the volunteers who worked to make my experience such a great one. As I tweeted on Saturday morning, I got a $1,300 conference experience for 3% of the price.

A Checklist for New Forms-Based Authentication Users in SharePoint 2010

In recent weeks, I have done a fair amount of analysis and testing of various Claims-Based Identity scenarios in SharePoint 2010. One of these scenarios involves a web application configured to use Forms-Based Authentication (FBA obviously requires the use of Claims in SharePoint 2010) that is tied to a custom membership provider. The membership provider is quite simple, storing user IDs and passwords in a table within a SQL Server database (in plain text, so please don’t do this in production!) The solution was initially developed in MOSS 2007 and then migrated to SharePoint 2010. I have not yet performed a Visual Upgrade, which is why my screenshots still look “MOSS-y.”

There are numerous primers out there that explain how to handle the migration of existing FBA users to their Claims-based counterparts in SharePoint 2010, but what happens when you add new users to the custom membership database after the migration? Does everything go smoothly? In my experience, there are a few steps you should always perform to ensure all new users added to the membership database have the end-user experience you would expect.

First, I will create a new user and show you what may happen if you take no further action.

Step 1: Create the New User

This procedure will vary based on your custom membership provider. In this example, I will create the user example in my database table with an equally secure password (again, please don’t do this in production!)

What if I did nothing further at this point? Should the user example be able to log in to the FBA-protected site if he or she has not been explicitly granted any access (and when “All Authenticated Users” has not been granted any level of access to the site)? The answer may surprise you…

I’m in!

We’ll deal with this little bit of nonsense (the ugly Claims-encoded welcome name for the new user) in a minute. By the way, does anyone else find it amusing that the last two characters of the user’s display name are dropped in favor of a three character ellipsis (…)?

What’s even “better” is that example can click “View All Site Content” and navigate to all the lists and libraries within the site.

This does not seem like the behavior we would expect to see. How can we clean things up?

Step 2: Create an SPUser Object for the New User

In my initial quest to learn why a new FBA-user’s welcome name is always in Claims-encoded format, I stumbled upon Tyler Holmes’ excellent blog post entitled Awkward Usernames Courtesy of Claims Authentication (FBA). This led me to realize that I needed to update the DisplayName property of the SPUser object associated with the new user. Unfortunately, when I tried to run the PowerShell cmdlet Tyler provides, I found out that my new user doesn’t even have an associated SPUser object yet!


To create this object for my new FBA user, I run the following cmdlet:

New-SPUser -Web http://abc.shrpnt.loc -UserAlias “i:0#.f|abcmembershipprovider|example”


Before I run Tyler’s cmdlet to set the DisplayName for my SPUser to a friendlier value (although I now see example as the user’s name rather than its Claims-encoded equivalent), I thought I’d try logging in as example again to see if having an SPUser object for my new user makes a difference.

Access Denied?! But all I did was create a security principal (SPUser) for my new FBA user, I didn’t change any permissions…

Naturally this is the behavior one would expect to see when a new user is created and has not yet granted access to any resources. It’s a new FBA user (without a security principal)’s ability to have reader access across a site that has me more troubled.

Step 3: Grant the New User the Appropriate Level of Access

Unless you have assigned “All Authenticated Users” with a certain level of access to the site, you will experience the Access Denied error shown above. Just as in any other SharePoint deployment, a user with the appropriate level of access should assign the new user (either through a SharePoint group or directly) the permissions he or she will need on the site.

After this has been done, example is able to log in to the site once again. As an added bonus, example‘s welcome name at the top right of the page is no longer in Claims-encoded format.

Step 4: Set the New User’s DisplayName Value

When I created the user example in Step 1, I gave the user a name of Example User. I can run the following in PowerShell to set the user’s display name accordingly:

$user = Get-SPUser -Web http://abc.shrpnt.loc -Identity “i:0#.f|abcmembershipprovider|example”
$user.DisplayName = “Example User”
$user.Update()


This step is absolutely necessary if you do not use LDAP or BCS to map user profile properties to your custom membership provider’s data store. (Conversely, if you do use LDAP or BCS and have user profile synchronization configured, the value you set in this step will be overwritten the next time profile synchronization occurs.)

Now when example logs in, we see the new welcome name.

It’s worth noting that nothing within the infrastructure of Claims itself has anything to do with the user’s welcome name or how it is displayed. In fact, using the Claims Viewer Web Part, we can see that the information contained within example‘s Claim looks exactly the same as it did before example had an associated SPUser object. The display name we just set is not contained within the user’s Claim; it is only maintained within the SPUser object.

Conclusion

By following the above steps each time a new user is created, you guarantee consistency with each new user’s ability to access the site (and not have read access to all site content by default if this is not the desired behavior) and how the new user’s name is displayed. I strongly encourage you to automate this process using PowerShell or the object model if you need to create a lot of new users.

Have any questions, comments, or ideas you want to share? Feel free to post them in the comments below. If you will be at #SPSTCDC next month, feel free to come to my presentation on Claims-Based Identity at the August 11 meeting of the SharePoint User Group of Washington, DC. The meeting begins at 6:00 p.m.

Which SharePoint Front End Server Am I Hitting?

If you have ever worked in a network load balanced (NLB) environment with multiple SharePoint front end servers, you have no doubt had at least one occasion where only some of your users were seeing some sort of strange behavior. Perhaps some users receive a generic error message when accessing a page and others do not. Whatever the reason, it never hurts to be able to have users give you just a little bit more information to help you in the troubleshooting process.

Of course, you can always dig through the ULS log files on each front end server to look for any anomalies or to match up correlation ID values associated with generic error messages. But wouldn’t it be great if your end user could tell you that he or she is hitting front end #3 so you don’t have to waste time searching through the logs on front ends #1 and #2 first?

One potential solution to this problem (and there are no doubt more elegant ways to solve it) are to create multiple images such as the ones below:

Save each image with exactly the same name (such as frontend.jpg) and place it in the TEMPLATE\IMAGES directory of the SharePoint root on each front end (make sure you match up the correct image with each front end server!) Then, when something goes wrong for one user but not another, you can ask him/her to visit the following URL:

http://yourcompany.com/_layouts/images/frontend.jpg

Based on the number that appears, you will know exactly which front end that user is hitting!

I hope this information is useful to you. You could extend this by creating a custom URL action called “Front End Check” that allows certain users to hit the front end image link directly without having to remember it. Feel free to leave your thoughts and suggestions in the comments!

Using CloudShare to Set Up a MOSS to SharePoint 2010 Migration Environment

I have been using CloudShare for a little over a week now and have found it to be a convenient, cost-effective way to provision virtual environments to suit my development and testing needs. The time and money CloudShare saves me over having to procure the necessary hardware and software and install operating systems and applications myself has been HUGE. I can have a brand new server up and running, pre-configured with all the applications I need in a matter of minutes. I have also been very impressed with how quickly the machines come back up after a reboot. In spite of all these great things, CloudShare is a little light in the area of “how-to” documentation and their user support forums do not appear to be very active.

My primary objective at the moment is to use CloudShare to test various MOSS to SharePoint 2010 migration scenarios, particularly with respect to Claims authentication and the numerous problems users have encountered upgrading to Claims-based web applications in SharePoint 2010 (stay tuned for some blog posts about these problems in the future). In order to adequately test these out, I need a single domain with the same set of users and groups to test various pre- and post-upgrade scenarios.

In order to create this environment, I knew I needed to follow these basic steps:

  1. Provision and configure a MOSS environment. For this, I set up a “SharePoint 2007″ CloudShare machine which in addition to giving me MOSS, also took care of creating the domain shrpnt.loc on which I will ultimately be configuring a new SharePoint 2010 instance. On this machine, I have set up a number of different web applications including one with Forms-Based Authentication (FBA) tied to a custom authentication provider. I will also create a new SQL Server instance on this machine to host my SharePoint 2010 configuration and content databases.
  2. Once the MOSS environment was complete, detach my MOSS content databases. To fully replicate the issues I have seen in various production environments, I wanted to use the “database attach” upgrade method described in detail here.
  3. Create a new SharePoint 2010 farm on a new server on the same domain. Here is where things with CloudShare get tricky. They have plenty of pre-configured SharePoint 2010 virtual machines available, but all of them are already joined to a domain (obviously a different domain than the one that would be set up in my initial MOSS environment). I’ll describe how I work around this shortly.
  4. Attach the new content databases in the SharePoint 2010 farm. After running the Mount-SPContentDatabase PowerShell command, this will automatically upgrade them to SharePoint 2010. From here, I am good to go and can continue with my testing.

As much as I would have loved to see a “Windows Server 2008 R2 Enterprise 64-bit with SQL Server and SharePoint 2010 install media available” option, CloudShare has no such offering. The next best thing, I assumed, was to take their “SharePoint 2010 (Clean Install)” VM and do the following:

  1. Run dcpromo to remove Active Directory Domain Services from the machine, effectively un-joining it from its domain. After restarting, I also removed the “Active Directory Domain Services” and “DNS Server” roles from the server.
  2. Join the machine to the existing shrpnt.loc domain by performing the following steps:
    1. Add the IP address of the shrpnt.loc domain controller as the primary DNS server on the VM I want to join to that domain.
    2. On the new VM, join it to the shrpnt.loc domain using the domain administrator credentials from the shrpnt.loc domain.
    3. Restart the new VM and enjoy being able to leverage the users and groups defined on the shrpnt.loc domain.

    NOTE: After doing this, CloudShare needs you to hold its hand a little bit to let it know about the “new” domain to which you just joined the SharePoint 2010 VM. If you use the browser-based client to access your servers and do not make this change, it will attempt to log you in with an account that is no longer valid. This value can be set by going to “Edit domains” under “Edit Environment.”

  3. After another restart, run the SharePoint 2010 Products Configuration Wizard. When it errors out trying to find the original farm, choose to disconnect the server from the existing farm.
  4. Re-run the SharePoint 2010 Products Configuration Wizard, this time telling it to create a new server farm.

After completing this step, I now have a fresh SharePoint 2010 farm from which I can begin my migration testing. I wish CloudShare had some way to allow users to perform fresh installs of SQL Server and SharePoint 2010 on a Windows Server box without a pre-configured domain VM, but until they do, I believe this is an adequate workaround.

Please post any suggestions for improvements or enhancements to this process in the comments. Thanks!

Connecting Word 2010 to WordPress: be sure to enable XML-RPC!

This morning, I thought I would try to take advantage of the ability to publish blog posts to WordPress directly from Microsoft Word 2010. There are numerous posts out there (such as this one) that explain the basics of connecting Word 2010 to WordPress, and to be fair the process is quite simple.

Unfortunately, when I initially tried to connect to my hosted WordPress instance, I received a “helpful” error message:

Clicking “More Information” brought up a “Help with blogging in Word” page that didn’t directly address my problem, but jogged my memory just enough to clue me in. I hadn’t enabled XML-RPC from my WordPress Writing Settings (under Remote Publishing)!

After enabling XML-RPC, I was good to go (as evidenced by your ability to see this post)!

My initial thoughts about this capability:

  • I like being able to use Word as a platform for composing and editing posts.
  • I really like using Word to paste and crop screenshots, then letting Word manage the upload and linking of the images automatically within my posts.
  • I was able to easily open posts I had previously published via the browser-based WordPress interface, and save for some minor formatting issues (e.g., missing line breaks), everything came over perfectly into Word.
  • I could not readily find a place to tag my posts in the Word interface. This is a small drawback.
  • I got ambitious and tried to superimpose a shape over an image. Word treated these as two separate images and inserted a line break between them. It was worth a shot.
  • I wish credentials didn’t have to be sent in the clear to take advantage of this capability, and I expect this could be a show-stopper for many users. I suppose I will have to change my password often (be sure to update the account within Word after you do that).

If you have Office 2010 and enjoy using Word as an authoring platform, I highly recommend giving this capability a try!

No Inline Editing on a Styled List View? Say it ain’t so!

Most everyone is aware of the new inline editing capabilities offered by SharePoint 2010 in list views. If not, just know that in the Edit View page for a given list, you can expand the “Inline Editing” section and check a box to enable it:

Allow inline editing

Checking this box will provide a streamlined list editing experience. Simply hover over a row in the list and an “Edit” icon will appear to the left of the row:

Inline editing hover

Clicking the “Edit” icon will allow you to modify values for any editable field in the list item (e.g., NOT “Created By” or “Modified” if they are in your list view, but most everything else):

Inline editing experience

You can click the “Save” icon to update your changes to the item, or the “Close” icon to discard your changes. Pretty neat, huh?

Well, what if you are like me (or my friend Laura Rogers of SharePoint911) and you like your list views styled a little bit? Perhaps just a little alternate row shading to break up the monotony of a white canvas filled with gray text? Sadly, there is a cautionary note at the end of the description of Inline Editing that will break your heart (especially if you didn’t take the time to read it when you enabled the setting): “Inline editing is only available on views that have their Style set to Default.

This makes no sense to me, but if you apply any other style to the list (even when that style makes the simplest of cosmetic changes, as is the case with “Basic Table” or “Shaded”), you really do lose the ability to perform inline editing on the list. Here is the full list of style options and some proof that the ability to perform inline editing with those styles applied is gone:

List view style

Shaded:

No inline editing

Basic Table:

I don’t think I’m quite done with this one yet. In a future post, I will explore ways that we can (hopefully) take advantage of CSS to style our list views in such a way that we can keep the list view style as “Default” as far as SharePoint is concerned, but give our lists a little more style and flavor while preserving the ability to do inline editing.

Stay tuned!

Configuring a Birthday View in SharePoint using a [Today] filter

I was intrigued by a recent post on the Microsoft TechNet forums where the poster outlined the following scenario:

  • Employee information is maintained in a SharePoint list. The information includes each employee’s date of birth in a “Date and Time (Date Only)” field.
  • They would like to have a “Birthdays” view where they can display a list of employees whose birthday is today (i.e., using the [Today] filter on the list).
  • Problem #1: There are some privacy concerns about displaying an employee’s year of birth, and therefore his/her age to everyone.
  • Problem #2: The [Today] filter will not match if the year component of the date value does not equal the current year.

In one sense, I was glad that problems 1 and 2 both existed, because problem 1 led me to a solution that addresses problem 2.

My Proposed Solution

Algorithm: Think of the “Birthday” field as an “Actual Date of the Employee’s Next Birthday” field. This will mitigate both problems outlined above by no longer storing the employee’s year of birth in the list (we’ll assume that HR maintains and protects this data somewhere else) and allowing us to use a [Today] filter to show everyone who has a birthday today.

Solving this problem involves two components: one that initially updates all the Birthday values in the list with the current year or next year as the year component of the date (based on whether or not the employee’s birthday has already occurred this year), then one that updates the list daily to account for the previous day’s birthdays by updating the year component of those date values to next year.

Solution Part 1: Iterate through all items in the list (this will only need to be done once). For each item, based on the month and day component of the item’s “Birthday” value, update the year component to equal this year or next year based on whether the birthday has already occurred this year.

foreach (SPListItem item in birthdayList.Items)
{
  DateTime dtBirthday = DateTime.Parse(item["Birthday"].ToString());
  // Compare month and day components to the same month and day this year
  //  to determine if the birthday has already occurred this year
  DateTime dtBirthdayThisYear = new DateTime(DateTime.Now.Year, dtBirthday.Month, dtBirthday.Day);
  if (dtBirthdayThisYear.CompareTo(DateTime.Now) < 0)
  {
    // The birthday has already occurred, set the field to next year
    item["Birthday"] = new DateTime(DateTime.Now.Year + 1, dtBirthday.Month, dtBirthday.Day);
  }
  else
  {
    // Set the birthday field to this year
    item["Birthday"] = dtBirthdayThisYear;
  }

  item.SystemUpdate();
}

Solution Part 2: Query the list daily for all the birthdays that took place yesterday. Update each matching employee item’s birthday value to reflect his/her next birthday as taking place next year.

SPField birthdayField = birthdayList.Fields["Birthday"];
DateTime dtYesterday = DateTime.Today.AddDays(-1);
SPQuery query = new SPQuery();
query.Query = "<Where><Eq><FieldRef Name='" + birthdayField.InternalName + "' />" +
"<Value Type='DateTime' IncludeTimeValue='False'>" + SPUtility.CreateISO8601DateTimeFromSystemDateTime(dtYesterday) +
"</Value></Eq></Where>";

foreach (SPListItem item in birthdayList.GetItems(query))
{
  DateTime dtBirthday = DateTime.Parse(item["Birthday"].ToString());
  item["Birthday"] = new DateTime(DateTime.Now.Year + 1, dtBirthday.Month, dtBirthday.Day);
  item.SystemUpdate();
}

Some Notes on Deployment, Exception handling, etc.: For the sake of clarity and brevity, my code excerpts above do not include appropriate exception handling. You should always include this in your code. Likewise, I have not addressed some higher-level architectural considerations such as whether to deploy Solution Part 2 as a timer job, or a console application that runs as a scheduled task on the server, or something else entirely. I will discuss the relative merits of each of these approaches in a later post. For now, feel free to leave ideas and suggestions in the comments. Thanks!