Training Site Template – Part 2: Workflows

Sean Hey there,

 It's Sean again with another installment of the template development walkthrough. Last time we covered the list schema for the Employee Training Scheduling and Materials template, one of the new Application Templates for Windows SharePoint Services 3.0. In this series I'm showing you how we built one of these templates from the ground up, and today we're going to author all of the training site's workflows using SharePoint Designer. With that done, you'll have built the whole back-end of the template, so in a future installment we'll get our hands dirty with SharePoint's views and forms.

Folder List (Training Site)Open up a fresh installation of the training site in SPD and you'll see the folder list pictured on the right - with the three workflows you'll be creating today in the Workflow Designer. They'll provide some of the rich behavior that you wouldn't see in a static web app, and you won't need to write any code to get it done. Let's get started!

Automatic Reminders

People are forgetful. Computers aren't. So when an instructor comes to your training site to create a course, why should they have to remember when it is? That's where you can come in with this workflow, which we'll set on the Courses list:

  1. In SPD, go to File > New > Workflow...
  2. Name it "Instructor reminder" and attach it to the SharePoint list "Courses"
  3. Check the box to Automatically start this workflow when a new item is created
  4. Click Next > to continue

From here you'll want to create 3 steps which will logically separate our workflow into sets of related actions. Click Add workflow step to move on to the next step, and in each case if you don't see the specific action listed, click the Actions button > More Actions... to see the full list. Additionally I'm using [brackets] to refer to what you need to do in each placeholder.

Also, fx just means the data binding button. You get the same dialog whenever you push Add Lookup to Body in the e-mail builder.

So before you start, first create two variables (click Variables... > Add... to make them), one called "Reminder Time" (Date/Time) and one called "Subject" (String). You'll need them once you get to the individual steps:

  1. First step: name it "Set reminder time"
    1. No conditions
    2. Actions > Add Time to Date - Add -24 hours to [fx :: Current Item, Start Time] (Output to Variable: Reminder Time)
    3. Actions > Build Dynamic String - Store "RE: [fx :: Current Item, Course Title]" in Variable: Subject
  2. Second step: name it "Send confirmation"
    1. No conditions
    2. Actions > Send an Email - Email [...]
      1. To: Workflow Lookup... :: Current Item, Instructor
      2. Subject: fx :: Current Item, Course Title
      3. Body: This is a confirmation that you are scheduled to teach [Add Lookup to Body :: Current Item, Course Title] on [Add Lookup to Body :: Current Item, Start Time] at [Add Lookup to Body :: Current Item, Location]. For more information, please visit the training site.
  3. Third step: name it "Send reminder about course"
    1. Conditions > Compare Courses field - If Created is less than [fx :: Workflow Data, Variable: Reminder Time]
    2. Actions > Pause Until Date - Pause until [fx :: Workflow Data, Variable: Reminder Time]
    3. Actions > Send an Email - Email [...]
      1. To: same as above
      2. Subject: fx :: Workflow Data, Variable: Subject
      3. Body: This is a reminder that you are scheduled to teach [Add Lookup to Body :: Current Item, Course Title] on [Add Lookup to Body :: Current Item, Start Time] at [Add Lookup to Body :: Current Item, Location] in 24 hours. For more information, please visit the training site.
  4. Click Finish

Make sense? We're sending two reminders to anyone who adds a new item to the Courses list (i.e. an instructor creating a course) - one right when they make it as a confirmation, and another 24 hours before the course is scheduled. And the first step was just to keep the variable assignment separate, there's nothing wrong with doing it in the other steps right before they are used.

We'll want to do a similar reminder for students, but we can do it at the same time that we enforce seating policy (each item in Courses has an Available Seats and Total Seats) since it only really makes sense to send reminders if you actually make it into a course.

Processing Student Registrations

If you try to add a new course by browsing to Courses > New..., you'll see this line in the new form:

And you'll also notice that there's no line for Available Seats or Filled Seats, even though we added those fields to the Courses schema in part one. I'll teach you the trick to hide form items next time, what's important here now is that 0 will be our sentinel value in the workflow to come.

Let's go through this one a bit faster by using some shorthand.

  • ... means I'm referring to a string (probably for those long auto-generated e-mails) that you can find the full text for by opening Attendee registration.xoml in SPD.
  • Courses* means you need to perform a lookup back into the Courses list. To do this, start by pushing fx and pick Source: Courses, at which point you'll see the "Find the List Item" section appear. In that section, match Field: Courses:ID to Value: Registrations:Course ID (use the nearby fx :: Current Item, Course ID).
  • Variable: = anything with a leading Variable: in front of it is a workflow variable that can be found in fx :: Workflow Data.

Start with a new workflow called "Attendee registration," attached to Registrations and triggered when an item is created. Create 7 variables before you begin, 4 of type String (Subject, Confirmation Body, Reminder Body, Reminder Body 2), 2 Date/Time (Reminder Time, Reminder Time 2), and 1 Number (New Filled Seats). From there build out the steps:

  1. "Cache all variables"
    1. No conditions
    2. Actions > Build Dynamic String (x4)
      1. Store ... in Variable: Confirmation Body
      2. Store ... in Variable: Reminder Body
      3. Store ... in Variable: Reminder Body 2
      4. Store ... in Variable: Subject
  2. "Enforce seating policy"
    1. Conditions > Compare any data source (x2)
      1. If [fx :: Courses*, Total Seats] equals 0
      2. or [fx :: Courses*, Filled Seats] is less than [fx :: Courses*, Total Seats]
    2. Actions > Set Workflow Variable (x2)
      1. Set Variable: Reminder Time to [fx :: Courses*, Start Time]
      2. Set Variable: Reminder Time 2 to [fx :: Courses*, End Time]
    3. Actions > Do Calculation - Calculate [fx :: Courses*, Filled Seats] plus 1 (Output to Variable: New Filled Seats)
    4. Actions > Update List Item
      1. List: Courses*
      2. Add... :: Set Filled Seats to Variable: New Filled Seats
    5. Click Add 'Else If' Conditional Branch
    6. No conditions
    7. Actions > Delete Item - Delete item in Registrations (Current Item)
    8. Actions > Stop Workflow - Stop the workflow and log "Course is already full."
  3. "Set reminder time"
    1. No conditions
    2. Actions > Add Time to Date - Add -24 hours to Variable: Reminder Time (Output to Variable: Reminder Time)
  4. "Send confirmation"
    1. No conditions
    2. Actions > Send an Email - Email ...
  5. "Send reminder about course"
    1. Conditions > Compare Registrations field - If Created is less than Variable: Reminder Time
    2. Actions > Pause Until Date - Pause until Variable: Reminder Time
    3. Actions > Send an Email - Email ...
  6. "Send reminder for feedback"
    1. Conditions > Compare Registrations field - If Created is less than Variable: Reminder Time 2
    2. Actions > Pause Until Date - Pause until Variable: Reminder Time 2
    3. Actions > Send an Email - Email ...
  7. "Move to Past Registrations"
    1. No conditions
    2. Actions > Copy List Item - Copy item in Registrations (Current Item) to Past Registrations
    3. Actions > Delete Item - Delete item in Registrations (Current Item)

Yikes, I know. But thankfully that's about as bad as it gets. Here's a brief explanation - a student will register for a course, but they won't get in right away (technically, they get in but they may be kicked out immediately if the seating logic fails). After setting all the variables we check if Total Seats is 0 (unlimited) or greater than Filled Seats (i.e. is there room in the course?). If not, we abort prematurely (delete/stop step two), otherwise we do the math and add 1 to the Filled Seats, send reminders, etc. The last step is the archival in the mirror list Past Registrations, something that will become more evident in part three when we build up the front end.

A Dirty Workflow Secret

That's all well and good, but what happens when someone wants to unregister from the course? We need to subtract 1 from the number of Filled Seats, then delete their registration from Registrations, but here's a problem - workflow cannot be triggered to run before an item is deleted. So here's how we'll fake it - since workflow can run when an item is changed, we'll set up another sentinel value for our workflow to be interested in. DELETE seems pretty self explanatory, right?

(Note that this workaround has some serious implications - we'll need to hide item deletion in Registrations and block all edits to our field so the user never trips the sentinel. Don't worry, I'll explain in due time...)

Our last workflow, "Attendee unregistration" (for lack of a better word), attached to Registrations, triggered when an item is changed. One variable before you start: a String called Log Message. Not even really necessary, just for posterity:

  1. "Unregister from course"
    1. Conditions > Compare Registrations field - If Title equals "DELETE"
    2. Actions > Delete Item - Delete item in Registrations (Current Item)
    3. Actions > Build Dynamic String - Store ... in Variable: Log Message
    4. Actions > Stop Workflow - Stop the workflow and log Variable: Log Message

And there you have it, dynamic behavior that takes a long time to spell out in a blog post, but goes a long way towards the richness and robustness of your SharePoint app. It's taken us a few key design decisions to get here, and so in part three we'll learn what consequences that holds for the front end system, which is driven by SharePoint views and forms. I'll see you then!


Comments (100)

  1. CQuick says:

    In the first workflow, Instructor Reminder, you set a variable for the subject and then never use it. However, looking at the template, it appears you actually use that variable in the third step, Send reminder about course. Just thought I’d point that out…

    Another great tutorial… looking forward to the next one!

  2. CQuick says:

    Also, in the second workflow you never set the value for the variable Reminder Date 2. Shouldn’t this be set to the course start time + 24 hours?

  3. Gus Revolorio says:

    Great tutorial Sean!!!

    One complaint I’ve had on the applications released in the past, is the lack of documentation on what all they do.  Without your explanation I would’ve never even downloaded the application, but now that I know all that I can do with it I see the enormous value of the application, thanks for creating it and thanks for sharing with us how you did it.

    One question, do you have any suggestions on how to add on-demand courses to the Courses Schedule?

    Thanks in advance,


  4. paolonu says:

    Well, the workflow designing seems to be nice and easy, but in my first attempts to realize some new ones to train myself on Sharepoint Designer and WSS 3.0 I suddenly came to a stop.

    It happens on two points on Calendar events creation on which i’d like to get some help:

    1) I’m trying to set the lasting of an event after i created it to a precise amount of time (e.g. 3 days). After making "Actions > Add Time to Date – Add 72 hours to [fx :: Current Item, Start Time] (Output to Variable: Reminder Time)" and "Actions > Set Field to Value – Set [fx :: Current Item, End Time] to [fx :: Workflow Data, Variable: Reminder Time]" i get an error from the WSS 3.0 installation.

    2) I’d like to automatically create a Workspace related to a Calendar event the moment a certain user creates such event. How should i do?

    Thanks for your help

    Paolo Nugnes

  5. spdblog says:

    CQuick: thanks for the catch in the "Instructor reminder" workflow, I’ll add the correction (meant to use the "RE:" string in the second e-mail). As for "Attendee registration" Reminder Time 2 gets set to the related course’s End Time in step 2.2.2. We use it later in e-mail for step 6.

    Gus: appreciate the feedback! You could try setting a Start Time far into the past, and End Time far into the future – you’d then see the course span every calendar cell, so it would seem "dateless." Admittedly this is going to be clunky… the real problem is that Start and End Time are both required with the Calendar content type so you can’t alter that at the app level. You may just want to make a separate list (i.e. On-Demand Courses) for those special cases, and adapt the dashboard views to include it (we’ll get to the dashboard in a future installment).

    Paolo: with your workflow, it sounds like what you’re doing is correct but if you’re still getting errors, try setting the End Time separately (similarly to the template, do all the date math in one step and then actually set the list item’s fields in another step). As for Meeting Workspaces, I’ll cover view customizations in the next article – the one you’ll be interested in is Courses/NewForm.aspx, and setting a default value on the checkbox that we’ve hidden away. Stay tuned…



  6. Tubs says:

    Thanks for this tutorial Sean, its given me the kick start I have been looking for (and has saved me buying webparts that I thought I required). I think that only were scratching on the surface of a very powerful tool. Keep at it, looking forward to the next tutorial.

    Questions (hope theyre not too stupid):

    What happens to the workflows that are "paused" (e.g. the reminder) if I have to re-boot the server?

    The Action "Calculate …" allows for very simple formulas (plus, minus etc.) Is there a way to perform more complex calculations using, for example, the formuals available on the WSS site. A simple example would be to calculate the working days between two dates.

    Thanks in advance


  7. spdblog says:

    Tubs: definitely good questions to ask. When a workflow is paused, it gets pushed down into the database (in this sleeping state, we often call the workflow "dehydrated") so a server reboot will not cause the workflow to lose its state. If the wake-up time passes while the server is still in the process of rebooting, the engine will kick start the workflow once the machine goes up again.

    You’re right in that our support for date math within workflow today is limited. You’d be best served by expressing the calculation you want in WSS (e.g. create a new column in your list, a calculated field type that does End Time – Start Time) and then using that column wherever you need the calculated value within your workflow.



  8. David says:



    I really like this template and I’ve implemented it at our College for employee training purposes.  We have a department dedicated to Faculty & Staff training and they have many events “Courses” running every day.  This used to cause a massive administrative burden for their secretary — and with your magic I was able to reduce their workload immensely AND provide a central place for course documents an awesome archive for them.  Many thanks!


    I’m POSITIVE that I have permission settings wrong and this is causing workflows (triggered by registrations and UNregistrations) to fail.  I see this message: “Failed on start (retrying)” for all registrations (except for users who have “Design” permission throughout the app).  The description of the error is “Error updated a list item”; the outcome “Access Denied”; and the User ID is “System Account”.  (But this seems misleading…how can the system account be denied access, right?)

    I’ve posted two messages in the Sharepoint newsgroups about this problem but haven’t seen any responses:


    My permissions break down like this:

    – The “Employee Training Scheduling and Materials” template was created as a subsite and all our Active Directory users have “Read” permission throughout that subsite.  (These registrations fail.)

    – A small group of people who manage the training have “Design” permission. (These registrations succeed.)

    – All site content inherits those permission settings except:

    — “Course Surveys” allows all users to “Contribute” in addition to “Read”.

    — For “Registrations” and “Past Registrations” and “Tasks” I’ve given all users “Design” permission in addition to “Read” — (I did this hoping that the workflows wouldn’t fail, but they still fail.)

    It would appear that the “Courses” list also requires ‘more than Read’ permission for all users, but how then can I prevent ‘just any employee’ adding an event to this calendar?

    I realize this isn’t a “forum” for questions, but perhaps in your next article you might address the matter of “Permissions” and how to configure the tools in this template to ensure that the workflow works properly.

    Again…thanks for a great app — and I’m totally enjoying WSS.3

  9. paolonu says:

    It seems it doesn’t want to work… 🙁

    Even if i separate in different steps the "+3 days" calculation from the variable to field assignment it keeps giving me errors.

    I tried it on different installations but the problems keeps happening.

    I even tried to set the value to a string field. Then i found the value in "dd/mm/yyyy" format instead of "dd/mm/yyyy" but i don’t think this should be a problem. Or is it?

    Thanks again for your help

    Paolo Nugnes

  10. spdblog says:

    David: it’s great to hear the template site is working out for you overall. I apologize that we didn’t get to your newsgroup posts right away, commenting on the blog is a better venue for drawing the attention of the product team…

    One of our limitations today is that SPD workflows always run in the context of the initiator, so although the workflow engine itself has a system account we lock it down based on the perms of who triggered the workflow to start. So yes, you’ll get errors if people don’t have perms to any list that "Attendee registration" touches along the way, because there is an action that updates the seating count in Courses.

    So once you open the floodgates, how do you stop Joe Schmoe from adding his own courses? My suggestion would be to add a whitelist step to the existing Courses workflow – basically, before you do anything else, check Created By == GoodUser1, GoodUser2… and if the check fails, delete the current list item. You may be able to do something similar with Modified By to prevent drive-by edits, but realistically you should just turn on versioning to leave a "paper trail" on the list.

    Paolo: sorry you’re still having trouble. Our support folks will probably be more helpful than me at this point – the blog is not the best place for in-depth technical support. It sounds the problem you’re hitting is rather specific.



  11. says:

    Is it possible to have an action copy an item from one list to another located in a sub-site? If this is not a native capability, has anyone seen any extensions that might allow it?

  12. troyson73 says:

    now how the hell do u subtract days from time in the workflow, i see that there is add time to days but no subtract or is there a workaround. I require to workout a start date and an end date from a final date.

    thsi is what im trying to achive and was hoping i could do it with the workflow designer.

    Im a newbie to sharepoint and am in desperate need of help! My project is to dev an page that uses a final date date picker in order to assign a start date and an end date to a group of users. When the final date is picked; each user in the list must have their start and end date changes or updaated based on the final date and the amount of days they each have allocated to do the task.

    So if X’s allocated days = 5 and the final date picked = 2007/04/28, his start date must be assigned as the 2007/04/23 and end date will = the final date.

    The next step is to assign the next user’s start and end date based on the first users start date. ie: the second user has been allocated 7 days to complete task therefore would need to take x’s start date – 7 days: so must change or update the second users start date to the 2007/04/16 and then add or update the second users end date to 2007/04/16 + 7 = 2007/04/23

    The start and end date apply only to the users, the final date is global. The total of days allocated for all users should = 12 days at this point between the final date and the last start date

    pleeezzz help

  13. spdblog says:

    Rcrouch: currently, SPD workflows can only operate within the context of your current site. To do something cross-web you’ll need to develop your workflow in Visual Studio.

    Troyson: the Add Time to Date action accepts negative values (like step 1.1 of "Instructor reminder" in the walkthrough). If you need additional assistance, try soliciting the SharePoint newsgroups on for advice specific to your scenario. The Design and Customization forum would be a good place to start.



  14. paolonu says:

    Solved by updating (or setting) the [fx :: Current Item, Start Time] to itself after setting [fx :: Current Item, End Time] to the variable.

    This has no explanation to me, but it worked, in some ways… 😉

    Thanks again

    Paolo Nugnes

  15. CQuick says:

    When is the next installment? I’m really interested in how you changed the associated forms for each list since they all render XSLT transform errors and it is difficult to understand how these things are being handled.

  16. spdblog says:

    Thanks for the interest CQuick, I’m looking to get out the next installment by this week. It’s probably the most in-depth article of the series, so it’s been taking a while to write…



  17. Ben McMann says:

    Great work with the articles Sean.  It really helps us see the power of the applications and how to design our own for clients and internal use.

    One thought, I know writing doc can take a long time, have you thought about producing screencasts instead of doc?  This might help in speeding up the time it takes to produce how-to’s on application template designs.

    Great work,

    Ben McMann

  18. Scott says:

    Great Examples. I used this example to create a Workflow with a Reminder and an OverDue on a Project List. The only question I have is when the Workflow is paused waiting for a reminder date what if I want to stop the workflow if someone changes the status of an Item to "Completed" it doesn’t seem to be able to unPause to stop the workflow.

  19. bbarthel says:

    Great example to get started!  I took your examples and be experimenting creating a shopping cart like application.  The problem I’m having is getting input in a dataview.  I understand how to put a label in a table and see it in workflow but, how a textbox?  When I put a textbox in the table, I do not see it as a form variable to assign in workflow.  Any thoughts?



  20. hoailo says:

    Hi all,

    I want to build a new web part but I don’t know how SP store this information in database. I know that there’re some tables like AllLists, AllWebParts…store information ‘b lists, webparts… But I don’t know where SP stored all items in these lists?

    Please help me!

  21. pangolao says:

    Its possible insert in the email a link to new item created in lists? how? (sorry for my english)

  22. Goncalo Feijao says:

    Hi all,

    I created a subsite using WSS 3.0 template “Employee Training Scheduling and Materials”.

    I gave some users Read permission and others Contribute permission.

    Users with Read permission cannot do their registration for any course. (Registration Fails)

    Users with Contribute permission can register fine, however they have more permissions that they should. For example, with Contribute permission they can add, edit or delete items, which they shouldn’t.

    I found that this is a permission related issue.

    My workaround was to give specific permissions for the courses list. I.e.:

    -I created a new permission level from a copy of the Contribute permission level. I uncheck the “Add Items” and “Delete Items” permission and leaved only the “Edit Items” permission.

    -Then on Courses permissions, I created a Group (named Training Users) and gave this group the permission level created.

    With this I was able to give users the ability to register to courses and at the same time deny them the ability to add new items and to delete existing items.

    Unfortunately this doesn’t answer to all my requirements because users can still edit items, i.e., they can change the name, time and available seats of any course.

    Note: The “edit items” permission in the courses list is needed because each time a user registers for a course the “Attendee registration” workflow starts using the credentials of the user that initiated the workflow, and if this user only has Read Permission the workflow fails. The user needs to have the ability to “edit items” in the courses list because one of the steps of the “Attendee registration” workflow is the “enforce seating policy” which updates an item in the courses list.

    In the registration list I gave the users the Contribute permission level because they need to add and delete items depending if they are registering or unregistering from a course.

    Resuming, I want users to be able to register to courses but at the same time I don’t want them to add, delete or edit items in the courses list.

    Can I run the workflows with elevated privileges independently of the users permission?

    I don’t know if I made myself clear. Any question please feel free to contact-me.

    Thanks in advance.

  23. NehaSinha says:

    hey …i used a workflow in my system..

    but everytime the condition is true…it triggers the action more than once(around 10 times..)

    please share your views on this..

  24. CQuick says:

    Part 3? I know you’re busy, but it would be great to see Part 3!

  25. YokoGaijin says:

    Need some help.  I’m really interested in learning this but SPD gives me this ugly error:

    Errors were found when compiling the workflow.The workflow files were saved but cannot be run.

    Unexpected error on server associating the workflow

    Everything out there on this error points to VS.NET developed workflows, not SPD.  Help!?!

  26. YokoGaijin says:

    Well, I had the same error as David and my issue with SPD 2007.  Going through the logs (%systemdrive%Program FilesCommon FilesMicrosoft Sharedweb server extensions12LOGS) I found that the "temp" directory of the default NetworkService wasn’t letting the SHAREPOINTsystem user to compile the workflow.  Once I modified the directory permissions to let SHAREPOINTsystem compile in that location, the errors David and I see went away and SPD would also compile and associate a custom workflow.

  27. spdblog says:

    Wow folks… thanks for all the comments! I’m sorry I haven’t been around much as of late, we’ve all been busy planning out all the awesome new SharePoint Designer features you’ll see in the next wave of Office. But now that I have some time to catch my breath…

    Ben, CQuick: Part 3 is long overdue, I agree. Thanks for being patient – I hope you guys will find it useful in completing the picture here…

    Scott: after the pause action, you can create a new step with a condition to check status before doing anything else. It’s not a synchronous check though, for that I would suggest looking into using modification forms in the WinWF.

    BBarthell: are you using custom form actions? You should be able to access any text box from the data form by pointing the lookup dialog (fx) to the "Form Fields" data source…

    Hoalio: writing your own web part isn’t in the scope of this post, but you may want to try the SharePoint SDK for information on how backend data storage is handled.

    Pangolao: there isn’t an easy way to do this today, but you can certainly handcode the path portion of the URL (http://server/site/List/DispForm.aspx?ID=) and then apply a lookup to the Current Item’s ID, similarly to the examples in the post.

    Goncalo: SPD’s workflows always impersonate the person who initiated them, so no there isn’t a way to elevate without developing your own non-declarative workflow.

    NehaShina: did you check the start trigger for the workflow? It’s possible to get into this situation if you set the workflow to start every time an item is changed, and the workflow itself does the change (thereby triggering an action several times).

    YokoGaijin: good catch and thanks for sharing.



  28. bbarthel says:

    Yes, I am using custom form actions … my label shows up in the form fields (like your example) but, how can I put a text box in that is not related to the list?  For example, I want to show a list of products to order and ask for a Qty for each product.  The "Add to basket" is a custom form action (button).

    Products                     QTY

    Product A                _______    "Add to basket"

    Product B                _______    "Add to basket"



  29. YokoGaijin says:

    Sean, one request.  Can you tell me if the following even possible within the context of SPD (I know I can do it in VS… just didn’t want to have to)?

    I added another list populated by an InfoPath form.  The "forced attendance" list allows HR and the supervisors in certain departments designate training as ‘mandatory’, ‘highly suggested’, and ‘suggested’.  The difference being that the first is required, the other two are courses that directly apply to goals & objectives or identified on the job training needs.  The "forced attendance" list uses lookups from the "courses" list as defined in this example.

    My conundrum is how I can insert registrations using a workflow in SPD.  One of the fields in the "forced attendance" list is an attendees field populated with people picker and allows multiple entries.  Is there a way I can do a "do while" or "for each" using SPD without creating custom workflow features or resorting to VS?

  30. zullu says:

    Hi Sean,

    I surely adore the piece of work you are putting up here.

    This has definitely served me as the starting point and now to run forward with the SPD flag.

    3 Cheers to you!!

    Keeping my fingers crossed till you get us the next installment :-).

    Also, a small query…

    I am using the "Do Calculation" Action in my workflow in SPD.

    I am trying to use something like this:

    Calculate FileNumber:OldFileNo plus 1 (Output to Variable:NewNo)

    then use this variable "NewNo" to Update a column in myList which initially has a value "1".

    When this workflow runs, I see that the status is completed and also that the

    required list column is updated. But only problem is the updated value is incorrect.

    Instead of incrementing the "1" to "2", I find a value "11" in that column.

    This is wierd !!

    The calculation can’t be a concatenation. I need it to add 1 to the older value.

    Am I missing on somethig.

    Thanks for any kinda help.


  31. zullu says:

    Hey I figured that out !!

    Was really silly though….. 🙂 Sorry guys if anybody out there got disturbed due to this.

    It was the variable data type which should be "Number" instead of "String".

    Thanx Sean, I again appreciate your works.


  32. nicks says:

    Hi Sean,

       Thanks very much for your example.  I am trying to send a reminder before a Task Due Eate.  But I have a problem with a "Pause Until .. " activity.  After the pause I want to check a condition by adding a new Workflow step.  But after the pause is completed, the workflow is marked as Completed and never executed the next Workflow step.  I think there is a bug in the WF.  I also updated the patch according to the KB932394.   But it still doesn’t work.

    Thanks in advance for your help.


  33. Sergio says:

    Hi Sean,

    Is there to assign courses to specific person rather that ask the person to sign for a course.

    We have training courses for new employees, so what I am wondering is if there is a way to allow HR people to assign those courses direct to the new employees.



  34. Kunji says:

    Any news on the next installment?

    Both training site templates tutorials have been extremely useful. Thank you for putting them together as it reaaly helps in the understanding of how sharepoint works.

  35. Manuel84 says:

    Í have a leasing-list with 100 items. Every item has a date in a colum named "end-date". I need a workflow with checks every week all these 100 items and if the end-date is nearer then 1 month, the workflow should send an email to an defined e-mail-adress. I don’t know how to handle this problem… I only can start the workflow for several items, but ot for the hole list. Can somebody help me?

  36. CQuick says:

    Okay… I’m now officially frustrated because this article is taking so long to publish. I need some good examples in SPD, and this was a good start. Now that we’re looking to the actual functinality — I find myself in the middle of a desert with no water… please please please!

  37. Mohd Fauzi says:

    I’m unable to get a recurrance event at the new form to appear. After re-enabling the contents managment types , it still did not appear.

    Thanks In Advance for the assistance.


  38. wattsonlosen says:

    Hi Sean,

    i just read your examples. great idea do show this piece of work in detail.

    do you have any ideas when you can finish part 3 ?

    i’m really looking foward  to it !!!

    greets marco

  39. Glueck says:

    Really when can we expect part 3?  This walk through has been very helpful up to this point.  Thanks for the help in getting started with Designer because before I was just basically using it as an editing tool.   Now I can see where I can build an actual application.

  40. Thanh-Nu says:

    Hi Sean,

    Thank you for writing this Training Site Template part I and II, I found the articles very helpful.  I am desperateley looking for the same material concerning the Server Admin Application Template HelpDesk.wsp in order to understand how this helpdesk template is built.  I need to make some customization on the Helpdesk template, in particular, I need to modify the Service Request Form to add new fields.  I cannot find any guidance in a step-by-step manner as your "Training Site Template part I and II".  Could you please give me some hints to customize the Helpdesk.wsp and ProjectTracking.wsp?

    Thank you in advance.

  41. Doug says:

    Thanks for an excellent tutorial.  Now all we need is part 3 to glue it all together.  We know you are busy, but you should always finish what you start, right???  😉

  42. jfeagans says:

    Thanks for part I and II Sean. We are looking forward to part III. We find however that we are having issues with the workflow correctly managing the seat enforcement. We have tried this several times but the workflow never seems to increment/decrement even though the students are registered. Any ideas?

  43. bigpix2000 says:

    Trying to do this … either in the string or variable set …

    Set a variable (e.g. YEAR([%customlist:DATEFIELD%]) to get a string of the year

    so I can later use it in a Dynamic string …

    Why can’t I do this ???

  44. dink says:

    Odd problem here…

    Regardless of how I try this…whether following your steps to create everything, or using the default template that includes all these workflows…I run into the following problem:

    A user registers for a course (with no problems) and the workflow subtracts 1 from the total seats available.

    If the user then unregisters, the workflow seems to fire off and actually remove them from the registrants listing, but the total number of available seats does not increment back up.

    For example, I have a course with 5 seats available.  User1 registers for the course and the count decrements by one (now shows 4 seats available).  User2 registers for the course and the same process occurs (as it should) which decrements the count again by one (count now shows 3 seats available).  If User1 wants to unregister, they follow through the steps to confirm they want to unregister and it removes them…but the count will stay at 3 for the available seats, even though now only one person is showing as registered.

    No mattter what I try, each time the count will never go back up.  The only way I’ve been able to get things to work is to go back in and manually add one more seat in the edit item screen…which in effect make the count of available seats accurate again, but in reality is actually off by one (I’d have to do this for each user that unregisters).

    Has anyone ran into this…and if so, how did you get around it?  Seems like a pretty simple thing to me…register and the count goes down by one, unregister and it goes up by one.

    I’ve also monitored the workflows and none of them appear to be hanging or throwing any errors.

    Any ideas?

  45. rob says:

    I have aquestion with this part of the workFlow that i hope youcan help me with.

    you did a new work flow with the information =

    Start with a new workflow called "Attendee registration," attached to Registrations

    in your second workflow step

    2)"Enforce seating policy"

      1. Conditions > Compare any data source (x2)

            1. If [fx :: Courses*, Total Seats] equals 0

    My question is when i use the  "Compare any data source" what information should i put into the fields.

    Example , say i attach my workflow to workDocuments. in the first step i assign a form to someone to review the document (approve/reject) ( i know sharepoint has its own Approve/reject for this examples lets stay with the form)

    in step 2 i want it to  be

    condition  > if Approve/reject equals  reject

    heres where my question comes in. to do this i cannot use "Compare workDocuments field " i have to use "Compare any data source". so i use this and it Brings up "Define Workflow Lookup" so i  select Source>Tasks  Field> Approve/Reject   then under Find the List Item  i select Field>Approve/Reject then there is a "Value" drop down box. i can leave blank or put in Approve , Pending or Reject. (Should i fill in a value and what does this do?) pressing the OK button bring up the Unique value warning press yes and next to condition it shows "If Taks:Aprrove/Reject equals value". Now i fill in Reject for Value and i get "If Tasks:Aprrove/Reject equals Reject" which seems like what i wanted originally, but it never seems to work out and i think it is from the question of the "Value" drop down box in the Define workflow Lookup.

    So could you help me with my example and could you give some incite as to what happens if i fill in different Values in the Value box of the Define Workflow Lookup.

    Desperate in need of help

  46. MG says:

    I used the original template to design the course registration website. And I am having problems while deleting "My Registrations". On the home page, where "Courses I am attending" is displayed, when I click "Remove", it doesn’t delete that particular registration. Instead it deletes the very first registration in the list. What I also observe is that the "Remove" link has the same parameter value (for the parameter ID) for all the registrations.

    Can someone please confirm if this is the case with them? And how to resolve this? I have recreated this site several times and I see the same issue all over.



  47. Yannis says:

    MG: Add one line above the remove link in the XSL code, then change

    the ‘remove’ link parameter as follows:

    Add this line above the link:

    <xsl:variable name="CourseID" select="@ID"/>

    Change the parameter of the remove link (after the ID=) to read:

    {../../../Registrations/Rows//Row[@Course_x0020_ID=$CourseID and

    contains(@Author, $UserID)]/@ID}

  48. Yannis says:


    I’ve changed the locale in the Regional settings of the site from English (US) to Dutch (Belgium). This causes an error when editing a course without changing the Start & End Time. Does anyone know how I can solve this?

    Thanks in advance.

  49. MG says:

    Yannis: SUPER! That worked out just perfectly. Many thanks for your solution.


  50. dink says:

    As a follow up to my earlier comment on the workflow for the "Attendee Unregistration" workflow, I’ve posted a walkthrough on how to adjust the workflow to increment the "Available Seats" variable after a user unregisters from a course.

    Hopefully this will help someone else if they have the same issue.

    And Sean…you may want to look at modifying this post to include what I posted because you forgot to include this logic in your walkthrough.

    – Dink

  51. Oscar says:

    Using Assign Form To Group Activity in SPD

    I have the workflow working where it creates a task for each user.  The problem is, how do I check what EACH user responded to and either approve or reject the workflow item?

    Thanks and fantastic job!

  52. Craig DeSantis says:

    I have been working with this template and am ready for nearly for final user testing.  My last issue is identical to one posted earlier by Goncalo Feijao: "I want users to be able to register to courses but at the same time I don’t want them to add, delete or edit items in the courses list"


    You posted a response to this: "SPD’s workflows always impersonate the person who initiated them, so no there isn’t a way to elevate without developing your own non-declarative workflow."

    I saw no additional follow-up on this and am not sure how to interpret.  Can you elaborate a bit on this?



  53. This is an awsome post!.    However, there has not been a response yet to Goncalo’s post regarding setting permissions on the workflow so that a user does not need "Edit" permissions on the list to start the workflow.

    Ironically, I build a similar class registation, tracking system for our organization and discovered many of the same permission issues with running workflows that were identified here.     I have NOT found a work around for this either.  The difference here is that my workflow does NOT update the number of available seats.   Initially I had this feature but removed it since I thought it was the culprit but found that it does not matter.. to start the workflow on a list you need the Edit permission.

    To get around this… I changed the advanced settings on the list so that the item-level permissions are set to Edit Access = None.   This ensures that ONLY the folks who have "Manager List" privileges can edit the list items.   I’d rather give that permission to the 2-3 folks who add courses to the course calendar than the Edit permission to my 4000 other users.

    Regarding impersonation that Sean was refering to, this is true and is fundamentally how workflows work.  The only way to get around this is to program a custom workflow and use some Single-Sign On methods to imporsonate someone with the required permissions if that is required (eg.  Register for a class and log a custom audit row to a list that the user does not have access to add/view/or edit)

    A few lessons learned from my expeirence:

    1) I created a list that used to track the classes users registerd for on-line called My Classes.  Items in this List are created by the workflow and let our registrat keep track of who’s registered for classes, approve their registrations and communicate to users if a class is cancelled.   There are even future plans to track attendance using this list.   The main reason I did this was because not all our users have access to EMAIL, some still use our Hospital Information System to send messages to each other.   So it was pointless notifying them by email to confirm they’ve been accepted into a class.   This way it make communication MUCH easier and will save countless hours of our registrar trying to track down folks if a class is cancelled or for some other reason.  

    2) I love the available seats feature and will likely bring this back into my list as I originally intended.  

    PS. Love the reminder time..  maybe we’ll incopoate something like this into our list.  This is not possible with the alert features of SharePoint.  

    My only concern is that th OSTIMER service seems to have a memory leak making me weary of getting too deep into Workflows until that’s resolved…  There is a hotfix out there from microsoft for that but we’ve not applied it yet.  A workaound is to restart the service every few days.



  54. zullu says:

    Anybody out there !!

    My "Copy List Item" action in the workflow has stopped working for no reasons I can think of.

    WIERD !!!!

    It was initially working but has started throwing an error "Error while copying…." kind of.

    Has anyone faced this problem.

    Need quick help!!!


  55. Kiran Mantrala says:

    Hello Sean,

      This is a very intesresting blog that i have read. I really appreciate your work and the patience that you had in explaining all the steps in creating the necessary lists and workflows.

      but, out there right now, I am waiting for your 3rd blog. I would be thankful if you could post the 3rd most wanted blog which as you said will explain the important steps to create a site template on our own.

      Could you please post the blog for all of us ?

    zillion thanks,

    -Kiran M

  56. Rocky says:

    All there

    How can I customize this template so that it displays a message to user if he tries to create a course with duration longer than 2 hours and does not add that item.

    I created a workflow,  it deletes the item if duration > 7200, but the user has no clue of what has happened. Can I make it interactive and ask the user to change the timings ?

    … Rocky

  57. Kiran M says:


      You can do customization to your work by doing some Event Handling code work. There is lot of good stuff explained on how to handle events at: Check out the article for WSS -> Creating and Using Event Handlers in Windows SharePoint Services 3.0.

      Hope that helps.


    -Kiran M

  58. Rocky says:


    Thanks for the response. but i dont want to write managed code. I handled that with javascript code and that worked great.


    I have another problem. How can i determine if the user belongs to a particular sharepoint group, say MyCutsomGroup. Again, i want to do it without .Net code. Can this be done by editing some XSL/XML or writing Javascript ?


  59. Huda Albar says:

    Hi all,

    I need ur help , i need to create workflow start automatically without add, edit or delete any item to my list

    bcz i need it work daily @8:00 am to send e-mail to end users.

    is it possible , plz tell me how i can do that????/


  60. frist44 says:

    When the course is scheduled, the workflow is paused and waits for the reminder time. I’m doing a similar thing, but what happens if the date of the course is changed. The workflow doesn’t updated itself and the old one is still in progress, which would send the reminder at the wrong time.


  61. Mark Arnold says:

    I have some users that can’t unregister from any of the courses they registered too during testing when, as it turns out, I had restricted perms too much causing the workflows to fail.  That’s corrected now, and they can register/unregister new courses as desired, but how can I delete all the old registrations and failed workflows in the registration list?



  62. Mark Arnold says:

    Regarding security on the Courses list, an alternative that will help is to remove the standard control bar from the list form in courses/dispform.aspx.  Oddly though, I tried this and it has no affect.  I’m guessing the properties are being assigned somewhere else, particularly since the list form web part appears greyed out in dispform.aspx.

    Any thoughts on how to disable that control bar?  The admins could create a copy of the page with control bar enabled for their use, but this keeps the users from getting click-happy.


  63. Simo says:

    Great !


    But a question: My workflow remains in "Pausing" state !!


  64. Dan says:

    Thanks!! This works perfectly.

    Had the same issue as Yannis opn the remove button on the MY Registrations.  Your fix did the trick.

    Nice job on the details!

  65. TheMaxx says:

    How to set Workflow variable  (or field value) to some calculated value?

    I want:

    NewBudget (int) = NewBudget + 1

    So i need to do some math, not just reference to other Fields


    Field3 = Field1 + Field2

    Thank you.

  66. Chanda says:

    I realize it’s been a year since this post, but are there any plans for Part 3?  I’m currently working with this template and need to slightly modify the dispform.aspx page for the Courses list.  Unfortunately, SharePoint Designer cannot render the XSLT in the Data View that is being used to display the course information, and I don’t have XSLT experience, so I’m somewhat stuck.  It looks like what I need to know would have been included in Part 3 so I’m hoping that someone can help me there.  Thanks!

  67. tremor97 says:

    There is a major problem with the Employee Training Scheduling and Materials template.  The template is designed to use several workflows, all very needed and impressive.  The biggest problem I see with it that has not been answered by anyone, including Microsoft is the fact that user need Edit permissions on the “Courses” in order to successfully run the workflow for incremental Seating Policy adjustments.  This is a great feature that automatically adjusts available seating when a user registers or un-registers for a course.  Without this feature, I think the template is nowhere near as useful as it should be.  The problems come in to play with the fact that once you give the users the “Edit” permission, they can also go in and edit every single course scheduled, including those very same Available Seats, along with Course Title, Comments, Location, etc.  Hopefully most users are adult enough not to make these changes but some are invariably not that mature and / or some will mistakenly edit a course, believing they are registering or simply editing their own version of it.  This is a huge bug in my opinion, particularly when Microsoft preaches so much about security and the importance of it.  There should be a way to either run a workflow as another user and / or simply hide the Edit button on the form for users that should not have this permission.  I have literally seen hundreds and hundreds of posts on this and nobody has the answer, including Microsoft posts, which is surprising to me.  Any help would be extremely important and could allow most companies to us this potentially valuable tool fully.

  68. Jimmy says:

    The post here has been very helpful.

    In the Emploeye Training  Scheduling templates installed from Microsoft, I see this message: "In progress" for all registrations, what could be responsible. Can anyone help.

  69. Chandan says:

    hi everyone,

    I would also Like to Know the Logic behind the MyRegistration button in CourseList.It passess the URL with parameters to the registrration page but i am not able to do so.Can any body give me steps to rectify this problem..or make me walkthrough the courseregistration part.this would be very helpful in creating other similiar applications as well.

    Thanks in Advance

  70. MelissaM says:

    Chandan –

    This is exactly why we need part 3!!! I could use this type of functionality all over SharePoint at my company and I am sure that many others could as well. It’s great that I have the template to download, but it doesn’t really help me because I do not understand the setup.

  71. Pete says:

    This tutorial was really great, it helped a lot with getting my mind around workflows. But sadly it doesn’t look like the third installment is going to come. Does anyone know of an equivalent tutorial that deals with forms and views.

    Specifically, I’m looking to automatically hide certain fields based on prior answers. I’d also like to change the default based on what was previously answered. In essence i need to dynamically add and remove content based on conditions in the other fields.

  72. Jimmy says:

    Can anyone tell me which sets of permission work well on The Training template?

  73. LYD says:


    I realized that the calendar displayed in course list is displaying the previous day! Today is 9/06/2008 and the day in "Today is…" displays Sunday, June 8, 2008.

    Others calendars in the site are working well. Has anyone any idea what is wrong?

    I have to add the functionality to get the manager’s approval for a course registration. How can I add it?

    Thanks in advance.

  74. Prashanth says:


    I want to develop a leave sanction loop in Shrepoint. Could you please anybody help me?

    Ours is a software company, here in our staff if anybody wants to apply a Leave, they should upload it to sharepoint and then first it should approve by the PM and then HR head and last CEO (If necessary). After all this he should receive mail that "your leave has been granted" like this. Also there should be comments from all the 3 (?) peoples.



  75. Anand says:

    when i clicked on share point  templates (file->new->wesite->sharepoint templates) in share point designer 2007 the following message get displayed " microsoft windows share point services required at the website location" i installed wss 3 with sp1. please help me.

  76. Hi everyone, This is Sean (I know, finally!), blogging to you with the next part of the training site

  77. spdblog says:

    All, I just wanted to drop a quick line to say thanks for your patience and contributions to this thread, along with my apologies for leaving you in the dark these past months. I’ll be modding some of the commentary re: part 3 now that it’s out there, and we’ll continue the dialog on this thread shortly.


  78. Andy says:

    I’ve just dropped onto this after trawling the net for assistance in setting up reminders from a Sharepoint calendar. This works fantastically well but my only question is, how can you accommodate recurring events using this system?

  79. Marty says:

    If the event was deleted how would you clear the variables?  After some testing I’m finding that the reminder still fires even though the event was deleted prior to the start time.

  80. Took me long enough to get this post up, but it&#39;s finally done (hopefully – please let me know if

  81. Jerry says:


    If you are interested in instructor-led SharePoint training, consider Aivea –

  82. Sara says:


    I have been trying to find an answer for this for week now But No luck at all. I recreated everything again and now I am stuck again. Basically I have to give Edit permissions to the user so the Available seats increment/decrement. If I give user to the course list the Read only permission – When they register or unregister the available seats does not change. Did anyone find out a solution for this? Why is this such a problem with security?

    I have searched and searched… and the suggestions I have found didnt seem to be working for me. Because user would like to have the toolbar on the top which shows Export Event link so they can export the event to their outlook calendar and not see edit/add/delete links.

    Please help! I really would appreciate it!

  83. nlcabrera says:


    I’m trying to accomplish something, but need a little help in understanding.  I have a task update list that every friday needs to be "reset" to blank, meaning the items in the list are copied to another list and then deleted from the original list.  I’m still not understanding how to trigger the workflow step based on a particular day, vs. relative to a column date.  Can you help?

    Thank you,

    – Nes

  84. Saurabh Kumar Singh says:


    I am creating a reminder wrokflow using SharePoint Designer, and when i  using "Pause Until Date" activity. It doesn’t resume and Workflow status does not change from "In Progress".

    (i.e it displays "Pausing for 0 minutes" under Workflow History but it doesn’t take specified action).

    I have created it many times but found same problem.

    I have done some googling for that in last some days, and from there I had got a hot fix  KB 932394 and installed it but still I am in same trouble with Pause Until Date Activity.

    I have also changed job-workflow time duration using stsadm command from 5 minutes to 1 minute as below:

    stsadm -o setproperty -propertyname "job-workflow" -propertyvalue "every 1 minutes between 0 and 59" -url http://localhost

    but found same problem.

    What should I do for this?

    Please suggest me why "Pause Until Date" doesn’t resume and Workflow status does not change from "In Progress" in my workflow.

    If anyone have any solution regarding this then please reply me at

    Thank you,

    Saurabh Kumar Singh

  85. Jerry says:

    I have a task, and the requirement is to send a notification email to the requestor after 6 months of request created.

    how this work using workflow?

  86. Chris Muller says:

    I’m having the same error that YokoGaijin had,

    Errors were found when compiling the workflow.The workflow files were saved but cannot be run.

    Unexpected error on server associating the workflow

    Can someone tell me where the "temp" dir is that the NetworkService uses so that I can check the permisions?  I’ve been looking all day for a solution to this problem with no success.



  87. Jimmy says:

    frist44 said:

    When the course is scheduled, the workflow is paused and waits for the reminder time. I’m doing a similar thing, but what happens if the date of the course is changed. The workflow doesn’t updated itself and the old one is still in progress, which would send the reminder at the wrong time.

    I am interested too. Any solutions.

  88. Pat says:

    Hi, I did all the steps in the blog, and fixed the seat increase/decrease. I am getting a problem with the Registrations list. I seems it just deletes the first row in the list regardless of whos logged in.

    DELETE item in Registartions (current item) might be the problem?

  89. Simon says:


    I am getting the same thing – if the user deletes from their ‘my courses’ page then the first item in the registration list gets deleted. If they open the training session and click my registration, then it deletes right – or it would if the permissions worked properly.

    I reckon its that line too

    Currently I am just deleting them manually in Access

  90. dink says:


    I have a series of articles that cover what is missing in the template (they compliment this series and fill in the missing pieces).

    This one specifically:

    Covers how to change the XSL for the "my courses" webpart to remove the user from the correct course.

    Hope it helps,

    – Dink

  91. Eric R. says:

    Frist44 and Jimmy,

    I’m also interested in the question about course dates changing and related workflow issues.  Any information out there?


  92. Deepak says:

    Is there a way to integrate this with MySites?  The idea is that after a learner completes X number of courses and tests, that he would be "certified".  Or is there a better way to track certification?



  93. Joe says:

    I find that this does not work:

    "Unregister from course"

    Conditions > Compare Registrations field – If Title equals "DELETE"

    Actions > Delete Item – Delete item in Registrations (Current Item)

    Actions > Build Dynamic String – Store … in Variable: Log Message

    Actions > Stop Workflow – Stop the workflow and log Variable: Log Message

    Appears to be a need to minus 1 from the available seats

  94. Linzt says:

    When attempting to complete step 2 and 3 of the instructor reminder workflow:

    (Second step: name it "Send confirmation"

    No conditions

    Actions > Send an Email – Email […]

    To: Workflow Lookup… :: Current Item, Instructor)

    "Instructor" is not an option from the drop down once I select "Current Item".  (However, Created by and Modified by ARE options). Not sure how to fix this– I’ve deleted and recreated the column a couple of times….

  95. Tim says:

    I need to send out a reminder 5 days in advance, so I set my reminder time variable to start time – 5 days.

    I know this is working because I had the system email me the variable values and I received the email with the values.

    When I do the compare statement create date < reminder time variable, pause until reminder time variable then send email, the date and time comes and goes and the email is never sent.

    What would cause this to happen?  Something is not triggering.

  96. Franc says:

    I would like to ask you whether is possible to send an outlook invitation, not e-mail with text?

  97. spdblog says:

    Unfortunately no, not with the pre-installed actions. You'll need to write some custom code to achieve that.

  98. Franc says:

    Could you write such code, I need this to our internall WSS site… I would be grateful!

  99. Tania says:

    How do I create a unregistration confirmation email?

Skip to main content