Microsoft

Blog Categories

Subscribe to RSS feed

Archives

Follow our Microsoft Technologies board on Pinterest

Posts by this author: RSS

Clean Up Customized CSS Files with CSSCompare

Have you ever come across a SharePoint installation that’s been customized in an unsupported way? You look at the 12 (or 14) hive and see that files have been modified by hand? Not good.
 
As you may know, changing core SharePoint files is unsupported and can lead to problems when patching.
 
The best way to clean up modified SharePoint installations is to pull out the customizations and move them into new files as part of a solution package (WSP file). That makes it easy to re-deploy customizations and ensures your environment will stay clean.
 
Re-packaging most files is easy, but CSS can be very tricky to pull out the customizations. What if somebody went in and modified a few random styles (e.g. changing a color attribute or border width). Tracking those down by hand is tedious and error-prone.
 
 
For situations like these, I wrote a tool called CSSCompare which is hosted on CodePlex. CSSCompare will look at two CSS files and output the effective differences between them.
 
With SharePoint, you can take your customized version of Core.css (or other customized CSS file) and find the differential from an uncustomized version of Core.css by running:
 
CSSCompare.css -v1 CustomizedCore.css -v2 OriginalCore.css > MyCustomStyles.css
 
You can then add “MyCustomStyles.css” to your solution and replace your customized file with its original version.
 
Other Uses
 
CSSCompare works with any CSS files, so it can be used in non-SharePoint scenarios as well. I’ve started using it in version control situations to quickly determine changes between styles.

SharePoint Change Management: A Checklist

SharePoint deployments succeed or fail based on adoption and adherence to business goals, not technical functionality. It doesn’t matter how pretty your SharePoint site is or how many features you pack in. Perception is reality, and if people don’t perceive value, it’s failed.
 
Along those lines, communications planning is paramount for winning hearts and minds. Whether deploying a small upgrade or embarking on a transformational change from another system, engaging end-users early and throughout is the most important ingredient of success.
 
With that in mind, I’d like to offer a checklist of topics to consider during any SharePoint project. There are more comprehensive guides available (I particularly recommend “Essential SharePoint 2010″), but this primer should get you on the right track. I’ve mapped the steps to Prosci‘s “ADKAR® Model”, a goal-oriented framework for Organizational Change Management. If your business has an OCM framework, the same steps should apply regardless; if not, I recommend ADKAR as a starting point.
  1. Gaining Awareness
    1. Designate an “Awareness Team” of all impacted business users
    2. Catalog potential objections to change
    3. Discuss project objectives with Awareness Team
    4. Review key SharePoint workloads with Awareness Team
    5. Recruit a “Design Team” for interested parties to share input
  2. Driving Desire
    1. Communicate outcome benefits to all stakeholders via multiple channels
    2. Provide targeted demos to Awareness Team
    3. Solicit feedback via focus groups with Design Team
  3. Spreading Knowledge
    1. Train SharePoint IT operations teams
    2. Educate end-users via one or more channels:
      1. Videos
      2. Classroom training
      3. Training manuals
      4. Wikis / knowledge bases
      5. Power user groups / communities
  4. Fostering Ability
    1. Deploy SharePoint solution
    2. Proactively check in with affected users
  5. Ensuring Reinforcement
    1. Enact governance plan
    2. Incorporate SharePoint training into onboarding training plans
    3. Require training before receiving sites / administrative rights
    4. Regularly survey for feedback
    5. Foster Power user groups / communities
    6. Start small; focus on quick wins

#SPC11: Day 2

The SharePoint Conference is in full swing! Despite a groggy start for some attendees (thanks to AvePoint‘s late-night “Red Party”), Tuesday continued the great stream of content.
 
While a peek at the next version will have to wait until at least SharePoint Conference 2012, excitement and innovation around SharePoint 2010 are still in vast supply.
 
Six Key Themes from SharePoint Conference 2011
 
I’ve attended a mix of sessions focusing on IT, business, and development and six common themes have stood out:
  • The Cloud- Office 365 and Azure are everywhere at SPC. We heard during yesterday’s keynote that over 50,000 organizations are already paying subscribers to Office 365. It seems like every session I attend has people asking “how does this fit into our SharePoint Online” strategy?Andrew Connell demonstrated Azure playing nicely with Office 365 and I was blown away by the speed. As Andrew pointed out, both services operate in the same data centers, so integrations feel native. There have been plenty of hints, both subtle and not, that knowing Azure is going to be increasingly important in the world of SharePoint.

    The most exciting news for me so far is that Office 365 will support external BCS connections by the end of the year. That opens a lot of doors.

  • Mobile- Guess what the first mobile device shown during the SharePoint Conference’s keynote. An iPad. Yes, Microsoft acknowledges the reality of IT consumerization and the mobile seems to be everywhere at SPC11.In addition to the tablets I see open to Twitter at every session, the community keeps asking “yeah, but does it work on mobile”? The answer with SharePoint isn’t always yes, but it’s clear that Microsoft and the ecosystem are working hard to bridge the gap.
  • HTML5 and Standards- Is Silverlight dead? I think saying so is a bit premature, but the new belle at the ball is definitely HTML5. As Ted Pattison demonstrated today, HTML5 with a bit of jQuery can be as beautiful and functional as any proprietary app.Along with HTML5, a few other standards keep popping up. Know OData? How about JSONP? If you’re a developer, you should.
  • Enterprise Search- As a huge fan of FAST Search, I’m delighted to find that it’s everywhere at SPC11. At the keynote yesterday, we saw FAST return results from tens of millions of documents in <0.2 seconds. We’ve since witnessed SharePoint and FAST used to slice and dice every kind of data possible, including video.Amongst all the types of sessions at the SharePoint Conference, I love the real-world client debriefs most. EA showed off one of the most impressive intranets out there and search is integral to every step of the experience.
  • Social- A number that’s been thrown around a few times is that over 60% of SharePoint deployments include social networking. The implications of that are amazing. At SPC11, we continually hear about empowering users to collaborate, self-service, and organize content in relevant ways. Adoption and education are tricky, but several sessions on change management have rounded out the technical components.Every time I glance an attendee’s screen, people seem to be tabbed to Twitter, Facebook, and LinkedIn. On two occasions, I even saw people posting away on their internal NewsGator streams.
  • Governance- In many ways, SPC11 reflects a giant leap in maturity for SharePoint. While other conferences sometimes get swept up in features and technology, it’s refreshing to hear the word “governance” all throughout the SharePoint Conference. Some great sessions have tackled governance plans, compliance, and building the perfect SharePoint team.My favorite takeaway may be from Dan Holme’s session this afternoon:

    “Don’t train your employees to use SharePoint. Train them to do their jobs.”

Great conference. If you’re around, please say hello.

Oh, and SharePoint Conference 2012? November 12-15, 2012 at Mandalay Bay in Las Vegas. Can’t wait!

Redirecting to the right SharePoint page following UAG authentication

Here’s the scenario:
  • You publish SharePoint content using UAG
  • Users want to share links via email/IM
  • When the recipient clicks your link, they’re prompted to log in
  • After authenticating, they’re redirected to your SharePoint homepage instead of the original link

The reason for this is that UAG only has one <FORM/> action target that is set to your homepage.

The good news is that UAG keeps your original link in its ‘orig_url‘ parameter. We can use Javascript in SharePoint to look at the referring URL and redirect automatically.

To do so, simply add this Javascript to the <HEAD/> of your master page:

<script>

var origURLPos = document.referrer.indexOf(‘&orig_url=’);

if (origURLPos > -1){

var url = unescape(document.referrer.substr(origURLPos + 10));

location.replace(url);

}

</script>

Delete All Old Versions from SharePoint 2010 Document Libraries

How many versions of a typical document do you need to keep? 5? 10? 100?
 
SharePoint content databases often get cluttered with redundant versions of the same documents. In some cases, I’ve seen presentation libraries with less than 10 GB of active content, but hundreds of GBs of content due to gradual changes.
 
If you’re ready to clear out old versions, SharePoint 2010’s Management Shell makes it easy. The script below will iterate through all lists and update them to keep only the last 2 copies. It will also loop through and delete unneeded versions.
 
Get-SPWebApplication|Get-SPSite-Limit All|Get-SPWeb-Limit All|ForEach-Object{ForEach($listin$_.Lists){If($list.EnableVersioning-eq $true){$list.MajorVersionLimit=2;$list.Update();ForEach($itemin$list.Items){$item.URL;$item.SystemUpdate()}}}}
 
You can see that it…
  1. Loops through all web applications
  2. Loops through their site collections
  3. Loops through their webs
  4. Loops through their lists
  5. If versioning’s enabled, it sets the major version limit to 2
  6. In order to remove old versions, it needs to loop through each item and perform a system update

The script can be easily amended to deal with only specific site collections / libraries. To keep a different number of versions, modify the MajorVersionLimit variable above.

Adding Flash Content to SharePoint 2010 / Office 365

SharePoint 2010’s rich text editors make it pretty easy to format text and insert media, but they also make it difficult to embed Flash content. In order to streamline the HTML generated by the Content Editor Web Part and other edit boxes, Microsoft decided to automatically remove non-essential tags. Any time we try to embed a Flash file or other add-in that uses an <OBJECT/> tag, SharePoint removes it upon being saved.
 
So how do we add Flash to a SharePoint page? The trick is to use the Content Editor Web Part’s “Content Link” functionality.
 
In SharePoint 2010, we can tell the Content Editor Web Part to show data from a file in one of our document libraries. That’s a nice feature because we can define HTML centrally and reference it in many places, allowing for changes to scale everywhere.
 
Best of all, files that we upload to a document library aren’t processed at all, so our <OBJECT/> tags won’t be escaped. The process of adding Flash to a SharePoint web part page then becomes easy:
  1. Create a minimal HTML file containing just your Flash reference. Make sure that the path to the SWF file reflects the document library where you’ll upload it to.For example:

     

    <object classid=”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″
    codebase=http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0
    width=”1024″ height=”768″>
    <param name=”movie” value=”/SiteName/DocumentLibraryName/FlashFileName.swf“/>
    <param name=”quality” value=”high”/>
    <embed src=”/SiteName/DocumentLibraryName/FlashFileName.swf” quality=”high”
    pluginspage=”http://www.macromedia.com/go/getflashplayer” type=”application/x-shockwave-flash”
    width=”1024″ height=”768″></embed></object>
  2. Upload this HTML file along with your SWF file to the document library corresponding to the bolded text in step 1.
  3. On the page where you want to add your Flash content, add a Content Editor Web Part. Click “Edit Web Part”. Under web part properties, enter the relative path to your HTML file in the “Content Link” property” and save.

Edit: As Ram Gopinathan pointed out on Twitter, there are many upsides to using the Content Link web part. Perhaps most importantly we can then version page content. One caution is that it adds an extra step to rendering your page.

SharePoint Saturday Chicago Slides

Last month, I had the distinct honor of speaking at SharePoint Saturday Chicago. Kudos to the organizers for putting on another great event.
 
Here are slides from the two sessions I presented:
 
 
 
Office 365 Deployment Strategies
 
Moving to Office 365 provides the perfect opportunity to clean house and get SharePoint back on track. Whether starting fresh or migrating existing sites, early planning will facilitate long-term success in the cloud. This session will explore deployment decisions, migration options, and governance strategies to get the most out of SharePoint Online.
 
 
Securing the SharePoint Platform
 
As SharePoint adoption continues to grow, so do the number of threats against it. Whether used as an intranet, a public-facing website or a point solution, securing SharePoint is critical. This session will go beyond permissions to examine the entire attack surface of SharePoint 2007 and 2010. Real-world strategies will be provided for mitigating risk.
 
Upcoming Events
 
I’ll also be presenting on Office 365 at a few upcoming events. I hope to see you there:

Conditional logic in InfoPath

I consider InfoPath Forms Services to be one of the most underrated features of SharePoint. When combined with workflows, InfoPath allows us to streamline most day-to-day tasks. Sometimes that takes a little creativity…
A scenario that I’ve run into a few times now is trying to find the first non-null value from a given set of fields. Most recently, I created a production log in InfoPath where each row represented an hour’s worth of parts successfully produced. I wanted to be able to report on the most recent hour’s production (similar to SQL’s COALESCE statement), but there’s no obvious way to do that.
In most systems, we’d use some form of "if", "while", "switch" or other conditional statements. For InfoPath actions, validation, and formattion rules, most functions are geared around math or string manipulation.
A workaround
It turns out that we can create conditional logic in InfoPath through a combination of the string-length() function, multiplication, and number comparisons.
A warning: this approach definitely isn’t pretty, but it works.
The crux of this trick is that comparisons return boolean values but booleans can be cast to strings. That means that a statement like "1 > 0" returns "true" while "1 < 0" returns "false". We can then take a logical comparison’s output and wrap it with the string-length() function. That gives either 4 or 5 (for the lengths of "true" or "false"). We can then use those values to determine which value to return.
An example of how we’d handle conditional logic in most languages:

if (value1 > value2)

output = value1;

else

output = value2;

In InfoPath, we can instead do:
(5 - string-length(value1 > value2)) * value1 + (5 - string-length(value1 <= value2)) * value2

If the first string length will be 4 for "true" and 5 – 4 = 1, the first multiplication returns value1. If the second string length will be 5 for "false" and 5 – 5 = 0, the second multiplication will return value2.

Conditional logic in action

I applied this approach to the production form mentioned above. Employees would enter their hourly production and the latest hour’s data would be promoted to a promoted field for SharePoint reporting.

The code ended up like this:

../my:goodParts16 + (string-length(../my:goodParts16 > 0 or ../my:badParts16 > 0) - 4) *(../my:goodParts15 + (string-length(../my:goodParts15 > 0 or ../my:badParts15 > 0) - 4) *(../my:goodParts14 + (string-length(../my:goodParts14 > 0 or ../my:badParts14 > 0) - 4) *(../my:goodParts13 + (string-length(../my:goodParts13 > 0 or ../my:badParts13 > 0) - 4) *(../my:goodParts12 + (string-length(../my:goodParts12 > 0 or ../my:badParts12 > 0) - 4) *(../my:goodParts11 + (string-length(../my:goodParts11 > 0 or ../my:badParts11 > 0) - 4) *(../my:goodParts10 + (string-length(../my:goodParts10 > 0 or ../my:badParts10 > 0) - 4) *(../my:goodParts9 + (string-length(../my:goodParts9 > 0 or ../my:badParts9 > 0) - 4))))))))

As can be seen, the code piles up quickly but it works. If the user has entered data for the 4:00pm hour, that branch will show. Otherwise, it will check for 3:00pm, then 2:00pm, etc.

Attached is an example InfoPath form template demonstrating this approach. After downloading the file, remove the ".rename" extension from its name.

  • InfoPath form template with conditional logic

Upcoming SharePoint Events

My favorite thing about SharePoint is its friendly and vibrant community. Having already attended a few fantastic conferences this year, including yesterday’s standout SharePoint Saturday in Twin Cities yesterday, I’m excited about the slew of other events coming up. 2011 is a huge year for SharePoint.
I’m planning to attend:
  1. April 25-27: SharePoint Connections Coast to Coast Boston – I’ll be presenting on "Customizing SharePoint Online"
  2. April 30: SharePoint Saturday St. Louis – I’ll be presenting on "Securing the SharePoint Platform"
  3. May 14: SharePoint Saturday Michigan
  4. Late Spring: SharePoint Saturday Chicago (Suburbs)
  5. July 27: SharePoint Fest Chicago
  6. August 8-10: SharePoint Connections Coast to Coast Chicago – I’ll be presenting on "Customizing SharePoint Online"
  7. October 3-6: SharePoint Conference 2011 in Anaheim
  8. Late Fall: SharePoint Saturday Chicago (City)
The easiest way to keep up to date with SharePoint events is via the SharePoint Community Calendar.
I encourage you to attend these if events you can. Please come say hi.

Randomize SharePoint List Items

Challenge
 
You have to show items from a SharePoint list in a random order. Maybe it’s a subset of data (or just one item). Maybe it’s everything, just returned in a random order.
 
Approach
 
You may think .NET code is necessary to make that work, but there’s a much easier approach. SharePoint’s decoupling of list items from their presentation allows us to present arbitrary data in any format we want.
 
The approach outlined here relies on eXtensible Stylesheet Language Transformations (XSLT) to format aggregated data.
 
 
Several SharePoint web parts allow results to be styled with XSLT, including:
  1. Content Query Web Part
  2. Data View Web Part
  3. Search Core Results Web Part
From Scratch
 
If you’re starting from a blank slate, the first step is to decide which web part to use for aggregating list items.
 
When To Use a Content Query Web Part
 
If you need to “roll up” content spread across multiple lists or webs, the CQWP is the easiest path to do so. It provides a straightforward UI for selecting your list(s), content type(s), web(s), and filtering criteria. On the downside, CQWPs are more difficult to style and rely on modifying other files including ItemStyle.xsl and Header.xsl.
 
When To Use a Data View Web Part
 
If you only need to show data from one list and SharePoint Designer is installed, the DVWP is easiest to style. Joining data from multiple locations is complicated, but SharePoint Designer makes editing and previewing XSLT easiest.
 
Decide carefully between the two options.
  1. For guidance in setting up a Content Query Web Part, see this guide from Heather Solomon.
  2. For guidance setting up a Data View Web Part, see this guide by Laura Rogers.
The important consideration for this guide is to return all list items that will selectable for our randomizer (the corpus of data).
 
Randomizing Results
 
Once all possible list items are being returned by your web part, it’s time to customize the underlying XSL formatting to randomize our results.
 
If working with a CQWP, that logic will live within files in /Style Library/XSL Style Sheets/ such as ItemStyle.xsl and Header.xsl. If working with a DWVP, the XSL can be manipulated by viewing source in SharePoint Designer. For other XSLT web parts such as Search Code Results, you should be able to edit XSL directly in the web part properties.
 
Enabling the ddwrt:Random() function
 
The trick to randomizing results in XSLT is making a special function in the DDWRT namespace available. That’s a SharePoint-specific set of functions that Microsoft built. Data View Web Parts reference DDWRT by default, but other web parts need a reference to be explicitly added.
 
I described how to do so in a previous post. It involves adding the bold sections to your opening <xsl:stylesheet /> block:

<xsl:stylesheet version=”1.0″ exclude-result-prefixes=”x d ddwrt cmswrt xsl msxsl” xmlns:x=”http://www.w3.org/2001/XMLSchema” xmlns:d=”http://schemas.microsoft.com/sharepoint/dsp” xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime” xmlns:cmswrt=”http://schemas.microsoft.com/WebParts/v3/Publishing/runtime” xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” xmlns:msxsl=”urn:schemas-microsoft-com:xslt”>

The “Randomize” Template

Once the DDWRT namespace has been added, the ddwrt:Random function will be usable. It accepts two parameters: a minimum number and a maximum number. We’ll be using that in a custom template to choose results.

Here’s the core template to add to your XSL:

 

<xsl:templatename=Randomize>
<
xsl:paramname=Rows />
<
xsl:paramname=Limit />

<xsl:variablename=SelectedRowselect=ddwrt:Random(1, count($Rows)) />
<
xsl:value-ofselect=$Rows[position() = number($SelectedRow)]/@FileLeafRef /><br/>

<xsl:iftest=count($Rows) &gt; 1 and ($Limit &gt; 1 or $Limit = 0)>
<
xsl:call-templatename=Randomize>
<
xsl:with-paramname=Rowsselect=$Rows[position() != number($SelectedRow)] />
<
xsl:with-paramname=Limitselect=$Limit – 1 />
</
xsl:call-template>
</
xsl:if>
</
xsl:template>

 

That template accepts two parameters.

  • Rows: The node set of items to choose from.
  • Limit: The number of items to return. To return everything, pass 0.

It works by selecting one node at a time, then iterating through the remaining nodes one at a time until either there are no nodes left or the limit has been met. Because of the recursive approach, overall running time is bound by O(N^2) where N is the number of nodes.

Randomizing Results

Once that template has been added, you can replace existing xsl:for-each loops with the following:

<xsl:call-templatename=Randomize>
<
xsl:with-paramname=Rowsselect=/dsQueryResponse/Rows/Row/>
<
xsl:with-paramname=Limitselect=1/>
</
xsl:call-template>