New Codeplex Project: SP Link Checker

I have just finished putting together a new SharePoint project for Codeplex (again something I put together for Readify that they have let me share). This one is designed to report on broken links in a site. Basically it works by scanning a site collection to find all the links in any publishing HTML fields, link fields, summary link fields, summary link web parts and content editor web parts and then does a quick HTTP Request to make sure that there is something at that URL. This means it can reports on links to content both within the SharePoint site as well as links to external sites.

I have labeled the current release as a beta because I know there are features that should be in this that I haven’t had the chance to put in yet, but it does work quite well in its current form. Anyway if you want more info, or you want to download and try the link checker head over to codeplex and check it out!

http://splinkchecker.codeplex.com/

SharePoint Saturday Melbourne is now confirmed!

For those of you who got the chance to come to SharePoint Saturday when we held it in Sydney in August, I’m sure you would agree that it was a great event – we had great speakers, great sponsors and from all the feedback we got everyone had a fantastic day. The good news now is that we are doing it again, and this time we are taking it to Melbourne!

We are aiming to raise the bar in a few ways for the event in Melbourne, such as:

  • Getting even more attendees there – we will be opening it up for at least 160 people this time
  • We are looking into being able to run some lab based sessions for some hands on experience, so stay tuned for details here
  • We are hoping to be able to line up even more top level presenters to be able to present on a wide range of topics, and given that we will be running the event after the Vegas SharePoint Conference we are hoping that there will be plenty of SP2010 goodness we can present on as well (fingers crossed there!)

The event will be held at the Cliftons training suites in Melbourne on November 14th, and if you want more info head over to http://www.sharepointsaturday.org/melbourne. Registrations to attend aren’t open just yet but they will be shortly, so stay tuned. Also if you are a twitter user make sure to follow @SPSMelbourne for all the details as they are announced!

Issues setting up the CFK Forms Based Authentication Solution

I’ve been spending some time looking at the Forms Based Authentication solution that is part of the CKS – it has some great web parts and management forms for working with forms based authentication in SharePoint – but I did find that there are a couple of things to make sure you do before everything will work for you correctly that I thought I would share here.

When activating the user management feature you get an error about a dependant feature not being installed

When you run the setup script you might find that you get yourself into some trouble when the feature “FBAManagementSelf” tries to activate, complaining that a feature that is a dependency of this one is not installed. Technically this is true, the feature it is looking for isn’t installed and that is because it was cut from the solution. So the fix here is to update the feature.xml file and remove the dependency. Browse to 12\TEMPLATE\FEATURES\FBAManagementSelf in windows explorer and open feature.xml and remove these lines:

<ActivationDependency FeatureId="01AA8D8B-000A-4c35-8F4F-5D1280377650" />
<!--  My Settings Save Override  -->

“Object reference not set to instance of an object” error on FBA User Management page

This one had me stumped for a short while, but wasn’t too hard to figure out. Basically what was happening when I clicked on the link from the site settings page I would keep getting the good old NullReferenceException error message there – after downloading the source code and debugging this it became pretty easy to figure out. Basically what this page is doing by default is showing a list of users in the current site that are forms based authentication users – so if none of your FBA users exist in the user info list in the site, then there will be nothing returned and the exception is thrown.

The fix is easy – go in and grant one of your FBA users permission to the site somewhere. This will add them to the list and then when you browse back to the page you will find the exception is gone and you can see the list now.

Apart from that the install and setup was fine for me, just set up your forms based authentication source just like you would normally, and then install this solution to get all the extra goodies and you are off and running!

New CodePlex project: Blog list definition with OPML export

So I’ve had the opportunity to put another great little tool I wrote for Readify on to CodePlex. This one is a SharePoint list definition that is used for storing details of blogs and their RSS feeds – which in itself isn’t all that cool, but what this solution does is give you an option to export the list of blogs in the list to an OPML file that you can then easily import into an RSS reader! Just browse to the list and select “export to OPML” and you will be prompted to save the OPML file that is generated on the fly.

Check out the project on CodePlex at http://spbloglist.codeplex.com/.

SharePoint Saturday Sydney this weekend!

I am really excited about this one – SharePoint Saturday Sydney is happening this weekend! It is the first SP Saturday event to happen in Australia (Adelaide are having one next weekend, and I have it on good authority that others are being planned for later this year too!). The popularity of this event has been overwhelming, we have had to close registrations because the Microsoft Office won’t hold any more people, so if you didn’t get in to register then your not gonna be able to come.

If you did register though I have some fantastic news for you, thanks to a last minute sponsor Mimosa Systems we now have a couple of major prizes for the raffle draw at the end of the day – the runner up prize is a Western Digital 640GB external USB Hard Disk, and the major prize (and I really love this one) is an Xbox 360 arcade system, including 5 Xbox Live arcade games, Sega Super Star Tennis and the Ultimate Sega Mega Drive Collection! How cool is that!

W10-9008-Main-JHxbox_360_arcade_console

The way the raffle is going to work is that for every session feedback form you fill in you will get one entry into the raffle, meaning you can have a maximum of 6 entries across the whole day. You will be able to drop the forms off to us during the day, and we will provide you with the forms, a pen, and all the other paperwork in a special bag for the day that you will get to keep, so you have no reason to not enter the raffle now!

If you haven’t already had a look at the session line up, head on over to our website and check it out – we have some great speakers covering a wide range of topics for the day.

We have also confirmed the lunch details, we are having the catering done by the guys at Subway in Lane Cove, so there will be a nice selection of sandwiches to pick from there (including the usual vegetarian options), and there will be plenty of soft drinks and bottles of water there throughout the day to make sure you don’t get too thirsty.

Lastly, after the event we are all going to head to a pub nearby and have a SharePint event (thats not a typo, I mean Share “pint” :-P) to unwind from the event and just have a good time in general. We will advertise that on Twitter and on the day at the event, so if you can keep yourself free for the night to come along that would be awesome as well.

I’m really looking forward to seeing you all there – stay tuned here for a special video blog post I will be putting together with footage from the day, and of course there will be pictures, slide decks and source code (where possible) made available to download after the event as well.

Using PowerShell to apply a site logo to all sites in a site collection

I came across this while doing some work last week, basically we needed to apply a new logo URL to every site in a site collection. When you go into a site and change the title description and logo there is no way to apply that logo to all sub-sites though, which means to change that URL in every site is a very long and manual task normally.

Lucky for me, this is a very easy to do thing if you write some PowerShell for the job. Here is the quick script I wrote that will apply the logo from the top level site to every site in the site collection.

############################################################################
#Assumptions:
#-Running on machine with WSS/MOSS
#-C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN in path
############################################################################
$12HivesDir = "${env:CommonProgramFiles}\Microsoft Shared\web server extensions\12\"
cd $12HivesDir
[void][reflection.assembly]::Loadwithpartialname("Microsoft.SharePoint") | out-null

#returns the SPSite at the specified URL
function get-spsite ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
   return New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl";
}

$site = get-spsite("http://mysiteurl");
$rootWeb = $site.RootWeb;

$newLogoUrl = $rootWeb.SiteLogoUrl;
Write-Output("Setting all site logos to: " + $newLogoUrl);

foreach($web in $site.AllWebs)
{
	$web.SiteLogoUrl = $newLogoUrl;
	$web.Update();
	$web.Dispose();
}

$site.Dispose();
$rootWeb.Dispose();

Write-Output("All logos updated!");

The breakdown is pretty simple – it gets the SPSite object (just put in the appropriate URL to the script) then it checks the property of the RootWeb SPWeb to get the URL that is being used to update the rest. Then it passes through all the SPWebs in the site collection through the AllWebs property of SPSite and updates each of them one by one. Its a very quick script that is easy to use, I hope you find it useful!

New Codeplex project: SharePoint alert import/export tool

Before I begin, let me clear the dust off the blog – it’s been a little while since I wrote a blog post! (I had a lot on with moving house and starting my new job as well, so e blog kinda took a back seat for a while).

Anyway, I’m back with a great little tool that I wrote as one of the first pieces of code I put together for Readify in my new job. Basically we needed to come up with a way to stop alerts from being sent from a specific SharePoint site while some bulk updates went on (this would prevent item updated alert was very old being sent to people). What we came up with was a tool that would allow you to export the alerts from a site (SPWeb) to an XML file, and then import them back in when you were ready to do so. This did the trick quite nicely, and I was pretty happy when I got the green light to put it on codeplex as well rather than just keep it as an internal solution. I know there isn’t a lot to it, but its nice to be able to share these little solutions!

So if you want to check it out and get all the details, head over to http://spalertimportexport.codeplex.com/ and have a browse -the wiki has instructions (with pictures, yay!) and the latest release available for download. Feel free to leave comments about it here or on the codeplex site in the discussion board.

My adventures into SharePoint and PowerShell

On the back of some requests on Twitter about me using PowerShell for SharePoint, I thought I would put this post together to talk about where I started and the things I did today in the space of a couple of hours. To start with, I’ll admit that I haven’t done more than look at powershell and briefly read over some doco in the SDK about it, so this article is more of the people who haven’t touched it – and seriously you don’t know what you’re missing if that is you!

So to get started I downloaded the PowerShel 2.0 CTP and PowerGUI(to edit scripts with InteliSense, top tool). I had a read over the article at SPDevWiki(and I will probably go and contribute more to that now that I have done it myself). So the first thing I learned was about the powershell profile (this is from the SPDevWiki page). Basically this is somewhere that you can put in functions that you want to be available in all the PowerShell scripts you run on that machine. The page there recommends putting some neat little functions into this before you get too far along – I didn’t to begin with (I just put them into my script file) but I will be doing it shortly.

I had also better explain why I had been looking into PowerShell before I get into the details though – basically I got handed a deployment document for a site that a client wanted built. It was pages of screenshots of the manual steps involved to create a default team site and apply a few customisations to it. It took a while to actually do this so I thought to myself “there has to be a better way”, then I thought of scripting it with PowerShell – I knew I could essentially access the entire SP object model in the script, which meant I knew I could achieve everything they were doing in the script.

So the first thing I did was create a new site collection in an existing web application. This was pretty straight forward, here is the code:

$webapp = [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup("http://server")
$webapp.Sites.Add("http://server/sites/mynewsite", "Site title", "Site description", 1033, "STS#0", "DOMAIN\SiteOwner", "Site Owner Name", "Site.Owner@domain.com")
$site = get-spsite $url

So the $webapp is basically the SPWebApplication object, and from that you can get all the properties and functions you can through C# code, so we can add the site collection the same was as we would through code. The next thing I needed to do was to update the properties of one of the lists in the site. So I used the get-splist method that was in that profile section from SPDevWiki to get the SPList object, then just updated settings as I needed to  

$mylist = get-splist $url "Announcements"
$mylist.Description = "My new description"
$mylist.OnQuickLaunch = $true
$mylist.Update()

So again, this is pretty much the exact same as if you were writing the code in C#, so naturally at this point I’m getting pretty excited at what I can do with this whole PowerShell thing! Next I needed to update the properties of a document library, so I needed the SPDocumentLibrary object instead of the SPList, so I made a copy of the get-splist function and called it get-spdoclib, then used it to update the document library.

function get-spdoclib ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'),String]$listName=$(throw 'Parameter -listName is missing!'))
{
$site = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl";
$web = $site.OpenWeb();
return [Microsoft.SharePoint.SPDocumentLibrary]$web.Lists[$listName]
}

$lstDocuments.Title = "Custom Document Library"
$lstDocuments.Description = "I changed this with PowerShell!"
$lstDocuments.EnableModeration = $true
$lstDocuments.EnableVersioning = $true
$lstDocuments.EnableMinorVersions = $true
$lstDocuments.Update()

This worked quite nicely and let me set the versioning and approval settings of the document library. So the things I learnt here were that I could still cast objects (The return line of the get-spdoclib function uses a type cast to get the SPList that is returned to come out as the SPDocumentLibrary) and that if you need to refer to things like true and false, you do it with a $ at the front. My next target was the quick launch navigation, I needed to move an item to the top of the “Lists” section, and delete an item off the bottom, so again I took what I knew I could do with C# and applied it here:

$web = get-spweb "http://vds000023/sites/mynewsite"
$quicklaunch = $web.Navigation.QuickLaunch
$quicklaunchlists = $quicklaunch[1]
$quicklaunchlists.Children[2].MoveToFirst($quicklaunchlists.Children)
$quicklaunch.Delete($quicklaunch[4])

I wasn’t overly happy with the way I put this part together because I just refer to the items in the quick launch by their indexes in the array (so $quicklaunch[1] is the heading “Lists” and then the Children[2] property from it is the 3rd item in the list of items under that heading). But again it’s just the same methods to move the navigation around and then to delete the item. My next thing was that I wanted to move one of the web parts on the home page, add a new web part and delete a web part – here was what I came up with:

$file = $web.GetFile("default.aspx")
$wpmanager = $file.GetLimitedWebPartManager([System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared)

$wpmanager.DeleteWebPart($wpmanager.WebParts[3]) $calendarwp = [Microsoft.SharePoint.WebPartPages.ListViewWebPart]$wpmanager.WebParts[1]
$wpmanager.MoveWebPart($calendarwp, "Right", 20)
$wpmanager.SaveChanges($calendarwp)$documentswp = New-Object "Microsoft.SharePoint.WebPartPages.ListViewWebPart"
$documentswp.ListName = $lstDocuments.ID.ToString("B").ToUpper()
$documentswp.WebId = $web.ID
$documentswp.ZoneID = "Right"
$wpmanager.AddWebPart($documentswp, "Left", 20)

So the delete operation was first (and again I’m using the indexes to refer to the webparts – I don’t like it but it works), then I moves a web part to the right zone, and then I created a new list view web part (the $lstDocuments variable in there was from a previous call I had to get-spdoclib to update the document library settings). So here I figured out that you can refer to enumerations such as the PersonalizationScope in PowerShell by giving the typename followed by :: then the value – and this had intelisense for the values as well which was handy.

The last thing I wanted to do was around permissions – I needed to create a group, create a custom permission level, and then assign that permission level to the group for the site. Here’s the code:

$newroledef = New-Object "Microsoft.SharePoint.SPRoleDefinition" -ArgumentList $web.RoleDefinitions["Contribute"]
$newroledef.Name = "Approve"
$newroledef.BasePermissions = $newroledef.BasePermissions.ToString() + ",ApproveItems"
$web.RoleDefinitions.Add($newroledef)
$web.Update()  

$customroledef = $web.RoleDefinitions["My Permission Level"]
$customroleassignment = New-Object "Microsoft.SharePoint.SPRoleAssignment" -ArgumentList $web.SiteGroups["Group name"]
$customroleassignment.RoleDefinitionBindings.Add($customroledef)
$web.RoleAssignments.Add($customroleassignment)

So the first thing I did here was to make a copy of the Contirbute permission and add the approve items right. In PowerShell when you have a flagged enum like the BasePermissions property, you can actually refer to the list of values like “Value1,Value2,Value3″ and it will work the rest out for you. In this case I am just ToString()’ing the value and adding the ApproveItems flag – I like this, very easy to do. Next I added the group, again straight forward ($site was  already around from where I had used the get-spsite method from SPWevWiki again) and the applying the permission to the group was again, the same as it would be in C# code. The thing I learnt here was around creating new objects. You use the “New-Object” variable and the put the arguments for the constructor you want to call after the ArguementList option (just as a comma seperated list).

So in the end when I string that all together I got myself the desired result, so I was pretty impressed after that. So the theory of what will happen with this script for the client is that the fill script will become a base for a new extranet site, so whenever they need to create a new one they can take a copy of the script, tweak it a little and roll out the new site in a lot less time that it takes to manually prepare it. The are some alternatives that could have been taken (such as site definitions, or using features to apply the changes) but given that there is likely to be a large number of these sites, and they will all be slightly different (but still essentially just customised OOTB sites) going to all that effort didn’t seem like an appropriate choice. The script on the other hand didn’t take long to put together, will create the individual sites, and won’t clog the farm up with endless site definitions and/or features for each extranet.

I will definitely be looking to make more use of PowerShell from here on in, and I hope that if you have learned something from this (somewhat large) post that you will too!

Customising the Content Query Web Part’s RSS feed

If you have ever used the Content Query Web Part (CQWP) you will have noticed that it has an option to return an RSS feed for the items it’s returning. This makes it great for things like “Latest News” sections of a website and things like that. But did you know that you can actually control how that RSS is generated? It’s surprisingly simple – it does an XSL transformation on the XML data returned by the query to turn it into valid RSS XML. Here’s how you go about changing it.

Firstly, find a CQWP that has an RSS feed on it and click on the link, have a look at the URL it is taking you to, it should look something like this:

/_layouts/feed.aspx?xsl=1&web=%2F&page=[GUID]&wp=[GUID]

If you have a look at the default ContentQueryMain.xsl you can see the code that generate the link for you, it looks like this:

<xsl:variable name="FeedUrl1" select="concat($SiteUrl,$FeedPageUrl,'xsl=1&web=',$WebUrl,'&page=',$PageId,'&wp=',$WebPartId)" />

The bit in this that we are concerned with is that “xsl=1″ part. Basically this is what determines the style sheet that gets used. If you get reflector out and have a look at the code behind for that feed.aspx you will see that it goes and does a looks in the web.config file to determine which XSL file it should use to generate the RSS feed. It does this by combining the string “FeedXsl” and the value of that XSL query string parameter. So by default it’s going to go to web.config and get the value of “FeedXsl1″ from the appSettings section, which by default will return “/Style Library/Xsl Style Sheets/Rss.xsl” (I’ve seen that setting there a bunch of times before, but I never really wondered how it worked!).

So now if you go into a publishing site and open up that Rss.xsl file, you will see that it is generating the RSS feed XSL by slipping the appropriate variables into the appropriate places – reasonably straight forward XSL stuff here, nothing special.

So now, if you want to customise the XSL that gets used for a specific CQWP what do you do? It goes a little bit like this:

  • Create a copy of the ContentQueryMain.xsl file and changing the xsl=1 to something else (xsl=2 is a good start :-P)
  • Customising the XSL stylehseet that the CQWP uses (do this by exporting a CQWP and doing a find and replace for contentquerymain.xsl to point it to a new file that is your own copy of the file, than upload it back to your web part gallery and put it back on the page)
  • Adding a web.config entry to the appSettings section called “FeedXsl2″ (or whatever it should be based on the xsl query string attribute) that points to a copy of the Rss.xsl file in your site
  • Then customise that copied Rss.xsl file to control how your RSS is rendered

That’s it – so now if you look at the newly updated CQWP you should see the URL you’re feed points to has xsl=2 in it and the RSS is generated from your custom XSL file.

Registrations for SharePoint Saturday Sydney are now open!

SharePoint Saturday Sydney

If you are planing on coming to SharePoint Saturday Sydney you can now register to attend the event by following the “register” link on our website!

We have had a few people put their hand up to present as well, but we still need more presenters! So if you think you have something you want to present on head over to the site and fill out the speaker registration form and email it through to us (the instructions are on the form).