Creating new sites in a batch

During SharePoint development you just need a whole bunch of sites. Creating them just for test purpose using the central administrations seems to be to much hassle. Instead I created a little batch-file to take care of spinning up a new test-site.

Basically you just have to edit the variables at the beginning of the script. Just specify the port, the site name, title and description. The name is used to create the web-application, application pool, the database and the stuff.

When creating the new site-collection for the web-application I did not provide a template; this way I can choose a template at the first call to the newly create site.

@echo off
setlocal
pushd .
    set SPLocation=%CommonProgramW6432%\Microsoft Shared\web server extensions\12
    set SPAdminTool=%SPLocation%\BIN\stsadm.exe
    set sitePort=6001
    set siteName=SampleSite
    set siteDescription=Demo a SharePoint Web-Application
    set siteTitle=Web-App Demo
echo Creating WebApplication '%siteName%' at port '%sitePort%'
"%SPAdminTool%" -o extendvs -url http://localhost:%sitePort% -owneremail me@acme.local -ownerlogin acme\me -ownername "Acme Big Boss" -databasename WSS_Content_%siteName%_%sitePort% -description "%siteDescription%" -apcreatenew -apidname "WSS_AppPool_%siteName%_%sitePort%" -apidtype NetworkService -donotcreatesite
echo Creating WebSite '%siteTitle%'
"%SPAdminTool%" -o createsite -url http://localhost:%sitePort%/ -owneremail me@acme.local -ownerlogin acme\me -ownername "Acme Big Boss" -lcid 1031 -description "%siteDescription%" -title "%siteTitle%"
popd
endlocal

Apply Workflows to folders

In my last blog-post I described how to enable meta-data for folders. Even though you can configure workflows for your custom content-type (of type “folder”), there seems to be no way to actually start those workflows. There is no context-menu entry to start such workflows as for any other content-type.

But there is a way! If you happen to know the right URL to start workflows … just call /_layouts/Workflow.aspx?ID=[ItemID of the folder]&List=[GUID of the list]. Just insert the appropriate values and off you go.

Folders with Meta-Data in SharePoint

When working with document libraries you can use folders to structure your documents within the library. This is ok, but a better approach to structure documents would be by assigning meta-data to the documents and create the structure based on this meta-data.

But sometimes you actually do need to have folders. For example you have bunch of documents which belong together. You could ZIP them up and thus have just one item in the document library, but this will stop you from being able to edit those documents directly in SharePoint. With SharePoint 2010 you could use document-sets, but what to do when you’re stuck with SharePoint 2007? Well, in this case you have to use folders.

OK, so folders it is. But how can I add meta-data to folders? When adding new columns to a library these will be available for all documents added to the library but not for folders. Here’s a trick to work around this problem:

  1. instead of added columns to the document library, create websitecolumns.
  2. create a new content-type, which derives from “document” to hold the actual documents of the document library. Add the websitecolumn created in step 1 to the content-type.
  3. create a new content, which derives from the type of “folder”. This content-type is being uses to create folders with meta-data in the document library. Add the websitecolmn of step 1 to the content-type.
  4. in the document library activate the use of content-types and deactivate the usage of folders(!), since we want to use our own content-type to create folders.
  5. add the in step 2 & 3 created content-types to the list and alter the order of the content-types in such a way the “document” type is not at position one. The first content-type of the list is always the default content-type and thus cannot be deleted. Once you alter the ordering you can delete the “document” content-type and just have your two custom content-types.

So now you can add folders to the document-library which also have meta-data. Interesting enough is the fact, that you can create a new content-type based on a content-type folder and then add this newly created content-type to the document library, but you cannot add the “raw” folder content-type to the library. However.

Active-Directory Groups in SharePoint

When adding an Active-Directory group to SharePoint, for SharePoint this group is like any other (user) account. SharePoint doesn’t care whether the account added is a group or just a single user. Because of this “ignorance” of SharePoint not the group-members are being added to SharePoint, but the AD-group. This group can then be used just like any other SharePoint user.

But there are a couple of caveats:

  • let’s take a task-list for example. When a task is being assigned to a person in a task list, this person will get an email notification of the task assignment. When a task is being assigned to a SharePoint group (not an AD-group!), then every member of the group gets the email notification. Also when looking at the task-list every group-member will see the task, as long as no group member has assigned the task to himself. Every group member can assign the task to himself, and by this the task will only show up in the users task-list, not anymore in the view of the other group members.
    When a task is being assigned to an AD-group no one receives an email, because SharePoint want’s to send an email to the groups email-address (since SharePoint doesn’t know that an AD-group is a group which consists of members, and hence it believes it’s a single user). And because SharePoint believes the AD-group is a single user the task can not be assigned to a member of the group – and also the task is not shown to the members of the group.
  • When assigning an AD-group individual permissions on a site I usually can send an email to the user notifying them about the new permissions. with AD-groups this doesn’t work as well, since usually AD-groups don’t have an email-address and SharePoint is unable to iterate over all the members of the AD-group. The same is true for setting up notifications for lists and libraries, these cannot be set to an AD-group.

Errors that actually help to solve something

Well, suddenly it just happens – a YSOD. Just happened in my recent SharePoint dev-project.

Typical for SharePoint, this error is not obvious. Instead of the YSOD you’ll get a SharePoint specific page, telling you that something went wrong. No hint what happened or where the error actually occurred.

OK, so let’s head to the web.config and stop this hide-and-seek behaviors. I wanna know what’s happening. So we have to enable to show the actual CallStack and disable the use of CustomErrors.

<SafeMode MaxControls="200" CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
<customeErrors mode="off">

OK, so now we’re talking. I have some sort of Null-Reference-Exception in my code. But this code just worked perfect on my dev-machine, so why is it failing on the test-machine? And why is something null anyway? The StackTrace tells me, that this happened in a property-getter.

private SPGridView _mySpGrid;
public void CreateChildControls()
{
    _mySpGrid = new SPGridView();
}
public bool HasRows
{
    get { return _mySpGrid.Rows.Count > 0; }
}

How can this be null? CreateChildControls is always being called, so the grid always exists. This cannot be the reason why.

OK, let’s try something totally irrational:

public bool HatWerte
{
    get { return _mySpGrid == null ? 0 : _mySpGrid.Rows.Count > 0; }
}

This could should actually not be necessary … except when this modification makes the Null-Reference-Exception to disappear. But just to make room for the next Exception. And now everything is making sense (and I could revert the above modification).

The next exception states:

Could not load file or assembly ‘System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’ or one of its dependencies. The system cannot find the file specified.

D’oh!

My application was build against .Net 3.5 and I didn’t install that on my test-machine. Since the test-machine is a Windows 2003 Server running SharePoint 2007 there was no need to install .Net 3.5 – yet!

But .Net could have told me so from the beginning on – I would have understood this. But instead it was hiding behind some Null-Reference-Exception, just like a coward!

Permission by obfuscation

… or how to hide certain actions in SharePoint?

There are a couple of things, which can not be configured in SharePoint. For example you cannot configure, that users are not able to edit a list in datasheet view or in Excel or Access. Bummer!

But with a couple of lines of JavaScript this isn’t really a challenge.

<script language="javascript" type="text/javascript" src="/Scripts/jquery-1.4.2.min.js"></script>
<script language="javascript" type="text/javascript">
$(document).ready(function() {
  $("[id$='_EditInGridButton']").remove();
  $("[id$='_ExportToSpreadsheet']").remove();
  $("[id$='_ExportToDatabase']").remove();
});
</script>

Just place this code in a Content-Editor-WebPart on the page and off you go!

The ultimate list of GUIDs

I’m not really sure, what is disturbing me more – the fact that I am actually searching for a GUID on Google, or the fact that there exists a list of GUIDs.

OK, so I have sharepoint manifest file, which is part of a site-template. This template has a whole lot of features, which have been added by sharepoint to the manifest and actually not needed at all. But all those features are only being described by their GUIDs – so who is who?

Lucky for me Robert Bogue has a blog-post, where he features a list of MOSS 2007 GUIDs. This was perfect to identify the features und to remove all the unwanted features from the manifest.

Half-day events in SharePoint

The Story

If you’ve been working with SharePoint you might have been working with calendar lists already. This is an easy to use way to add events to a web-based calendar. Like Outlook this features a checkbox to mark an event as a full-day event and thus omitting the start and end time (actually that’s not correct, behind the scenes the event starts ad 00:00 and ends at 23:59).

Recently someone asked on how to add a functionality like the full-day feature, but for half-day events. So you could just select wether an event should take place in the morning or in the afternoon.

That sound fairly simple to do.

How it’s done

OK, so I start by creating a new calendar from scratch. Next move to add an new item – and this is where we want to make our modifications to the form to allow selecting half-day events.

Because this view can not be edited directly in the browser you have to tweak SharePoint a little bit by altering the URL by adding toolpaneview=2 to the querystring.

Next you drag a content-editor-webpart below the editform and switch to the HTML source view.

I usually keep a copy of jQuery around, so I just add

<script language="javascript" src="/_layouts/jQuery/jquery-1.4.2.min.js" type="text/javascript"></script>

in the source-view. You might have to adjust the URL pointing to jQuery at this point. If you have no access to the file-system on your SharePoint server you could also just create a document library and place the jQuery library there and put the path in the above reference.

Next we add two buttons (this might not be the most pretty solution, but this is mostly about showing how this could be done!).

<input type=button value="morning" id="btnMorning">
<input type=button value="afternooen" id="btnAfternoon">

So the final step would be to hook to the click-events of the two buttons. Whenever one of the buttons are pressed, we just change the hour-selection for the start end end time of the event.

So the complete source looks like this:

<script language="javascript" src="/_layouts/jQuery/jquery-1.4.2.min.js" type="text/javascript"></script>
<input type=button value="morning" id="btnMorning">
<input type=button value="afternoon" id="btnAfternoon">
<script language="javascript">
  var startTime = $("#" + g_strDateTimeControlIDs["SPEventDate"] + "Hours");
  var endTime = $("#" + g_strDateTimeControlIDs["SPEndDate"] + "Hours");
$("#btnMorning").click(function() {
  startTime.val("08:");
  endTime.val("12:");
});
$("#btnAfternoon").click(function() {
  startTime.val("12:");
  endTime.val("18:");
});
</script>

Neat, if I may say so myself!