Brad's profileSharePoint BlogPhotosBlogLists Tools Help

Blog


    May 29

    The HTML Calculated Field

    I have been using this function a lot lately, as it's easy to build, easy to modify and does not require SPD's Data Form Web Part to create good looking lists. The basic premise behind it is you use a "calculated field" to construct a HTML String, then you throw a small bit of javascript on a page in a content editor web part (the js never changes from page to page, so you could lob it in a sharepoint js file too, as it does not affect anything else). This allows you to do things like apply traffic lights to any conditional test you can perform in Excel (as a calculated field has 90% of the functionality of excel formulas) or colour-code a list item based on its approval status. It's pretty cool, and really jazzes up your user interface – for example, you can colour a monthly calendar event to represent some type of event, without chewing up valuable real-estate describing the event in the item title.

    Cristophe also has some other neat features, such as a month calendar view that can be displayed on the right side of the screen without requiring a 1600x1200 display, a scrolling news item, etc. Check his site out to be inspired :) He also has some other sites containing content too - http://8002.freesharepoint2007.com/default.aspx and http://pathtosharepoint.wordpress.com/

    May 28

    Theming – a useful utility for getting colours

    So, more on the theming quest for knowledge – I was at a corporate site and they dumped this style guide on my desk and said "Follow That, sport" (actually, it was nothing like that, I'm just talking it up – it's a great client). After laughing my ass off at the Branding Nazi's (Marketing) choice of site colours, I thought – I could probably use one or 2 of these colours and come up with a nice theme. Maybe there is a tool on the web that'll help me…

    http://colorsontheweb.com/colorwizard.asp – Enter your hex colour code and hit go, and it'll pick colours that work together well (shades) and colours to use for "hover" and button effects (Tetradic and Split Complimentary were great for these).

    Oh, I also use Paint.NET to create and manipulate images, buttons etc – this was an undergraduate program started at MS to supersede MS Paint, but it's now a community tool. The best part are the plug-ins, but it's simple enough to use without being an art major. You can grab it here.

    A theme with the name "<themename> 1011" and version already exists on the server.

    First time I've ever hit this one – Building a custom theme for a client, using the technique Heather Solomon suggested here (Great strategy, saves heaps of time in testing cycles). Everything's going smashingly, then when I first change the test site to the new theme, it comes up with the dodgy message listed in the title.

    Googling found a few people with some unique ideas – Change the name of the theme (puh-lease), renaming the theme folder (uh-huh) and delete the cached theme using SPD (this was plausible at least, but didn't help me resolve the issue).

    In the end, I had to go in to the codepage value within the inf file in the themes folder to a different value (anything but what it was) and it resolved the problem. Thinking about it now, I probably could have deleted the file altogether as generally it's only used for multilingual environments so they can "read" the theme name in their native language, and has nothing to do with the theme functionality. One trap I'll remember for next time when copying a theme folder as a starting point for customisation.

    Thanks for the tip, Aris!

    May 26

    Search Not Working? Might be that an update has clobbered it…

    I’m starting to hit this problem so much lately that it’s now one of the first things I look for when a client calls me and indicates their search is not working properly. It also seems to affect authentication in other cases, and is more likely to occur in demo environments where everything sits on the one box (including the browser being used to access the site) – Mark Harrison's hit the issue recently too…

    A security bulletin came out on November 11th 2008 that discusses a remote code execution vulnerability. Almost all versions of Windows are affected by this vulnerability. SharePoint systems on <= Windows 2003 SP1 or Windows 2008 server have this patch installed. Implementing the patch causes an indexing server to fail when it attempts to index a site that is:

    • Hosted on the same server and
    • Uses a host header / DNS entry instead of a machine name and
    • Is being indexed using aforementioned DNS Entry
    • The site runs under a named account (an AD or Local Computer account, not say “Network Service”)

    Symptoms:

    • You will see errors in the indexing log that indicate access is denied to the web sites
    • You will see Errors in the Windows Security log that indicate Event ID 537 has occurred – this error will list the user as the crawling account used by your indexing engine, a logon type of 3 and a Logon process containing some unusual characters such as Ðùº
    • You will not be able to search for content that would normally be returned on those sites

    The text from the error is:

    "Access is denied. Verify that either the Default Content Access Account has access to this repository, or add a crawl rule to crawl this repository. If the repository being crawled is a SharePoint repository, verify that the account you are using has "Full Read" permissions on the SharePoint Web Application being crawled."

    Cause:

    The patch that was rolled out as part of the 2003 Service Pack and with Windows 2008 Server disable the service account’s ability to use cached authentication credentials to access the local resource – this prevents an authentication token playback exploit that the patch fixed.

    Resolution:

    There are 2 resolutions, neither of which involve modifying SharePoint or the security granted to the account. On the server running the indexing service, you need to enable a registry key that either:

    1. Enables an authentication request to be cached for a specific DNS name, or
    2. Enables all authentication requests to be cached for that computer (disabling the hotfix’s change).

    Option 2 needs a reboot. Now let’s say that you have a server farm. Every time you add a new web application with an Alias and you go with option 1, you need to apply the Registry update so that the site can be indexed. In most enterprises, this would be "discovered" post-Search implementation until it happened so often that it became annoying - and a process was put in place to update the registry key along with creating a search site. I can’t see many people buying this "Best Practice" option unless they work for a bank or somewhere with sensitive information. Here is the info from KB Article 896861:


    Method 1: Specify host names
    Note: Microsoft recommends that you use this method.
    To specify the host names that are mapped to the loopback address and can connect to Web sites on your computer, follow these steps:
    1. Click Start, click Run, type regedit, and then click OK.
    2. In Registry Editor, locate and then click the following registry key:

      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0

    3. Right-click MSV1_0, point to New, and then click Multi-String Value.
    4. Type BackConnectionHostNames, and then press ENTER.
    5. Right-click BackConnectionHostNames, and then click Modify.
    6. In the Value data box, type the host name or the host names for the sites that are on the local computer, and then click OK.
    7. Quit Registry Editor, and then restart the IISAdmin service.
    Method 2: Disable the loopback check
    Follow these steps:
    1. Click Start, click Run, type regedit, and then click OK.
    2. In Registry Editor, locate and then click the following registry key:

      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa

    3. Right-click Lsa, point to New, and then click DWORD Value.
    4. Type DisableLoopbackCheck, and then press ENTER.
    5. Right-click DisableLoopbackCheck, and then click Modify.
    6. In the Value data box, type 1, and then click OK.
    7. Quit Registry Editor, and then restart your computer.


    This is just one of those Search Issues that is not immediately clear… hopefully this saves someone more troubleshooting time than it cost me :)
    The only other mention I have seen of this issue specifically relating to SharePoint was here - http://stabilissolutions.blogspot.com/2009/02/sharepoint-2007-search-access-denied.html – Thanks Darren for pointing me in the right direction :)

    Brad

    May 23

    Logging anomalies in SharePoint Designer Workflows

    My mate Yaohan keeps telling me to “man up” and learn how to use Visual Studio and Windows Workflow Foundation to build SharePoint workflows. I just can’t bring myself to do it – It would be such a major transition for me that the rest of my work would suffer.

    Step Completion
    Something I’ve been noticing recently (while using my girly-girl SharePoint Designer workflows) is how the logging to workflow history behaves a bit strangely. When doing SPD workflow, the history log entries don't get written until the end of the step they’re created in... so if your workflow crashes out near the end of say step 6, the last log entry you'll see is the last one written on step 5. Sometimes this makes it hard to troubleshoot where the issue actually is.

    Serial Actions do not complete in order
    Also running actions in serial does not mean things complete in order. As an example: just because within a single workflow step “Action 1” creates an activity list item and assigns the item id to a variable, doesn't mean that “Task 2” (which writes the variable to another list item) will be writing any useful information (When it tries to read the variable, it reads an empty string and replaces it with ???? in some cases). This is because the reading of a variable happens a lot faster than the creating of an activity – and it looks like SharePoint is still creating the list item when it hands back control to the workflow. The only way to guarantee it (as far as I can tell) is to read the variable on a subsequent step.

    Commit & Proceed
    Putting these 2 issues together, it seems that there must be some kind of "Commit and proceed" phase at the end of each step. Having discovered these two anomalies, I've started to change the way I build workflows now to leverage this. I now try and spread my workflow out between multiple steps, with each step containing a decision (or conditional test) and a single action or activity for each “branch” of the decision (Think "Baby Steps").

    Custom Workflow Logging
    Also, I now use a custom list to log workflow progress (and configure the behavior of your workflows) for more complex workflows, or ones that need a permanent audit trail – this provides me with a permanent log (vs the history log which “cleans up” events after 60 days) and allows me to change the workflow behaviour without modifying the workflow. For example, if you build a workflow that emails a report to some execs, set a “debug” flag in a list or read the recipients from a list you’ve created. That way you can do all your testing with your own email address and set it up for Executive receipt once you have finalised it and ironed out the issues. Paul Galvin discusses the 60-day Workflow history log in more detail here, including recommending the creation of a Custom list to create a workflow log. Some other people have strong feelings on the thinking behind this “auto-cleanup” feature too, so much so that Microsoft have released instructions on how to disable the cleanup job.

    Brad

    May 22

    Whoopsie! Service Pack 2 has a 180 day timebomb…

    Sometimes things just don’t go according to plan. It looks like SharePoint’s latest service pack has a 180 day timebomb in it. There’s a patch coming, and the workaround is pretty easy – you just enter your key again.

    I feel sorry for the SharePoint dev team – they do such a good job, but people often remember the things that do not go so well… Hopefully this one will be quickly fixed and just as quickly forgotten… At least it does not affect people immediately.

    More details can be found here - http://blogs.msdn.com/sharepoint/archive/2009/05/21/attention-important-information-on-service-pack-2.aspx

    UPDATE: There's a hotfix available to fix it now. check it out here - http://support.microsoft.com/default.aspx?scid=kb;EN-US;971620

    May 18

    Bypassing the recycle bin

    Testing can be so much fun. You build up sites, fill them with rubbish data, tear them down, rinse and repeat. Recently I had a site I'd put a fair bit of effort into and the client loved it. Problem - how do I leave the site as it is, but remove all the bad data?

    Option 1: Once you have deleted all of the bad content from the lists, etc, you can go page by page through the recycle bin, 50 at a time and delete them from there... then do the same in the site collection recycle bin (this takes too long, gives me RSI)

    Option 2: You could go to Central admin, and under the web app delete everything in the site collection by switching off and on the recycle bin (not granular enough - deletes all recycled objects in all site collections within that Web app)

    Option 3: You can go to the recycle bin of interest, then enter the following into the address bar (by itself):
    javascript:emptyItems();
    Woah! Files in the recycle bin vanish, and people would not even know they existed. Lucky users don't know that this exists... oh wait, now they do :) - thanks to Jag from OBS who blogged this "gem" - http://itfootprint.wordpress.com/2008/03/14/empty-sharepoint-user-recycle-bin/ 

    Option 3 wins hands down.

    Brad

    May 17

    Can’t get the Room and Resource Reservation system working?

    Came across an issue with a client when deploying the Room and resource reservation system on a client site (you know, the one from Microsoft’s “Fab 40” collection with all of those pesky issues).

    Anyway, it was installing fine, no error, could create an RRR site… but it was not booking the rooms properly. Huh? I know about the fact you cannot delete a reservation (fixed that issue – future post), or that there’s a bug when creating resources in any locale except US (bug in the Workflow, fixed that)… but being able to book the same resource for the same time to 2 different people? Surely even the simplest test would have picked this one up!

    Turns out that there is a column that this “Conflict Detection” feature relies on… and if you try and install the application and this column exists as a site column for a parent (or a site collection column) then you’ll run into this. Problem is, I cannot remember the name of the column… and the environment is one I no longer have access to (so I cannot find out). I know this post does not have a specific resolution, but if you have installed this Template, and you find that you can “double-book” meeting rooms, check to make sure that the necessary feature is active – If it’s not, the error you get when you try to activate it will likely indicate a column name conflict.

    Cheers! B

    SharePoint 2010 Preliminary Requirements

    Some details have started to come out about the requirements for SharePoint 2010.

    Running it:

    • It can only be installed on 2008 Server
    • It will only be released in 64-bit, which means…
    • You can either install it on Windows 2008 64-bit OR Windows 2008 R2 64-bit

    Information Store:

    • You can only use SQL 2005 OR 2008
    • ONLY 64-bit versions of SQL 2005 or 2008 will be supported

    Using it:

    • You can only author content using a Windows machine and IE 7, IE 8 or (wait for it) Firefox 3 (I know, no way, right?) – Essentially the Browser MUST be XHTML 1.0 Compliant.
    • IE 6 will continue to be supported as a level 2 browser, along with FF 1.5, 2, Safari 3, etc… also IE 7, 8 and FF 3 will be supported as Level 2 browsers on other Operating systems (although they indicate that they’re working on removing the restriction on the OS).

    More info can be found here… - Announcing SharePoint Server 2010 Preliminary System Requirements

    Brad

    April 17

    SharePoint 2007 Service Pack SP2 has been released

    Update 29/04/2009 – The Service Pack 2 for SharePoint 2007 (that is, WSS 3 and MOSS 2007) has been released to the general public. You can get the Windows SharePoint Services one here and the Microsoft Office SharePoint Server one here.

    There are lots of changes (Change Log WSSChange Log MOSS) so please ensure you test this in a development environment first before rolling out to production.


    The release date for SharePoint 2007 SP2 has been set at the 28th April (2 weeks from today). There’s a write-up of the biggest changes here - http://blogs.technet.com/office_sustained_engineering/archive/2009/04/16/service-pack-2-for-the-2007-microsoft-office-system-due-to-ship-april-28th.aspx – The thing I’m most happy about is the fact that they are releasing the bugfix list as a spreadsheet again. Nice, very nice. Whack it in a SharePoint site, index it and you have a “That was fixed in Service Pack n” lookup feature for clients who are still on RTM (and who are in an unsupported state).

    Sweet! And information that’s much more useful than the name of the next version of SharePoint. Honestly, I’ve lost count of the number of blog entries proudly proclaiming that the next version of SharePoint is going to be called… wait for it… SharePoint Server! <Commence Sarcasm>WooHoo! I’ll sleep better tonight!</Commence Sarcasm>

    Anyway, keep an eye on this blog to be notified of the release http://blogs.technet.com/office_sustained_engineering/ (Or you could diarise it I suppose…)

    Brad

    April 03

    Creating Shared Hosted environments using WSS

    Just quickly wanted to blog this - here's a video on how to create a shared hosting environment using WSS 3 - the video was created by MCS so it's a good reference.
     
    March 25

    Renaming Title back to Title…

    I have just done this for a second time at a client’s site. Got a list, using content types, want to have the Title field appear in the list as something different (in my case, Question). So I happily rename the field, forgetting that this is a Site collection based field type that is in EVERY list – Damn, I hate racing the clock.

    Anyway, you can’t easily rename it back through the UI because “Title” is a reserved keyword (I reckon it’s a bug too) but you can using SharePoint Manager. SharePoint Manager is a great tool that lets you manipulate your SharePoint system in ways one could only dream about thru the User Interface – including bypassing that annoying “Reserved Keyword” message.

    Crack it open on one of your WFE servers, point to the right site, drill down until you get to the “Fields” collection. Underneath there, you will see the name you renamed title to – double check in the pane on the right and ensure the “Static Name” still says title. Then just edit the “Title” property back to Title and you’re done…

    Of course, the answer is to hide the field – but how? Mike Ferrara has the answer here. Essentially, you enable management of content types, set the field to “Hidden” and you’re on your way. Done! The only problem then is fixing up all of the other lists that have a “Title field. Let’s see, that’s… hmmm, carry the 2… All of them. Oh man…

    March 08

    Fishing an ItemID from a URL – the easy way

    I’ve recently started to follow Jeremy Jameson’s blog – He knows lots about MOSS and the associated technologies, and he always seems to be coming up with little “gems” of information. The post that led me to his blog was one he wrote where you can create a bookmark or quicklink which extracts the ItemID from the current URL in a browser.

    It’s a neat trick and could easily be expanded to a little toolbox of functionality for people who are constantly pulling things out of querystrings (like me). From his blog:


    Parse List Item ID
    How do I install the browser button?

    For Internet Explorer users:

    1. Right click the Parse List Item ID link and choose Add to Favorites.
    2. A security alert dialog will warn you that the link may be unsafe. Click Yes.
    3. In the Save in dropdown list, choose Links. Click Add.

    For Firefox users:

    1. Drag the Parse List Item ID link to your Links/Bookmarks toolbar.
    How do I uninstall the browser button?

    For Internet Explorer users:

    1. Right click the Parse List Item ID button on the Favorites toolbar and choose Delete.
    2. A confirmation dialog will warn you that the button will be permanently deleted. Click Yes.

    For Firefox users:

    1. Right click the Parse List Item ID button on the Links/Bookmarks toolbar and choose Delete.
    2. A confirmation dialog will warn you that the button will be permanently deleted. Click Yes.

    Cheers!

    Found a way to "Address" a SharePoint field using JavaScript

    One of the things that makes it a bit tough working with SharePoint pages is the fact that you cannot predict what the form fields will be called. They get random names like ctl00$m$g_b38c402f_5254_4ae1_8677_39beff22ef48$ctl00$ctl02$ctl00$ctl01$ctl00$ctl00$ctl02$ctl00$ctl00$ctl04$ctl00$ctl00$TextField and they change every time you change the form fields. Bah!

    Hopeless.

    However... in my hunt around for a solution to the Outlook Calendar times in GMT issue for one client, I came across this little gem of a script that solves this problem: http://blogs.msdn.com/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx

    The getTagFromIdentifierAndTitle code below grabs a Form field tag (id) based on the tag Name, Identifier and Title you pass in. In this code sample, they are using that information to pre-populate form fields in SharePoint from values in the querystring. One of the projects we’re working on at the moment has a common requirement to have the form fields pre-populated - this may be useful in that solution somewhere.


    <script type="text/javascript">   
    // This javascript sets the default value of a lookup field identified
    // by <<FIELD DISPLAY NAME>> to the value stored in the querysting variable
    // identified by <<QUERYSTRING VARIABLE NAME>>     
    // Customize this javascript by replacing <<FIELD DISPLAY NAME>> and
    // <<QUERYSTRING VARIABLE NAME>> with appropriate values.
    // Then just paste it into NewForm.aspx inside PlaceHolderMain   
    _spBodyOnLoadFunctionNames.push("fillDefaultValues");   
    function fillDefaultValues() {
       var qs = location.search.substring(1, location.search.length);
       var args = qs.split("&");
       var vals = new Object();
       for (var i=0; i < args.length; i++) {
         var nameVal = args[i].split("=");
         var temp = unescape(nameVal[1]).split('+');
         nameVal[1] = temp.join(' ');
         vals[nameVal[0]] = nameVal[1];
       }
        setLookupFromFieldName("<<FIELD DISPLAY NAME>>", vals["<<QUERYSTRING VARIABLE NAME>>"]); }

    function setLookupFromFieldName(fieldName, value) {
       if (value == undefined) return;
       var theSelect = getTagFromIdentifierAndTitle("select","Lookup",fieldName);
      // if theSelect is null, it means that the target list has more than
      // 20 items, and the Lookup is being rendered with an input element
        if (theSelect == null) {
           var theInput = getTagFromIdentifierAndTitle("input","",fieldName);
           ShowDropdown(theInput.id);
          //this function is provided by SharePoint
           var opt=document.getElementById(theInput.opt);
           setSelectedOption(opt, value);
           OptLoseFocus(opt);
          //this function is provided by SharePoint  
        } else {
         setSelectedOption(theSelect, value);
       }
    }  

    function setSelectedOption(select, value) {
       var opts = select.options;   var l = opts.length;
       if (select == null) return;   for (var i=0; i < l; i++) {
         if (opts[i].value == value) {
           select.selectedIndex = i;
           return true;
         }
       }
       return false;
    }

    function getTagFromIdentifierAndTitle(tagName, identifier, title) {
       var len = identifier.length;
       var tags = document.getElementsByTagName(tagName);
       for (var i=0; i < tags.length; i++) {
         var tempString = tags[i].id;
         if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {
           return tags[i];
         }
       }
       return null;
    }
    </script>


    Here's a list of the most common SharePoint Field types and their associated Identifier and tagName:

    SharePoint Field Type identifier tagName
    Single Line of Text TextField input
    Multiple Lines of Text TextField input
    Number TextField input
    Currency TextField input
    Choice (dropdown) DropDownChoice select
    Lookup (single)* Lookup select
    Lookup (multiple) SelectCandidate; SelectResult select
    Yes/No BooleanField input

    *Lookups are a bit more complicated because Lookup FormFields render differently when the target list contains more than 20 items. That's why the code above has a special function for Lookups

    March 07

    Hamlet, Act 2 scene 2 (Oh how I hate Daylight Savings, TimeZones, and the fact XML can’t deliver a date format JavaScript understands)

     Yes, while working onsite at a Client’s place I've been getting my hands all icky with code... I scrub and I scrub but all of the ocean's waters won't wash this code from my hands.

    Anyway, the point of this blog entry is to record the challenge that I had and the code I wrote to fix it, as it will be useful in the future for both me and maybe others. Essentially, the page I was fixing was giving me times in Zulu (GMT) - and in an XML format the JavaScript time functions could not understand. The business requirement was to have the times appear in Outlook in the same time zone the user was using. It took me the better part of a day, and I learned way too much about time zones and how to detect them on the user's computer, but I got there in the end.

    The original code for this was here - http://patrikluca.blogspot.com/2008/03/extension-to-rooms-and-equipment.html - an "Add to Outlook" button to go beside every Resource reservation, for a company still using a Lotus Notes app that allowed them to place multiple conflicting (overlapping) bookings on the same room / item.

    I leveraged the free "Resource Reservation" add-in for SharePoint and enhanced it according to the article, but when the users started using it they noticed that the times never matched. It was always 10 hours earlier than the real booking time that appeared in the page. Hmmm... 10 hours... Australia's GMT+10, so it must be passing them in as GMT Times.

    I updated the JavaScript so the times were changed back to the equivalent time zone (taking into account daylight savings) of the current user (Useful because this client is in 4 different time zones at any time as a minimum). There's only one problem in the code (and it's unlikely to be hit) but if a user books a resource for either side of a daylight savings change, then one of the times will be out by 1 hour. You can see the note I've put in there to remind myself if I ever get asked to fix it :)

    If you are copying the code, watch out for line breaks!


    function createOutlookAppointment(title,meetinglocation,startdate,enddate)    
    {
    // if you ever get asked to manage the booking hours over a DST change period, you will need to
    // test each date to see if it is in dst - isDST returns 1 if it is during DST, and 0 if not
    // if (isDST(startdate) - isDST(enddate)) = -1 then the end time is during DST
    // if (isDST(startdate) - isDST(enddate)) = 1 then the start time is during DST
    // however if the calculation = 0 then leave 'em be
    //   newAppt = new appt(title, meetinglocation, formatIncomingDateTime(startdate + '_' + isDST(startdate)), formatIncomingDateTime(enddate) + '_' + isDST(enddate));
       newAppt = new appt(title, meetinglocation, formatIncomingDateTime(startdate), formatIncomingDateTime(enddate));

      saveAppt( newAppt );
    }

    function isDST(incomingDateTime)
    {
    // This function detects if the inbound date and time is in Daylight savings time, and returns a 1 if it is, and a 0 if it's not
    // Kinda handy, seeing as DST is always "1" hour difference
    //I've dropped this in so I don't have to find it again if I ever do need to fix it
      var yearPart = incomingDateTime.substring(0,4);
      var monthPart = incomingDateTime.substring(5,7);
      var dayPart = incomingDateTime.substring(8,10);
      var d = new Date(yearPart, monthPart, dayPart);
    //   var d=new Date();
       var dY=d.getFullYear();
       var d1=new Date(dY,0,1,0,0,0,0);   
       var d2=new Date(dY,6,1,0,0,0,0);  
       var d1a=new Date((d1.toUTCString()).replace(" GMT",""));  
       var d2a=new Date((d2.toUTCString()).replace(" GMT",""));  
       var o1=(d1-d1a)/3600000;  
       var o2=(d2-d2a)/3600000;  
       var rV=0;  
       if (o1!=o2)
       {   
         d.setHours(0);
         d.setMinutes(0);
         d.setSeconds(0);
         d.setMilliseconds(0); 
         var da=new Date((d.toUTCString()).replace(" GMT",""));
         o3=(d-da)/3600000;   
         rV=(o3==o1)?0:1;  
        }
      return rV;
    }

    function formatIncomingDateTime(incomingDateTime){

      var timePartHours = incomingDateTime.substring(11,13);
      var timePartMinSecs = incomingDateTime.substring(13,16);
      var yearPart = incomingDateTime.substring(0,4);
      var monthPart = incomingDateTime.substring(5,7);
      var dayPart = incomingDateTime.substring(8,10);
      var newDate = new Date(yearPart, monthPart, dayPart); //gives us the current date and time in UTC
      var timeOffset = (newDate.getTimezoneOffset())/60; //gives us the amount of hours we need to deduct

      //create the date we are going to manipulate
      var myDate = new Date(yearPart, monthPart, dayPart);

      //calculate the hour we are booking for...
      timePartHoursInt = parseInt(timePartHours,10) - timeOffset;

      if (timePartHoursInt < 0) {
       //This means the booking hours + the time offset are really for yesterday...
       //because the timeoffset is the difference between current local time and GMT
       //so a negative number means we need to deduct a day and change it into real time again by adding 24h
       timePartHoursInt += 24;
       myDate.setDate(myDate.getDate() - 1);
      }
      else if (timePartHoursInt >= 24) {
       //in this case, we are booking for tomorrow (and midnight - 00:00:00 - is tomorrow)
       timePartHoursInt -= 24;
       myDate.setDate(myDate.getDate() + 1);
      }

    if (timePartHoursInt < 10) {
    // add a leading 0 to the time string so it's formatted in a standard way
    // then convert the int to a string
      timePartHours = '0'+timePartHoursInt.toString();
    }
    else {
      timePartHours = timePartHoursInt.toString();
    }

      if (myDate.getMonth() < 10)
    // add a leading 0 to the time string so it's formatted in a standard way
    // then convert the int to a string
       monthPart = '0'+myDate.getMonth();
      else
        monthPart = myDate.getMonth();

      if (myDate.getDate() < 10)
    // add a leading 0 to the time string so it's formatted in a standard way
    // then convert the int to a string
        dayPart = '0'+myDate.getDate();
      else
        dayPart = myDate.getDate();

      var datePart = myDate.getYear() + '-' + monthPart + '-' + dayPart;

      return datePart.concat(' '.concat(timePartHours).concat(timePartMinSecs));
    }

    function appt( Subject, Location, Start, End){

      this.Subject = Subject;
      this.Location = Location;
      this.Start = Start;
      this.End = End;

      this.ReminderMinutesBeforeStart = 15;
    }
    function saveAppt( obj ){

      var olAppointmentItem = 1;

      out = new ActiveXObject( "Outlook.Application" );

      appt = out.CreateItem( olAppointmentItem );

      appt.Subject = obj.Subject;
      appt.Location = obj.Location;
      appt.Start = obj.Start;
      appt.End = obj.End;

      appt.ReminderMinutesBeforeStart = obj.ReminderMinutesBeforeStart;         

      appt.Display();
      return null;
    }      


    This "Add to Outlook" button can be used on any page that can pass in a Start and End date, time, a Title (for the calendar appointment) and a location (eg a calendaring Confluence site?). With a bit of modification you could also add other attendees, a reminder, etc.

    However, the site hosting the link / button must be trusted for this to work properly. If the site appears in the "Internet Zone" you just get a JavaScript error. If your site sits in the Intranet security zone you get a security dialogue, asking you if you are sure you want to run this crazy activeX control.

    Anyway, an interesting day and a successful outcome for the client.Although a word of warning – the Room and Resource Reservation solution from Microsoft will deploy successfully on a Publishing website, however it will NOT stop users from booking an overlapping meeting (because there’s a conflicting named column or content type – one or the other).

    Brad

    March 04

    All my life, I’ve wanted a consistent Menu system…

    Up until now, menu systems for MOSS had to be built if you created new site collections that resided below the “parent” site (Parent in a URL-hierarchal sense). The team at RDA have released a few projects, but by far and away the best one from them (IMHO) is the Global Navigation solution in CodePlex.

    Basically, you can nominate a web site or set of web sites you want to have the navigation based on, then using a separate administration page, Staple it to whichever web sites you want. I hope to try it out on one of our lab servers soon, and if it works as described I’ll just start rolling this out as a matter of course for all of the clients I create intranet sites for, where you will often have separate site collections with separate navigation in the same URL hierarchy.

    You can get the code and binaries for it here – there’s also a blog entry with screen shots here – I just wish they’d explain what they mean by the phrase “associating a Data Source with all sites” – Is the web site the data source? A Database table?

    Cheers!
    Brad

    February 25

    New hotfixes for WSS and MOSS (SharePoint 2007)

    And not a moment too soon! We rolled out the infrastructure update to a client just recently to resolve an issue they were having where emails coming into an email-enabled document library were not triggering a workflow. As most people know, the Infrastructure Update breaks Alternate Access Mappings when using Load-balancing or Proxies… so if you use them, you then need to install at least the next hotfix rollup that came out after it.

    So that was the plan… and all was going swimmingly until we looked at the workflow and realised that they were all failing – it appears as though the October and December hotfixes introduced an issue where updates to user columns failed when running through SharePoint Designer workflow. It’s like playing Whack-a-mole.

    Anyway, the new hotfixes have just been released and they fix a lot of outstanding issues – they can be found here for WSS - http://support.microsoft.com/kb/961750 – and here for MOSS - http://support.microsoft.com/kb/961749. I can’t find the hotfix rollup yet, so until they are published, these should ideally be deployed on farms that already have the December releases.

    **UPDATE** - The Rollups for February have been released, as announced on Todd Klindt's blog - http://www.toddklindt.com/blog/Lists/Posts/Post.aspx?List=56f96349%2D3bb6%2D4087%2D94f4%2D7f95ff4ca81f&ID=111 - get them here (WSS3) and here (MOSS 2007)

    **UPDATE** - Joerg Sinemus has updated his blog with the information required to roll these out. Until the uber-patches are released, you need to be at least running SP1, however there are no other prerequisites as per his article... having said that, other people have had problems if they do not yet have the infrastructure update installed and they try to install a hotfix pack released after the Infrastructure Update was released.


    The big or “uber” packages are not yet available. CAPES (Customer and Partner Engineering Services team in Microsoft) is still working on these so please stay tuned. If you need to immediately install the Feb Hotfix update please read & follow the checklist.

     Checklist to install Feb CU:

    - Preqs are WSS and MOSS Global SP1 and all language specific SP1
    - Install WSS Global 961750 (Feb Hotfix pack WSS)
    - For each language including the installed one install language specific WSS 967703
    - Install MOSS Global 961749 (Feb Hotfix Pack MOSS)
    - For each language including the installed one install language specific MOSS 961754
    - Run psconfig -cmd upgrade -inplace b2b –force


    List of issues resolved is as follows:WSS


  • When you decline a recurring meeting request from the meeting workspace, the e-mail message that is sent by the SharePoint server is not recognized by Microsoft Office Outlook 2007 as a meeting declination. Therefore, Outlook does not update the meeting attendee status to "Declined."
  • You migrate discussion boards from Windows SharePoint Services 2.0 to Windows SharePoint Services 3.0. Discussion boards work fine after that. However, if you export and import a discussion board into another Windows SharePoint Services 3.0 site, the thread relationship is broken, and all entries appear in one list.
  • Content deployment target site permissions that are not inherited can be removed.
  • The entries for e-mail-enabled lists are being deleted from the EmailEnabledLists table in the configuration database. When this issue occurs, incoming e-mail messages for these lists are not delivered. Therefore, the e-mail messages are deleted, and errors are logged for "Unkown alias."
  • If you have a list that has more than 500 unique scope IDs and if the Content Approval option is enabled, duplicated items may appear in the default view of this list.
  • In a Windows SharePoint Services 3.0 site, alerts for All day Calendar events do not show the correct start and end time in alert e-mail messages.
  • When you try to modify group membership of the built-in groups of site collections, you may receive a "System.UnauthorizedAccessException" exception. For example, this issue may occur when you try to add a new user to a built-in group. Built-in groups include visitors, owners, members, and so on.
  • If you use the SharePoint Content Migration API to export large sites, the performance is poor.
  • You create a new page in the source variation by using a customized page layout that has calculated columns. However, when you try to allow the variation engine to propagate the new page to the other variation label Web sites, it fails.
  • When you move through a specific blog category page, you cannot move to the Next page of blog entries. By default, the paging is set to 10 items per page. However, when you move to the next page in a category, a "There are no posts in this category" message is displayed. This message is incorrect. Paging in the All Posts area works as expected.
  • Before an incremental content deployment, you activate and then deactivate the feature that creates content types on both the source site and the destination site. During the incremental deployment, the content type delete operation fails, and the content deployment stops with an error message.
  • All meetings that you view under a meeting workspace display folder numbers instead of document names.
  • You create a versioned page, and you create a major version and a minor version. When you delete the versioned page and try to export the document library, it fails.
  • If you have an orphan site collection, the XML produced by the stsadm -o enumsites command is not well formed, as shown in the following example.

    <Sites Count="3"> 
    <Site Url="http://webapp/" ... /> 
    <Site Error="Error message">  
    <Site Url="http://webapp/..." ... /> 
    </Site>

    The last tag is missing an "s." It should be </Sites>. Also, the <site Error …> tag is not correctly closed.

  • After you install update 957691, you cannot set a user type column from the workflow when you create a new list item.
  • If you programmatically run the SPListItem.SystemUpdate(bool) method on a document library, the latest check-in comment will be removed.
  • If you add a Site Columns choice type that has a slash (/) in the column name to a document library, you cannot change the value of it on a SharePoint site. However, you can change the value by opening the document in Microsoft Word, editing the property, and saving it back to the document library.
  • When you build an application to control a document library, the SPFolder.CopyTo() method does not increase the List.ItemCount number, this will cause inconsistency in the list.
  • The Microsoft PKM Search Filter Daemon (Mssdmn.exe) crashes every 15 seconds when crawled using certificate authentication.
  • When you try to back up the Shared Search index, it always fails, and you receive the following error message in the backup log:

    [30/9/2008 2:11:46]: Verbose: Starting object: Shared Search Index. [30/9/2008 3:12:17]: Error: Object Shared Search Index failed in event OnBackupComplete. For more information, see the error log located in the backup directory. WebException: The current operation timed-out after 3600 seconds [30/9/2008 3:12:17]: Debug: at Microsoft.Office.Server.Search.Administration.CatalogPauseTimeout.WaitAndThrowIfTimeout() at Microsoft.Office.Server.Search.Administration.SearchApi.CatalogResumeCrawl(GathererPauseReason reason) at Microsoft.Office.Server.Search.Administration.SearchSharedApplication.Microsoft.SharePoint.Administration.Backup.IBackupRestore.OnBackupComplete(Object sender, SPBackupInformation args) [30/9/2008 3:12:17]: Verbose: Starting object: SharedServices_Default_Search.

  • When you search on a SharePoint site, the performance may sometimes be slow.
  • Search results are not security trimmed for anonymous users who access the sites that have the lockdown feature activated.
    MOSS
    • The UserProfileChangeService service does not report user deletions.
    • If blob caching is enabled for a Web site, you cannot download files whose size is more than 32 megabytes (MB) from that Web site.
    • When you open a SharePoint Search site by using SharePoint Designer, the W3wp.exe process crashes.
    • You create a new page based on the "(Welcome Page) Welcome page with summary links" page layout. You add a new link to the Summary Links Web part, and you use a URL that starts with "mms://". However, the newly added link is an empty link.
    • You convert a Word document (.docx) to a Web page on a SharePoint site. However, the multi level numbering is incorrect. For example, 1.1 may be displayed as 0.1.
    • When you use spelling check in a Spanish site, it fails and you may receive the following error message:

      Spell checking is not available for the default language. Choose one of the following languages and click OK to continue spelling, or click Cancel to stop.

    • A Shared Services Timer job opens handles for each task, but the job does not close the handles. Because the type is set to manual reset for these handles, the garbage collector cannot clean them up. Therefore, a handle leak occurs in the Owstimer.exe process.
    • You have a Word document (.docx) that has Track Changes enabled. You convert the Word document to a Web page on a SharePoint site. However, deleted words are displayed in the conversion results as unhidden text.
    • If you disable the Show Subsites option on the navigation settings page and repeatedly visit a subsite, you see high latency and low throughput.
    • The variation engine cannot restore destination page properties if the page contains a Content Query Web part.
    • When you set a publishing time for a page in SharePoint, the publishing time may shift incorrectly if the time zone is not Coordinated Universal Time (UTC). This behavior occurs for the end time too.
    • If you input Date type cells in Excel 2007 files, the XLSX Filter extracts them as numbers.
    • A Variation Page propagation job cannot transfer updated content to target labels if the page has a comma in the URL. This is because the Variation engine cannot find propagated pages that have a comma in the URL.
    • The Business Data List Web part is not using the Regional Settings collation when it sorts the data.
    • When you build an application to control a document library, the SPFolder.CopyTo() API does not increase the List.ItemCount number. This behavior causes inconsistency in the List.
    • The Microsoft PKM Search Filter Daemon (Mssdmn.exe) crashes every 15 seconds when crawled using certificate authentication.
    • When you back up the Shared Search index, it always fails, and you may receive the following error message in the backup log:

      [30/9/2008 2:11:46]: Verbose: Starting object: Shared Search Index. [30/9/2008 3:12:17]: Error: Object Shared Search Index failed in event OnBackupComplete. For more information, see the error log located in the backup directory. WebException: The current operation timed-out after 3600 seconds [30/9/2008 3:12:17]: Debug: at Microsoft.Office.Server.Search.Administration.CatalogPauseTimeout.WaitAndThrowIfTimeout() at Microsoft.Office.Server.Search.Administration.SearchApi.CatalogResumeCrawl(GathererPauseReason reason) at Microsoft.Office.Server.Search.Administration.SearchSharedApplication.Microsoft.SharePoint.Administration.Backup.IBackupRestore.OnBackupComplete(Object sender, SPBackupInformation args) [30/9/2008 3:12:17]: Verbose: Starting object: SharedServices_Default_Search.

    • When you search on a SharePoint site, the performance may be slow.
    • Search results are not properly security trimmed for anonymous users who access the SharePoint sites that have the Lockdown feature activated.
    This release also includes fixes that are described in the following Microsoft Knowledge Base articles:
    • 961176 (http://support.microsoft.com/kb/961176/ ) Description of the SharePoint Server 2007 hotfix package (Coreserver.msp): December 19, 2008

    • 961176 (http://support.microsoft.com/kb/961176/ ) Description of the SharePoint Server 2007 hotfix package (Coreserver.msp): December 19, 2008

    • 963022 (http://support.microsoft.com/kb/963022/ ) Description of the SharePoint Server 2007 hotfix package (Coreserver.msp): January 27, 2009

  • February 24

    The Hosts file – here today, gone today!

    When I set up a SharePoint system, I like to ensure that it’s set up according to Microsoft’s “Least Privilege Access” rule. It means that if the site ever gets compromised, the user has no access to other resources except ones directly related to SharePoint.

    I was at a client’s site recently running an upgrade. Only one failure – It said that it could not find the hosts file… so I recreated the hosts file and reran the upgrade. No problems this time. Once I’d finished however, I noticed that there were a lot of errors coming up in the event log:


    Application Server Administration job failed for service instance Microsoft.Office.Server.Search.Administration.SearchServiceInstance (...).

    Reason: Could not find file 'C:\Windows\system32\drivers\etc\HOSTS'.

    Techinal Support Details:
    System.IO.FileNotFoundException: Could not find file 'C:\Windows\system32\drivers\etc\HOSTS'.
    File name: 'C:\Windows\system32\drivers\etc\HOSTS'
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.FileStream.Init(...)
       at System.IO.FileStream..ctor(...)
       at System.IO.StreamReader..ctor(...)
       at System.IO.FileInfo.OpenText()
       at Microsoft.Search.Administration.Security.HOSTSFile.ParseHOSTSFile(...)
       at Microsoft.Search.Administration.Security.HOSTSFile.ConfigureDedicatedGathering(...)
       at Microsoft.Office.Server.Search.Administration.SearchServiceInstance.SynchronizeDefaultContentSource


    The hosts file had disappeared again. Damn. Recreated it, but in about a minute it went again and these errors started up again. After a quick search, I uncovered this gem of an article which described the issue perfectly. It looks like the testing done for this feature was somewhat flawed.

    The solution is to grant permissions to the folder that the hosts file resides in – once the hosts file is deleted, then the service can recreate the hosts file the way its creator intended.

    Original article was here - http://blogs.msdn.com/jjameson/archive/2007/05/05/the-case-of-the-disappearing-hosts-file.aspx

    Brad

    February 19

    Had an interesting discussion after the last SharePoint User Group

    I really enjoyed myself at the last user group. I was all prepared to snore my way through it, but found that I was actually very interested.

    The usergroup was about Accessibility – a pretty lonely topic, less popular even than Governance. However, the presenter was a hearing-impaired, blind person who gave a very interesting speech. I was delighted because I wasn’t being forced to hear about another vendor product they say is for everyone and I think has an extremely limited scope… and because the presentation was interesting.

    But the most enjoyable part was once the presenter had finished – we started chatting amongst ourselves (there was about 20 people) about what the answer was. How do we make our systems more accessible? What technologies are out there today? Where do we need to be? What are the benefits? Downsides? There were several opinions – Most stemmed from personal experience. From a practical point of view, there were only really 3 things that could be improved - they were:

    1. The tools that visually impaired people use to interact with computer systems needs to be made better
    2. The languages that we use to create and “describe” the user interfaces needs to be made better
    3. The tools that developers use to build the UI need to be made better

    The problem with 1 & 3 is cost and motivation. 2 has already been solved – by using XML, people can create dynamic sites that are engaging and accessible. So what’s stopping a proliferation of web sites running XML with an XSL presentation layer? In the past it was bandwidth. XML is a heavy language – there’s no denying it… but these days bandwidth’s cheap and available to most… so it’s not so much of an issue.
    The tools we have today do not really facilitate using this type of language or developing in this way (that’s 3). Because visually impaired people are a minority, it’s difficult to get the type of private equity money invested into 1 – and if you do, the market is small and people with accessibility issues are generally at the lower end of the socioeconomic scale, making the potential market even smaller.

    The solution seems to be clear – make better developer tools – but an improvement in tools by vendors for something that is not being demanded or mandated is a tough ask (Vendors are looking for the “point of difference” in their product, not the same thing but in a different backend language). In the past, there has been considerable effort put into accessibility when governments started saying things like “We’ll only buy software that meets the following accessibility standards” – in fact, the only reason Windows has them is because governments were about to refuse to buy their OS as it didn’t have it “baked in”. So…

    Maybe what we need is some way for governments to say that they’ll only buy development tools that allow them to build web sites that meet accessibility standards with the same speed that they can build non-accessible sites. Hmmm… that’s a bit hard to quantify or measure. What about “We’ll only buy development tools that give developers the choice of creating the presentation layer of their solutions in either native code or a combination of XML+XSL”. That’s better – at least we can measure that.

    OK… That takes care of the guts of a web page, but how about the slick UI? What about Silverlight? Well… Silverlight uses XML to represent its functionality. It has limitations, but it’s getting there. What about InfoPath? InfoPath forms are ALL XML, with an XSL skin on them that gives them a rich UI experience in Forms Server. So you can see that we’re close. I mean, we have a language that is regarded as “Self-Describing” – that’s XML. We have tools that can have their toolset extended – in VS2008 you can implement your own intellisense for any language you can dream up. People have implemented CAML intellisense for VS2008. In a corporate environment where the devs are using this particular tool, you could conceivably build a corporate standard for XML and an XSL that maps to the corporate tags. XMLSpy has excellent capabilities, but the learning curve is steep.

    So we’re close… we have the capacity to enhance our current tools to meet the need for people with visual impairments. The population is aging, which will only increase the demand for these types of features. We have the language, and the overhead of running a UI layer through XML & XSL is being countered by the increase of available bandwidth to Joe user (even here in Australia, where ADSL1 is still kinda cool). Does anyone else have an opinion on this? Is there a better way to do it? I’m not on a personal crusade here, I don’t know anyone who’s blind, but it seems a bit silly that we’re 90% there and everyone’s looking at everyone else and say “you go first” “no you go first” “no, I insist, after you” etc.

    Anyway, just thought I’d get this down to see if there is a better approach. BTW – SharePoint has an “Accessibility” setting that can be turned on and off. Turning it on reduces some of the slick functionality in the UI but it makes it easier for screen readers to interpret what’s going on and let the users know.

    Lastly, if you are determined to build an accessible site or app the only true test of whether a user interface / web page is accessible is to get a blind person to try it for you. It’s easy to make something that is accessible, but a lot harder to retrofit it.

    Just my thoughts…

    Brad

    February 15

    Charities do it Cheaper!

    CustomWare does a lot of NFP and charity work as well as their commercial work. I was at the SharePoint user group in November ant one of the Microsoft employees there mentioned that there is a site these type of organisations can go to called http://www.donortec.com.au/ - here they can buy software from companies such as Microsoft, Cisco, Flickr etc for a fraction of the cost of going retail. for example:
     
    Office 2007 Professional normally sells at $500US - you can pick up Office 2007 Professional Plus for $30AU. That's a fair slab of savings!
    Or how about...
    SharePoint Server 2007 Enterprise Server? $377. Sweet!