Sunday, 20 March 2011

Extract WSP Solutions from SharePoint using PowerShell


There will be occasions when you will find it really useful to be able to extract a WSP solution from the SharePoint solution store.  This is not something that you can do out of the box, I’m not sure why, possibly to protect the intellectual property of third party solution providers perhaps?
I’m not saying that you should be extracting WSPs so that you can go poking around in other people’s solution packages, but there are definitely valid reasons for needing to extract those solutions.
The two main legitimate reasons I can think of for needing to extract a WSP are as follows:
1.   Your company does not have an appropriate source control system and your solutions have been developed by a third party.
2.   You need to audit any custom solutions that have been created.
Regarding the second point above, there have been a number of times when I have had to perform an audit of a customer’s SharePoint system as part of IMGROUP’s Health Check service.  The reason for wanting to poke around in the WSP solution package is to verify whether or not customisations have been made according to best practice.  For instance, in one particular instance a third party had assured the customer that all their customisations had been packaged as part of WSP packages, but by extracting the few WSPs that were in the solution store, I could see that this was in fact not the case.
Another example that is quite pertinent at the moment is where you need to assess what customisations are in place prior to performing an upgrade to SharePoint 2010.  The “preupgradecheck” command that is a part of stsadm is only available as part of Service Pack 2 for MOSS 2007, as well as ideally requiring a number of additional cumulative updates.  If your environment is currently at Service Pack 1 and you are fairly risk averse, performing an upgrade to Service Pack 2 purely to get an understanding of what customisations have been made may not be particularly desirable.  Instead, most customers that I am working with will include the Service Pack 2 upgrade as part of their implementation plan, but want some early visibility of their customisations so they can make steps to validate them against the new product.
The following simple PowerShell script will iterate through the solution store and write the WSP packages to file:
Start-Transcript "c:\wsp\transcript.txt"
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

$solutions = [Microsoft.SharePoint.Administration.SPFarm]::Local.Solutions;
foreach ($solution in $solutions) {
   $solution.SolutionFile.SaveAs("c:\wsp\" + $solution.Name);
}
Stop-Transcript

The above script uses the Reflection namespace to perform an Assembly load of Microsoft.SharePoint.dll from the GAC.  Since the dll is being loaded in this way, the script can be run in a standard PowerShell console.  If your environment is running on Windows Server 2003, PowerShell can be downloaded and installed from the following link:

Opening Links in a new Window in SharePoint 2010 using jQuery live() method

The Problem
I recently encountered an interesting requirement from a customer who wanted a way of ensuring that hyperlinks to external URLs would be opened in a new window.  The difficulty was that they were making heavy use of the native SharePoint Links List which unfortunately does not provide this option, unlike the Summary Links Web Part.
The reasoning behind their usage of the Links List was that the majority of their content was being stored within Autonomy Documentum, along with them needing to be able to reference external web sites, but they were using SharePoint 2010 for their Corporate Intranet.  The Links List enabled them to use a standard mechanism for specifying metadata on their links to content, whether it was stored in Documentum or elsewhere, resulting in a more structured Information Architecture that would facilitate a better search and navigation experience.
I had a few ideas of how I would want to implement this functionality and ultimately the most flexible approach would involve the ability to choose whether to open in a new window on a per Link Item basis.  On the flip-side, there was a limited amount of time available and I was conscious of the fact that a large amount of content had already been created which would have to be updated should I go for the item-by-item method.
Below are the constraints that I set myself for implementing the solution:
·         Requires no modification to core SharePoint templates.
o   Modifying core schema.xml files is not supported and is definitely not best practice!
·         Makes use of the existing Links Content Type and List Template.
o   Especially since half of the content had been created already using the above.
·         Can be applied to all existing content with minimum effort
Based upon the above constraints, the best candidate for this functionality is to use JavaScript, particularly as we are talking about an Intranet so we don’t have to be worried about users having JavaScript disabled.
Initially, whichever method I used, I had intended to locate the <a> tag for the link and set the “target” attribute to “_blank”, which is a fairly standard method.  I did a bit of Google research and found the following post which summarised a few different options, of which the first was the most simple and elegant:
The author proposes the method of using JavaScript to analyse the target URL of the <a> tag and compare it to the current window Hostname.  If the hostname of the target is different from the current window, then update the <a> tag with the appropriate “target” attribute.
Unfortunately, elegant as the above solution is, it doesn’t cater for the heavily asynchronous nature of SharePoint 2010 as the code will executed once after the page has loaded but not after any asynchronous calls have been made that may update the DOM.  In particular, the Links that I wanted to manipulate were contained within a Grouped View of the SharePoint List View Web Part, which uses AJAX to populate the contents once the group is expanded.
The Answer
I spent some time researching the problem and investigated the possibility of updating the event handler that makes the AJAX call, however, this became quite messy, involving some “eval()” code which generally doesn’t sit well with most developers.
What I wanted was a mechanism that could do one of the following:
·         Raise an event when any AJAX call has been completed
o   Doesn’t appear to be available
·         Raise an event when the DOM has been modified
o   Not supported in IE
o   Refer to this post for an excellent comparison of supported events from the W3C specification: http://www.quirksmode.org/dom/events/index.html
·         Bind events to DOM objects that don’t exist yet (i.e. the <a> tags)
o   Surely this must be impossible?!! …
Low and behold, I found exactly what I was looking for in the fantastic jQuery library (for those of you who do web development but haven’t started using jQuery yet, THIS LIBRARY ROCKS!!!).  To use the jQuery library, download from the link below and store in a sensible location within SharePoint (such as a subfolder within the LAYOUTS directory) and modify your SharePoint Masterpage to reference the library.
jQuery contains a method called “.live()” which enables you to perform the 3rd mechanism in the list above.  Refer to the following article for a detailed explanation of how this works, but to summarise, it works by a process of event delegation.  This means that a specific DOM container can handle events of a specific type that bubble up from the container’s subtree, effectively allowing me to bind the “click” event to <a> tags that will be created asynchronously.
Bringing it all together
Now I had a workable mechanism, all I had to do was write the appropriate jQuery code.  What I came up with is shown below:
$(document).ready(function() {
     $(
"#MSO_ContentTable").find("table.ms-listviewtable").each(function() {
          $(
"tbody td.ms-vb2 a", $(this)).live('click'function() {
               
var thisDomain = window.location.hostname;
               
var theHref = $(this).attr("href");
        
               
if (theHref.indexOf(thisDomain) != -1 || theHref.indexOf("://"== -1) {
                    window.location.href 
= theHref;
               }
               
else {
                    window.open(theHref);
               }
        
               
return false;
          });
     });
});
There are a couple of points that I need to explain about the above:
1.   The above code assumes that a DOM element with an id of “MSO_ContentTable” exists on the page. 
a.    This should be the case if you have adapted the SharePoint Masterpage v4.master.
b.    If you have created a completely custom Masterpage then wrap a <div> with an id attribute around the content placeholder “PlaceHolderMain” and substitute $(“#MSO_ContentTable”) with $(“#MyCustomContainer”)
2.   Only Links within a List View Web Part are targeted by selecting the <table> tag with a class of “ms-listviewtable” applied.
3.   The <table> above will act as the context for the .live() method for each List View Web Part, ensuring that the “click” event does not bubble up any further than is required.
4.   The URL comparison allows relative URLs (i.e. relative to the current site) to be excluded.
In conclusion, jQuery is an extremely powerful, easy to use and relatively lightweight library compared to some other libraries (you know I’m talking about you ASP.NET AJAX!).  Once you get your head round it, it can dramatically reduce the amount of code that you need to write and greatly simplify the process of working with the DOM.  Without the .live() method, I would have struggled to achieve what should have been a fairly simple task and I think that this method may see more use within SharePoint 2010 considering the much wider usage of AJAX calls.

Monday, 7 March 2011

Thoughts on turning 30

So I came home from work today to find my wife feeling a bit down as it's her 30th birthday.  Since it's going to be my 30th in a couple of weeks time, it got me thinking about how I feel about the inevitable approaching milestone in my life.
To be honest, I'm feeling fairly positive about it, although it is easy for me to say as I've still got a couple of weeks to go.  Obviously there are negatives to the whole thing and I have to admit that I'm starting to feel a greater sense of urgency about the following:
  • My wife and I don't have any kids yet...
  • I am reminded by my elders and betters that my best career earning potential is in the next 10 years so I need to 'make it happen!'...
  • I haven't really started saving that much money or making that much of a dent (if any) in the mortgage...
When I think about the above, it’s easy to fall back on the old cliché of “Well, you’re still young!”, and I have to admit that the saying helped reduce the anxiety I felt after buying an unnecessarily expensive car, but unfortunately there comes a point when you realise that you need to grow up, get your backside off the sofa and stop playing XBOX (Call of Duty: Black Ops at the moment...seriously addictive!).
In all fairness, that’s probably one of the reasons why I’ve started this blog in the first place...
Ok, enough of the bad points though and let’s talk about some of the good:
  • I don’t have to pretend to enjoy going to clubs anymore.
  • My social life tends to involve doing more coupley things, bit more refined etc etc
  • I do have a lot more disposable income than I had 10 years ago
  • I have become more established in my career (although I’m still fairly unsure of where I want it to lead, as I’m sure most people are)
  • hmm...well...I’m pretty sure I had more points than these when I started writing this post.
  • oh yeah...I’ll be getting an iPad when I’m 30!
So to sum up, yes it’s obviously not a great feeling to acknowledge that you’re getting older and are at least 10 years past your prime, but when I think back to how much has happened to me in the past decade, I can’t help but feel excited about what is in store over the next!

Sunday, 6 March 2011

Quick go on the iPhone

Just downloaded the BlogPress app for the iPhone / iPad to see what the mobile blogging experience is like. I guess it's more in anticipation of getting the iPad because I don't realistically expect to be making many posts on the iPhone just because of the awkwardness of the typing interface.

Having said that, I think the real beauty of this tool will be for blogging my general thoughts when I'm out and about.

Thoughts on the app so far:

1) was able to connect to my blogspot pretty quickly - good

2) comes with support for storing pictures in Picasa - good (although I would prefer integration with Flickr but you can't have everything)

3) interface doesn't scroll when writing text on the iPhone which is a bit annoying if you are making a fairly large entry - bad

For more information on the BlogPress app, do a search in the App store or check out the following link:

BlogPress iTunes AppStore

Enough of that for the moment, catch you soon when I actually have something relevant to blog about!

First Blog!!

Hey there everyone,

This will be my first post on my newly formed blog. I've been meaning to put something together for quite a while and never quite got around to it, but I've decided that enough is enough and it is time to get my backside into gear and get writing!

As you can see from the title of my blog, I will be devoting the majority of my time to SharePoint, including any related technologies such as .NET, jQuery, ASP.NET, C# etc etc. Having said that, I'm gradually finding myself to be more and more of an Apple fan, have finally convinced my wife to get me an iPad 2 for my 30th birthday, and no doubt will be making a number of posts about that as well.

Since you're here, I'll start by giving you an overview of my experience to date. I've been working with SharePoint since late 2007, coming from a more general .NET background when I was self-employed. For the first year or so my exposure to SharePoint was primarily on the development side, creating Web Parts, Event Receivers, Feature Receivers...pretty much the usual stuff that a SharePoint developer will find themselves getting involved in. The company I worked for at the time had a strong focus on providing tailored SharePoint branding solutions to their customers but at the time this was an area that I had little or no interest in and tended to steer away from, however, over the past year or so I've had to have a better appreciation of what goes on in this area. Believe you me, compared to the sometimes extremely painful experience that is writing code for SharePoint, creating CSS feels like a walk in the park!

I now work for a company called IMGROUP who are well known for being a Business Intelligence specialist in the Microsoft Stack. Since joining the company I have moved into a technical architect role involved in designing SharePoint solutions, specifying target infrastructure, designing topologies, configuration Kerberos authentication and all sorts of other good stuff. I would consider myself to be a customer focused software consultant, as opposed to pure a technical person. This is no doubt partly due to me being in customer facing roles since I started my career.

Well I think that serves as enough of an introduction for the moment. Realistically at this stage I am hoping to be able to post once a week as a starting point. Ultimately I guess it boils down to how much of something interesting I have to say. Generally I would say that the most interesting posts that I have read by other people tend to be focused on giving an example of achieving something fairly challenging, or a particularly difficult problem they have encountered, so I will be trying to emulate this approach to blogging as much as possible.

Hope someone reads this eventually and if you are then thanks for continuing to read up to this point!

Have fun
Ben