Search This Blog

Showing posts with label SharePoint 2007. Show all posts
Showing posts with label SharePoint 2007. Show all posts

Monday, August 1, 2011

MOSS 2007 to SharePoint 2010 Migration - Lessons Learned

I recently completed a migration from MOSS 2007 to Sharepoint 2010 and I encountered many application migration issues that I had to find a way to resolve.  As a result I learned a lot of lessons that I wanted to share with others who may be facing the same challenge - I hope this may save you some time and effort.

1. Search:

a. Issue: Search center web parts fail to load; search bar is missing

b. Fix: Reconfigure and redeploy search master page

c. Reference:




a. Issue: Advanced Search page broken

b. Fix: Reconfigure and redeploy search master page and results page

c. Reference:




a. Issue: Cannot search scopes

b. Fix: Ensure that the default search results page is the search center results.aspx page. Apply custom search master page and configure results.aspx with web parts. Remove scopes that do not exist by modifying the Scopes list on the Search Center site.

a. Reference:




a. Issue: The initial page opens in the test environment, but the subsequent pages open in the production environment

b. Fix: Change results page absolute URL to relative path URL



a. Issue: Results by Relevance option does not display and Time to complete does not display

b. Fix: Reconfigure results page in SPS 2010 (Results Relevance are handled differently in SPS 2010 - see below article in Reference).



a. Issue: Receive error/blank page when trying to access Search Center

b. Fix: Reconfigure the site to use the new default and custom master page



a. Issue: Pages are broken when trying to search in ‘All Sites’ and ‘People’

b. Fix: Change searched settings to show and default to contextual scope so people/all sites could be searched. Ensure that the default search results page is the search center results.aspx page. Apply custom search master page and configure results.aspx with web parts. Remove scopes that do not exist by modifying the Scopes list on the Search Center site.

c. Reference:




2. Ribbon:

a. Issue: Ribbon is not displayed

b. Fix: Check out page, edit it, check in page

c. Reference: N/A


a. Issue: Navigate Up in the Ribbon does not display breadcrumb trail; ‘Browse’ and ‘Page’ tabs are missing

b. Fix: Edit the page-check in-refresh browser and remove this line from SharePoint Designer:



3. Content Types:

a. Issue: Content Types do not work for uploading new items to a library

b. Fix: Apply a new custom form in SPS 2010



4. Trusted File Locations:

a. Issue: Excel documents won’t open

b. Fix: Recreate/create a new Trusted File location



5. Database connections:

a. Issue: Cannot launch reports that tie to a database connection

b. Fix: Update WFE Web.config to allow code blocks



6. Navigation:

a. Issue: The site did not correctly inherit its Quick Launch Navigation structure; the site did not correctly inherit its Global Navigation

b. Fix: Configure new default and custom master pages

c. Reference:




a. Issue: Second level navigation from the dropdown in Global Navigation is missing

b. Fix: Reconfigure the master page



a. Issue: Duplicate tabs in the Global Navigation

b. Fix: Delete the extra link through the Navigation configuration; deploy publishing feature



a. Issue: The visual upgrade caused all links in the Quick Launch to go away

b. Fix: The Quick Launch is based on a custom master page, master page must be redone for SPS 2010 post-migration. Design a new custom master page for this site. Reconfigure this site to use audiences to control visibility of the navigation links.

c. Reference:




7. Views/Custom Views:

a. Issue: Error when accessing views from the Library Settings Panel

b. Fix: Recreate the Content Type and Library



a. Issue: Calculated columns using Content Types as metadata are not working

b. Fix: Reconfigure the calculated columns to not use Content Types as metadata


a. Issue: Trying to change to datasheet view produces this error: ‘The query cannot be completed because the number of lookup columns it contains exceeds the lookup column threshold enforced by the administrator.’

b. Fix: In CA set the list view lookup threshold to 10,000. After some research, it appears that the threshold for the List View Lookup will need to be modified.

Your SharePoint administrator needs to change the Resource Throttling settings under Central Administration > Application Management > Manage Web Application > Your Web Application > General Settings > Resource Throttling. Set the List View Lookup Threshold value to a number larger than the number of lookup and workflow status column in the library and view

c. References:






8. Web Parts:

a. Issue: Clicking on an item in a web part does not lead to the item

b. Fix: Recreate web part



a. Issue: Web Parts do not display

b. Fix: Recreate the web parts



a. Issue: Custom Filter Web Part errors out and page hangs

b. Fix: Modify the Ajax Options to Enable Asynchronous Update



a. Description: “This list does not exist” error, cannot toggle between months in Calendar

b. Fix: Recreate the web part



9. Hiding Content

a. Issue: ‘All Site Content’ and the ‘Recycle Bin’ should be hidden

b. Fix: Reconfigure the site to use custom master page; this will have different security to hide ‘All Site Content’ and the ‘Recycle Bin’



10. Site Usage Reports:

a. Issue: Site Usage report will not display

b. Fix: Recreate link to point to OOTB SharePoint Web Analytics



11. Appearance:

a. Issue: Site does not have the 2010 master page applied

b. Fix: Deploy custom master page


a. Issue: The blue bar at the top doesn’t extend the entire way

b. Fix: Reconfigure the site to use the new and default custom Master Page

c. Reference:




a. Issue: Cannot open meeting dates links-various errors

b. Fix: This is a master page issue



a. Issue: Page opens in 2007

b. Fix: Update Navigation to use absolute URLs

c. Reference:



a. Issue: Logo (that is a link) in the top bar that has the title of the page points to the wrong page

b. Fix: Redeploy master pages



a. Issue: The Visual Upgrade was not applied

b. Fix: The SPS 2010 default and custom master pages will need to be applied

c. Reference:




Thanks to Rachel for all her help with this Blog!

I hope that helps!

Tom Molskow

Tuesday, July 26, 2011

SharePoint Designer 2007 – Business Days Task Reminder Workflow

1. In this article we will discuss how to use SharePoint Designer (SPD) 2007 to create a Business Days Task Reminder Workflow. Here is our scenario:

   a. A business leader assigns a task or tasks to an employee with a due date

   b. The employee receives an initial task alert e-mail message

   c. Four business days before the due date, if the task has not been completed, the employee receives a reminder e-mail

   d. Two business days after the due date, if the task has not been completed, the employee receives the first late reminder e-mail

   e. Seven business days after the due date, if the task has not been completed, the employee receives the first second reminder e-mail

2. To setup our environment we will need to create a custom task list. From the front page of your SharePoint site follow this click path: Site Actions -> Create -> Tracking -> Tasks. Name the new list “Business Days Task Reminder Workflow”. Choose “No” for the “Send e-mail when ownership is assigned” function. The list will have the following standard fields:

  • Title - Single Line of Text
  • Priority - Choice
  • Status - Choice
  • % Complete - Number
  • Assigned To - Person or Group
  • Description - Multiple lines of text
  • Start Date - Date and Time
  • Due Date - Date and Time
3. To build this application we will need four custom components, the SPD workflow to send the e-mail alerts, and three calculated columns to define the proper business day ranges, i.e. four days before due date, two days after the due date, and seven days after the due date.

4. To build the calculated columns we need to first configure our calculated columns to count business days (Monday through Friday) and ignore weekends (Saturday and Sunday). This can be done using the calculated column’s Weekday function and some simple conditional logic. The Weekday function returns an integer for each day of the week, as shown below:

  • Sunday 1
  • Monday 2
  • Tuesday 3
  • Wednesday 4
  • Thursday 5
  • Friday 6
  • Saturday 7
Now using the Weekday function we can use some simple conditional logic to determine business day, such as shown below:

   If Weekday > 1 and Weekday < 7

5. Unfortunately it’s not enough to simply know that the date is a business day, we also have to know how many business days it is from the Due Date, and we have to know this for both before and after the due date. So let’s look at the logic to determine these dates, first here is the logic for calculating 4 business days before the Due Date:

   =IF(WEEKDAY([Due Date])<6,[Due Date]-6,IF(WEEKDAY([Due Date])=6,[Due Date]-4,[Due Date]-4))

Essentially this logic can be explained as follows:

   • If the Due Date is before Friday, subtract 6 from the Due Date to derive the date 4 business days before the Due Date

   • If the Due Date is a Friday, subtract 4 from the Due Date to derive the date 4 business days before the Due Date

   • We don’t need logic for a Due Date of Saturday or Sunday since those aren’t business days

6. Next, here is the logic for calculating 2 business days after the Due Date:

   =IF(WEEKDAY([Due Date])>4,[Due Date]+4,IF(WEEKDAY([Due Date])>1,[Due Date]+2,[Due Date]+2))

Essentially this logic can be explained as follows:

   • If the Due Date is after Wednesday, add 4 to the Due Date to derive the date 2 business days after the Due Date

   • If the Due Date is after Sunday, add 4 to the Due Date to derive the date 2 business days after the Due Date

   • We don’t need logic for a Due Date of Saturday or Sunday since those aren’t business days

7. Finally, here is the logic for calculating 7 business days after the Due Date:

   =IF(WEEKDAY([Due Date])<5,[Due Date]+9,[Due Date]+11)

Essentially this logic can be explained as follows:

   • If the Due Date is before Thursday, add 9 to the Due Date to derive the date 7 business days after the Due Date

   • If the Due Date is Thursday or later, add 11 to the Due Date to derive the date 7 business days after the Due Date

8. Next we need to add all the other lists elements as shown below (Picture1):



There is one other calculated column, Start Date – No Time, its calculation is shown below:

      =TEXT([Start Date],"mmm-dd-yyyy")

And finally, there are two choice columns, they have these values:

   • Priority:

       (1) High

       (2) Normal

       (3) Low

   • Status:

      No Action Taken

      Approved

     Denied

9. Now that we have all the date calculations and other columns in place we can easily create a workflow to send reminders on those dynamic dates. The workflow will be configured to run on "Item Created". Our workflow will have the following four steps:

   a. Send Initial Email

   b. Remind 4 Days Before

   c. Remind 2 Days After

   d. Remind 7 Days After

10. Here is the logic for Step 1 – Send Initial Email (Picture 2):



The “Due Date – No Time does not contain Dec-30-1899” and the “Start Date – No Time does not contain Dec-30-1899”. These conditions are present to prevent the workflow from running if the user has not provided a Due Date or a Start Date. Normally these would be mandatory fields but in this case the customer wanted the ability to do a draft task, and not have to worry about the workflow sending out partial data. If the user doesn’t supply a Due Date or a Start Date the calculated column will generate a date of Dec-30-1899 (because the date is blank) and the workflow will not start.

I use a Boolean called First Run to tell me if the workflow has been rerun and if so to protect against certain conditions causing errors. As you will see, all the other steps will only be run if First Run equals “No”. The First Run value is changed when the Action “Update Items in Tasks” runs (the third Action in this step).

The initial e-mail is sent to the Assignee in the second Action of this step. Obviously the content of the e-mail can be whatever the user requires but essentially it is informing the recipient about the details of the tasks they must perform.

As you can see in the pause action, the pause is set to a date and the date is set equal to the calculated column “Due Date Minus 4 BDs”.

11. Here is the logic for Step 2 - Remind 4 Days Before (Picture 3):



In the conditions the First Run value should now be changed to “No”, if the value is “Yes” it means the conditions of the first step were not met and therefore this step should not run either.

The second e-mail is sent to the Assignee in the second Action of this step. The content of the e-mail can be whatever the user requires but basically it’s a reminder that the task has still not been completed.

As you can see in the pause action, the pause is set to a date and the date is set equal to the calculated column “Due Date Plus 2 BDs”.

12. Here is the logic for Step 3 - Remind 2 Days After (Picture 4):



Again, in the conditions the First Run value should now be changed to “No”, if the value is “Yes” it means the conditions of the first step were not met and therefore this step should not run either.

The third e-mail is sent to the Assignee in the second Action of this step. The content of the e-mail can be whatever the user requires but again basically it’s a reminder that the task has still not been completed.

As you can see in the pause action, the pause is set to a date and the date is set equal to the calculated column “Due Date Plus 7 BDs”.

13. Here is the logic for Step 3 - Remind 7 Days After (Picture 5):



Again, in the conditions the First Run value should now be changed to “No”, if the value is “Yes” it means the conditions of the first step were not met and therefore this step should not run either.

The final e-mail is sent to the Assignee in the second Action of this step. The content of the e-mail can be whatever the user requires but basically it’s a notice to the end user that the task has still not been completed within the allotted time.

14. OK, now both our calculated columns and our workflow are ready! Now let’s try out our application. Create a new task in the task list. Fill out the task as normally but in the Status field choose “No Action Taken”. For testing choose yourself as the “Assigned To”. Select the current date as the “Start Date”, and a day a week from now as the “Due Date”. Finally, click the OK button to start the workflow.



15. If everything is built correctly the workflow should send out an initial e-mail, a reminder e-mail 4 business days before the Due Date, another reminder e-mail 2 business days after the Due Date, and a final reminder e-mail 7 business days after the Due Date.

16. As always the power and utility of SharePoint Designer workflows amazes me – all this function without any code – now that is awesome!


I hope that helps!

Tom Molskow












Thursday, January 13, 2011

SharePoint Designer Workflows 3 - Developing a Timer Loop for Workflows

1. Introduction: Many times when designing workflows there is a need to use a Workflow Timer. As you may know a workflow timer will process workflows at a specified time or interval. While SharePoint Designer does not provide an out of the box (OOTB) capability for creating workflow timers, still, there is a way to create a workflow timer using SPD workflows.

2. Scenario: In our simple scenario we want our example workflow to run every five minutes. Now, given this is not a very realistic scenario, most users will want the workflow to run once a day, week, month, etc. However, once we have designed the mechanism to run a workflow every five minutes, it’s a simple matter of changing the pause delay to increase that to any duration needed.

3. Explanation: Essentially we will have two workflows, running on two separate lists; one workflow, “Endless Loop”, creates an endless loop and the other workflow, “Delay”, one creates a delay or timer. The logic for the Endless Loop workflow looks like this:

a. Calculate (increment) the loop counter

b. Update the item in the Delay workflow with the counter value

c. Log the Event

The logic for the Delay workflow looks like this:

a. Calculate (increment) the loop counter

b. Pause (Delay) for a period of time

c. Update the item in the Loop workflow with the counter value

4. Overview: To build a Workflow Timer we will need two SharePoint lists, and two SharePoint workflows. The first list will contain our Loop workflow, and the second list will contain our Delay workflow. For obvious reasons we will call the first list “Endless Loop” and the second list “Delay”. To create the lists follow these steps:

a. From the SharePoint site create a custom list, call it “Endless Loop”

b. From the Loop list add a custom Number column, call it “Counter”, set it’s number of decimal places to 0 and it’s default value to 1, finally add it to the default view

c. Create 1 item in the list and title it Endless Loop

d. From the SharePoint site create a custom list, call it “Delay”

e. From the Delay list add a custom Number column, call it “Counter”, set it’s number of decimal places to 0 and it’s default value to 1, finally add it to the default view

f. Create 1 item in the list and title it Delay

To create the workflows for these lists follow these steps:

a. From SharePoint Designer create a workflow that is associated with the Endless Loop list, call it “Endless loop”

b. Set this workflow to be started manually and to start automatically when an item is changed

c. Create 1 step for the workflow, call it “Endless Loop”

d. Create a condition – If Created By is not empty – this means the workflow will always run

e. Add a Do Calculation item, set it to Calculate Endless Loop: Counter plus 1 (output to Variable: calc), the configuration should appear as below:












f. Add an Update List Item activity, update the Delay list, Delay item, changing the value of Counter to the workflow calc variable’s value, configure the activity as shown below:


















g. Add a Log to History List activity, configure the log to write “Endless Loop – Ran”

h. The complete workflow configuration should appear as below:








i. From SharePoint Designer create a workflow that is associated with the Delay list and call it “Delay”

j. Set this workflow to start automatically when a item is changed

k. Create 1 step for the workflow, call it “Delay”

l. Create a condition – If Created By is not empty

m. Add a Do Calculation item, set it to Calculate Delay:Counter plus 1 (output to Variable: calc), the configuration should appear as below:











n. Add a Pause for Duration activity, pause for 5 minute (this is only a place holder testing value that can be increased to whatever value is needed for the delay)

o. Add an Update List Item activity, update the Endless Loop list, Endless Loop item, changing the value of Counter to the workflow calc variable’s value, configure the activity as shown below:




















p. Add a Log to History List activity, configure the log to write “Delay – Ran”

q. The complete workflow configuration should appear as below:









5. Test the Workflows: To test the workflow we only need to start the Endless Loop workflow from our item in the Endless Loop list. After a while we will see that the two workflows will keep initiating each other forming an endless loop.

6. Now Add Your Activity: Now you only need to add your activity to the loop, the best location being right after the Pause for Duration action in the Delay workflow. Once you add your activity here, it will run at the interval that you set in your Pause for Delay.

7. References: Use SharePoint Designer to Email Daily Task Reminders

Tuesday, January 11, 2011

SharePoint Designer Workflows 2 – Developing a For Each Loop for Workflows

(For those using SharePoint 2010 please see my other post - Create a For Each Loop for Workflows Using SharePoint Designer 2010 - the technique described below will only work for SharePoint 2007)

 1. Introduction: Many times when designing workflows there is a need to use a “For Each Loop”. As you may know a For Each Loop will continue to process an action against a list of items until all items in the list have been processed. While present in all programming languages whether declared, script or object oriented, the For Each Loop is not present in SharePoint Designer workflows, or the other GUI driven workflow tools I know. This article will help you build a For Each Loop for your SharePoint Designer workflow.

2. Scenario: In our simple scenario we want our workflow to run through each of several items in a list and to update each of the items Boolean “Processed” field from No to Yes (For Each list item update Processed field to Yes).

3. Explanation: Essentially we will have two workflows, one to create and delete a new item in the “Loop” list, and the other to update the Data list. The logic for the first workflow looks like this:
a. Create an item in the Loop list

b. Pause (allowing the Loop list workflow to run)

c. Delete the item created in Loop list

The logic for the second workflow looks like this:

a. Update the first item whose “Processed” field is set to No

4. Overview: To build a For Each Loop we will need two SharePoint Lists, the first list will contain our data, and the second list will control the For Each Loop. For our example we will call the first list “Data” and the second list “Loop”. We will also need two SharePoint workflows, one, to create and delete items in the For Each Loop list, and one to update items in the Data list. To create the lists follow these steps:

a. From the SharePoint site create a custom list, call it “Data”

b. From the Data list add a custom Boolean column, call it “Processed”, set it’s default value to No and add it to the default view

c. From the Data list create several list items

d. From the SharePoint site create a second custom list, call it “Loop”

e. From the Loop list create 1 item

5. To create the workflows for these lists follow these steps:

a. From SharePoint Designer create a workflow that is associated with the Loop list, call it “For Each loop”

b. Set this workflow to start automatically when an item is created

c. Create 1 step for the workflow, call it “For Each Loop”

d. Create a condition – If Created By is not empty – this means the workflow will always run

e. Add an Update List Item activity, configure the activity as shown below:


f. Add a Pause for Duration activity, configure the activity to pause for 1 minute

g. Add a Log to History List activity, configure the log to write “For Each Loop – Ran”

h. The complete workflow configuration should appear as below:











i. From SharePoint Designer create a workflow that is associated with the Data list and call it “Process Data”

j. Set this workflow to start automatically when a item is changed

k. Create 1 step for the workflow, call it “Process Data”

l. Create a condition – If Created By is not empty

m. Create a second condition and Processed not equals No – this means the workflow will not run if the Processed equals no

n. Add a Create List Item activity, create a new item in the Loop list, title the new item “New Loop Item”, and output to variable “idLoopListItem” of the type list ID, the activity should appear as below:










o. Add a Pause for Duration activity, pause for 1 minute

p. Add a Update List Item activity, update the current item in Data and change the value of Processed to No

q. Add a Delete Item activity, and delete the item in the Loop list that has the same id as the idLoopListItem or the item you just created (by deleting the item we will keep this list from growing too large in the future). The configuration should appear as below:


















r. Add a Log to History List activity, configure the log to write “Processed – Ran”

s. The complete workflow configuration should appear as below:












6. Test the Workflows: To test the workflow we only need to start the For Each Loop workflow from our item in the Loop list.

7. Error Messages: The last item created in the Loop list will have an error occurred in the workflow metadata field. This is because the last item to start cannot find any items that have not been processed. This error can be ignored; it’s part of the normal processing and will eventually be deleted by the Process Data workflow.

8. Thanks: I want to acknowledge Ricky Spears for his article “Looping through Items in a SharePoint List with SharePoint Designer Workflows”, which provided the technique that I describe in this article.

Monday, January 10, 2011

SharePoint Designer 2007 Workflows 1 – Best Practice Solution for Logging Runtime Workflow Errors

1. Introduction: When employing SharePoint Designer 2007 Workflow (SPDWF) applications it is very important to be able to identify, log and track runtime workflow errors. Typical requirements for this type of solution include the following:

a. Automatic alerts when errors occur – when a workflow error occurs the user will need to be alerted immediately

b. One location error logging – when a workflow error occurs the user will want to go to one location where workflow error information is logged

c. Workflow error step identification – when a workflow error occurs the user will want to go be able to identify which workflow step caused the error

This article will help you develop a best practice solution for logging runtime workflow errors that meets all these requirements.

2. Overview: As an overview let’s first discuss the types of SharePoint Designer Workflow (SPDWF) error logging available to us, the types are listed below:

a. List Item Error Logging: When a SPDWF error occurs that error is logged to the list item’s metadata, and appears as the message “Error Occurred”.

b. Workflow History Error Logging: When a SPDWF error occurs that error is logged to the workflow history for that item, and appears as a variety of messages depending on the error that occurred.

c. Custom Workflow Logging: With properly designed custom workflow logging, the step in which an error occurred in a SPDWF can easily be identified.

3. Best Practice: So to develop our runtime error logging best practice solution we will need to use all three types of error logging capabilities available to us as well as some other out of the box (OOTB) SharePoint capabilities. Our solution will have the following components:

a. Automatic Alerts: We will create a workflow dashboard that alerts an identified user when a workflow error occurs.

b. Workflow History Error Logging: We will leverage the OOTB capabilities of SPDWF error logging to point the user to one error logging location.

c. Workflow Error Step Identification: We will develop a custom workflow log that helps to identify the workflow step that caused the error. (This log will be written to the same location as the OOTB workflow error log).

While the requirements of the solution appear in the order the user will experience them, the design and build for the solution will occur in the opposite order, and so we will discuss the solution components in this order.

4. Design the List and Workflow: For our solution we will develop a very simple list and workflow, just as a straw man to use to illustrate our logging design. The workflow will have three steps, each step with one condition, and two actions. We will use the first step to establish the context of the error (i.e. step one will not cause an error), and we will use the second step to identify an error (i.e. step two will cause an error), and we will use the third step to establish whether or not the workflow completed. Here are the steps to creating our list and workflow:

a. From the SharePoint suite create a new custom list, call it “Workflow Log List”

b. From “Workflow Log List” create a new custom text column, call it “Force Workflow Log Error”, click on “Add to default view” and click OK

c. From “Workflow Log List” create a new custom Boolean column, call it “Workflow Ran”, click on “Add to default view” and click OK

d. From Workflow Log List create two items, for item 1 in the list set the title to “Title 1”, and then set the “Force Workflow Log Error” column to “No Error”, and for item 2 in the list set the title to “Title 2”, and then set the “Force Workflow Log Error” column to “Error”

e. From SPD, create a new custom workflow for the Workflow Log list, call it “Workflow Log”

f. From the “Define your new workflow” screen of the “Workflow Log” workflow set the workflow start options to “Allow this workflow to be manually started from an item”, and “Automatically start this workflow when a new item is created”

g. From Workflow Log workflow, create a workflow step, call it “Workflow Step 1”

h. From Workflow Step 1, create one condition – “If Created By is not empty” – this step will run whenever a list item exist

i. From Workflow Step 1, create two actions – “Update item in this list” and “Log this message to the workflow history list”

j. From the Update item in this list action add logic to update the current item in the list so that the value of our custom text column “Title” is set to “Update Title”

k. From the Log this message to the workflow history list action add logic to write “Workflow Step 1 - Ran” to the History log

l. From Workflow Log workflow, create a second workflow step, call it “Workflow Step 2”

m. From Workflow Step 2, create one condition – “If Created By is not empty” – this step will run whenever a list item exist

n. From Workflow Step 2, create two actions – “Update item in this list” and “Log this message to the workflow history list”

o. From the Update item in this list action add logic to update the current item in the list so that the value of our custom text column “Force Workflow Log Error” is set to “Force Error”

p. From the Log this message to the workflow history list action add logic to write “Workflow Step 2 - Ran” to the History log

q. From Workflow Log workflow, create a third workflow step, call it “Workflow Step 3”

r. From Workflow Step 3, create one condition – “If Created By is not empty” – this step will run whenever a list item exist

s. From Workflow Step 3, create two actions – “Update item in this list” and “Log this message to the workflow history list”

t. From the Update item in this list action add logic to update the current item in the list so that the value of our custom Boolean column “Workflow Ran” is set to “Yes”

u. From the Log this message to the workflow history list action add logic to write “Workflow Step 3 - Ran” to the workflow history list

5. Design the Workflow Dashboard: In addition to our list and workflow we want to design a workflow dashboard, the purpose of the dashboard is to tell us whenever an error occurs in the workflow.

a. From the site create a custom list, call it “Workflow Dashboard”

b. From the Workflow Dashboard list click on Site Actions -> Edit Page

c. From the Edit Page view click on “Add a Web Part”

d. From the Add Web parts dialogue box choose Workflow Log List and then click Add – the Workflow Log List web part will be added

e. Click on the Workflow Dashboard web parts Edit menu and choose Delete – we will not need this list’s default web part

f. From the toolbar of the Workflow Log List web part choose Actions -> Alert Me, this will take you to the New Alert view

g. From the New Alert view accept all the default settings by clicking OK – This will create an Alert that is generated every time there is a change in any of the Workflow Log List items

6. Test the Solution Workflow – No Error: Now we are ready to test our workflow and demonstrate a simple logging message. Follow these steps to test the workflow and generate the logging message:

a. From the Workflow Log List, item 1 (Title 1), click on the list item drop down menu and choose the Workflows menu item

b. From the workflows view page, click on the “Workflow Log” item

c. From the workflow initiation page click on the “Start” button

d. When you are returned to the list item view page you should see the message “Completed” under the Workflow Log column.

e. Click on the “Completed” link under the Workflow Log column and you will be taken to the Workflow Status page

f. On the Workflow Status page under the “Workflow History” page you will find our three custom log entries:

i. Workflow Step 1 – Ran

ii. Workflow Step 2 – Ran

iii. Workflow Step 3 – Ran


 g. You will receive an Alert like the one below, this alert informs you that something has changed in the Workflow Log List, notice that the Workflow Ran field has an entry - “Yes”
  

7. Test the Solution Workflow – Error: Now we are ready to test our workflow error logging by forcing a simple error to occur. Follow these steps to test the workflow and generate the logging message:

a. From the Workflow Log List tool bar, click on Settings, List Settings

b. From the Workflow Log List settings page, under the Columns heading, click on the Force Workflow Log Error column

c. From the Force Workflow Log Error column’s edit column page, at the bottom find the Delete button and click on it, and then choose OK when the warning message appears – This will delete our Force Workflow Log Error column and therefore force our workflow to throw an error when it attempts to update this column

d. From the Workflow Log List, item 2 (Title 2), click on the list item drop down menu and choose the Workflows menu item

e. From the workflows view page, click on the “Workflow Log” item

f. From the workflow initiation page click on the “Start” button

g. When you are returned to the list item view page you should see the message “Error Occurred” under the Workflow Log column

h. Click on the “Error Occurred” link under the Workflow Log column and you will be taken to the Workflow Status page

i. On the Workflow Status page under the “Workflow History” page you will find the following three log entries:

i. Error updating a list item: This is the message concerning the cause of the error – our error was caused by a problem that prevented the update of a list item

ii. Workflow Step 1 – Ran: This is the last step of the workflow that ran successfully

iii. An error has occurred in Workflow Log: This is where the error occurred, by interpretation we know we this is Step 2 because step 1 ran successfully but Step 2 did not






j. You will receive an Alert like the one below, this alert informs you that something has changed in the Workflow Log List, notice that the Workflow Ran field has an entry - “No”








8. Review of Our Design:

a. Workflow Error Step Identification – Custom Error Logs: SPDWF provide many useful conditions and actions, but for our best practice solution, one action is not only useful, it is essential - the “Log to History List” action. In our solution we ensured that each workflow step had a log that identified 1.) The workflow step name and 2.) The workflow step condition

b. Workflow History Error Logging – OOTB SPDWF Error Logging: By combining the OOTB SPDWF error logging with our custom logging, we are able to easily identify at which step the workflow failed

c. Automatic Alerts – Workflow Dashboard: By developing a custom workflow Dashboard we were able to alert the user to when a workflow failed

9. More Advanced Design: In addition to our rather simple alert system we can develop a more advanced alert system that sends a detailed error message with the list item ID, time of error, error message, last successful workflow step, etc. To implement this type of functionality will require developing a custom SharePoint event handler, however, this type of handler would be very useful and very reusable. I won’t cover how to develop that workflow event handler here, but maybe in future articles.

10. Conclusion: By combining both the OOTB SPDWF error logging system, with custom SPDWF logging and custom Alerts we are able to quickly and easily identify, log and track workflow errors.

Wednesday, December 15, 2010

Create a Custom Content Type

1. When your organization begins to use SharePoint 2007 or 2010, sooner or later they will want to discuss the subject of Content Types – What are they? When should they be used? How do we make custom content types? In this article I will try to answer those questions as well as take you through the step-by-step process of making a custom content type.

2. Microsoft provides the following discussion of Content Types:

“A content type is a reusable collection of metadata (columns), workflow, behavior, and other settings for a category of items or documents in a Microsoft SharePoint list or document library. Content types enable you to manage the settings for a category of information in a centralized, reusable way.

For example, imagine a business situation in which you have three different types of documents: expense reports, purchase orders, and invoices. All three types of documents have some characteristics in common; for one thing, they are all financial documents and contain data with values in currency. Yet each type of document has its own data requirements, its own document template, and its own workflow. One solution to this business problem is to create four content types. The first content type, Financial Document, could encapsulate data requirements that are common to all financial documents in the organization. The remaining three, Expense Report, Purchase Order, and Invoice, could inherit common elements from Financial Document. In addition, they could define characteristics that are unique to each type, such as a particular set of metadata, a document template to be used in creating a new item, and a specific workflow for processing an item.

You can use each of the content types in this example on any document library in the site hierarchy, and you can use all of them together on the same document library. When business requirements change, you can modify the content types to meet the new requirements and push down the updates to any document library where the content type is used.”

http://msdn.microsoft.com/en-us/library/ms472236.aspx

3. From this discussion we can derive the basic characteristics of Content Types:

a. They are reusable

b. They are a collection of metadata (columns)

c. Workflow, behavior, and other settings can be assigned to them

d. They can be centrally managed

e. Their settings can be inherited by other Content Types

f. They can be used throughout the site collection

g. Changes to a Content Type can be pushed to any lists that are using it

4. So now we need to create a custom content type for our new SharePoint application. Here is our scenario:

• The customer receives help request e-mails from various users

• The customer wants to receive these requests in his SharePoint site so he can use workflow and collaboration to develop, track, and monitor responses

• The customer will need to use a custom e-mail enabled SharePoint library

• When the e-mails arrive the SharePoint site must capture certain information from the e-mail itself as well as other calculated information from an event handler

• The customer will not directly create e-mail documents in the list, SharePoint will create the documents automatically when an e-mail arrives

• Below are the metadata fields the custom Content Type for our library must have:

o EmailID – Number

o Title – Single Line of text

o Date Received – Date and Time

o Due Date – Date and Time

o Reply Status – Choice

o E-mail Sender – Single Line of Text

o E-mail From – Single Line of Text

o E-mail To – Single Line of Text

o E-mail CC – Single Line of Text

o E-mail Subject – Single Line of Text

o E-mail Body – Multiple Lines of Text

o Event Log – Multiple Lines of Text

o DueDateNoTime – Calculated

o ReceivedDateNoTime – Calculated

• The Content Type will also have a workflow associated with it – the “Inbox” workflow

5. So, to begin with, we need to create a blank Content Type which we can then customize with the columns we need. Below are the steps for creating a custom content type:

• From the site’s front page, choose Site Actions -> Site Settings

• From the Site Settings page, under the Galleries heading, choose Site Content Types

• From the Site Content Type Gallery click on the Create Button

• From the New Site Content Type page, in the Name and Description section, provide a name and Description for the content type – we will use “Custom Inbox” as the name

• From the New Site Content Type page, in the Name and Description section, choose Parent Content Type from - we will use Document Content Types

• From the New Site Content Type page, in the Name and Description section, choose Parent Content Type – we will use Document

• From the New Site Content Type page, in the Group section, choose which group you want your content type to reside in - we will choose Existing Group: Custom Content Type

• Click the OK button

6. Next, we create the custom content type columns. (All the columns will be new custom site columns except Due Date, because this column already exists and its format is fine for our needs.) Below are the steps for adding a custom column:
• From the Site Content Type: Custom Inbox configuration page , under the columns heading, choose “Add from new site column”

• From the New Site Columns: Solutions page provide the name, field type, and pertinent information for each metadata item

• For each metadata item choose to Put this site column into: Existing group: Custom Columns




• In the Update List and Site Content Types section, choose No for the Update all content types inheriting from this type? Configuration





• Click OK

7. There is one existing site column to add, Due Date. Below are the steps for adding an existing site column:

• From the Site Content Type: Custom Inbox configuration page , under the columns heading, choose “Add from existing site column”

• From the Select Columns section, choose select columns from “All Groups”, Available Column “Due Date”, and choose Add

• From the Update List and Site Content Types section, Update all content types inheriting from this type? selection choose No






8. Our next step is to associate a SharePoint workflow with our custom content type. To do this we need to accomplish two actions – Removing the workflows we don’t want associated with the Content Type, and adding the workflow we do want associated. To remove the workflows we don’t want associated follow these steps:

• From the Site Content Type: Custom Inbox configuration page , under the settings heading, click on workflow settings

• From the Change Workflow Settings page, under workflows, choose Remove a Workflow

• From the Remove Workflows page, choose to remove the Approval, Collect Feedback, and Collect Signatures workflows





• Now click OK

• The three default workflows will now be removed

9. To add an association for our custom workflow follow these steps:

• From the Site Content Type: Custom Inbox configuration page , under the settings heading, click on workflow settings

• From the Change Workflow Settings page, under workflows, choose Add a Workflow

• From the Add a Workflow page, in the workflow section, choose to add the ContactUsInbox workflow





• Name the workflow - Contact Us Inbox Workflow

• In the Start Options section choose Allow this workflow to be manually started by an authenticated user with Edit Items Permissions and Start this workflow when a new item is created





• Now click the Next button

• On the next page add a comment “This workflow runs automatically whenever a new e-mail arrives”

• Then click OK to exit this configuration area

10. At this point we have our content type configured, but we still have not put it into us in our site, that is our next step. Since we created a custom Document Content Type, we will need to create a document library to house it. Let’s start by creating a document library in the usual way – we will call the library “Contact Us Inbox”. Once our library is created we are ready to associate our content type with it, to accomplish this follow the steps below:

• From the Document Library click on Settings -> Document Library Settings

• From the Document Library settings page, Under the General Settings header choose Advanced Settings

• From the Advance Settings page, in the Content Types section, for the Allow management of content types configuration choose – Yes, and then click OK

• From the Document Library settings page, under the Content Types Header, choose Add from existing content types

• From the Add Content Types page, in the Select Content Types section, from Available Site Content Types, choose “Custom Inbox”, and then click the Add button

• Click the OK button to return to the From the Document Library settings page

11. Now we need to remove the default Document content type, while SharePoint list and libraries can support multiple Content Types, in our scenario we only want this document library to support our custom content type. To remove the default Document content type follow these steps:

• From the Document Library settings page, under the Content Types Header, click on the Document content type

• From the List Content Type page, under the settings header, click on Delete this content type

• When the pop-up message box appears with the warning message “Are you sure you want to delete this content type” choose OK

• The content type will be deleted (but only from this one Document library) and you will be returned to the Document Library settings page

• Now the only content type used by this document library will be our Custom Inbox content type

12. Now go back to the Document library, and from the library menu choose New, and then from the drop down choose “Custom Inbox”. Your custom Inbox document should open and you should see all the associated metadata from your custom content type. Since all our documents will be created automatically when our custom SharePoint library receives an e-mail, we will not need to create a document manually and so we can close the document.

I hope that helps!

Tom Molskow

Tuesday, December 14, 2010

SharePoint Form Dynamic Field Hide or Reveal Using JavaScript

1. From time to time a customer asks for fields to be dynamically hidden or revealed on the SharePoint EditForm.aspx or NewForm.aspx. One the most versatile and effective ways to accomplish this is by using the Content Editor Web Part and JavaScript. In this article I will guide you through configuring and developing this kind of functionality.

2. Here is our scenario; we need to add dynamic capability to a custom task form so that when the user edits the task form and chooses to reassign a task the hidden Reassignment Reason Multi-Line Text field is revealed. Our custom task form will have a customized Task Status field and an additional custom field, Reassignment Reason, as shown below:

a. Task Status (Choice)
  • Assigned
  • In Progress
  • Completed
  • Reassign 
b. Reassignment Reason (Multiple Lines of Text)

3. So the first question you may be asking is “How do I add a CEWP to the Edit and New forms?” I’m glad you asked! While the New and Edit forms do not provide an interface to access to the Edit Page function in the Site Actions menu, you can still get access to this capability through the browser by appending the following query to the end of the URL string for the New and Edit forms:

&pageview=shared&toolpaneview=2 

4. OK, so now that you can see the Edit Page interface of the Task Form lets add a CEWP in the usual way, just click on the “Add a Web Part” control at the top of the Web Part Zone and then from the Webpage Dialogue scroll down to the Miscellaneous section and choose Content Editor Web Part. Now click on the Add button at the bottom of the dialogue page and the CEWP will be added to the page.

5. Now click on the edit button of the CEWP in the Web Part Zone and choose the menu option “Modify Shared Web Part”. This will bring up the web part configuration interface in the right panel. From this interface click on the Source Editor and the text entry dialogue box will open. This is the area where you will need to write your code. We aren’t going to write any code right now though, so you can close the dialogue box.

6. Now we have to talk about the special JavaScript function we will need to use in order to “discover” the SharePoint controls in the task edit page – this function is called “getTagFromIdentifierAndTitle” and it is displayed below:

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; 


7. According to Microsoft this JavaScript function “parses the page’s query string, locates the HTML objects that are rendered by the relevant SharePoint fields, and sets their value.” The function can identify the fields by matching three parameters:

a. tagName – The name of the tag rendered in the form’s HTML
b. identifier – The string associated with the SharePoint type of the relevant field
c. title – The value of the relevant HTML tag’s “title” attribute, which also matches the field’s display name

8. While the title parameter is easy to obtain, one of the challenges you will often face when using this script is finding the tagName and identifier parameters. Microsoft provides a partial list as a starting point - see this tech net article:

http://blogs.msdn.com/b/sharepointdesigner/archive/2007/06/13/using-javascript-to-manipulate-a-list-form-field.aspx

9. However, there is another way to find this information, by using a very handy tool set that comes installed with Internet Explorer 8, and which Microsoft has very cleverly named “Developer Tools”. To activate the Developer Tools in IE, press F12 or use the "Tools" – "Developer Tools" menu. To find out more information about any element, click on the “Select Element” arrow in the tool set, and then select the element on the page. The tool set will take you to that elements markup and code and provide a great deal of information about that element to include the identifier and tag name. (If you don’t have the option of updating IE to 8 or higher, with IE7 you can use Developer Toolbar for Internet Explorer.)

10. OK, so now we need to create our function to hide the Reassignment Reason field when the user opens the page. Here is our basic function outline:

_spBodyOnLoadFunctionNames.push("hideField"); {   
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  
//*** Hide the Field ***  
function hideField() 

   theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none";
}  

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; 
}


 a. spBodyOnLoadFunctionNames.push() – This is a built in SharePoint function that will allow you run a function when the page loads. This will be very useful to us because we want to hide the Reassignment Reason field before the form is viewed by the user. 
b. Script Variables – We need to set one variable, the Multi-Line Text Reassignment Reason. This variable will be set using the getTagFromIdentifierAndTitle function
c. style.display – setting this control property to “none” will hide the control from the user.

 11. Now we have to find a way to reveal the control if the user selects the custom task status choice “Reassign” (as well as a way to hide it back if she changes her mind and chooses another task status after the field is revealed). Here is our next bit of code, our revealField() function:

//*** Reveal the Field *** 
function revealField() 

   theInputMLTRR .parentNode.parentNode.parentNode.style.display = "";
}

12. All we need now is a way to capture the onChange() event for the custom Task Status field:

var theChoice = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  
getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason").onchange = function(){revealHideControl()};  

//*** Reveal the Field *** 
function revealHideControl(){  
if (theChoice.value == 'Reassign') { 
revealField(); 
}else 

hideField(); 



13. All we have to do now is copy our script into the CEWP, so let’s go back to the web part configuration interface in the right panel. From this interface click on the Source Editor and the text entry dialogue box will open. Now just copy and paste the code below into the text box and click “Save” which will close the dialogue box. From the right panel interface click “OK” and then from the EditForm.aspx click OK again, and your form is ready to test.

_spBodyOnLoadFunctionNames.push("hideField"); {  
var theInputMLTRR = getTagFromIdentifierAndTitle("TextArea","TextField","Reassignment Reason");  

//*** Hide the Field *** 
function hideField() 

theInputMLTRR. parentNode.parentNode.parentNode.style.display = "none"; 
}  

//*** Reveal the Field *** 
function revealField() 

theInputMLTRR .parentNode.parentNode.parentNode.style.display = ""; 
}  

//*** Capture the Change Event *** 
var theChoice = getTagFromIdentifierAndTitle("select","DropDownChoice","Task Status");  
getTagFromIdentifierAndTitle("select","DropDownChoice","Task Status")onchange = function(){revealHideControl()};  

//*** Reveal or Hide the Field *** 
function revealHideControl()
{  
   if (theChoice.value == 'Reassign')
   { 
      revealField(); 
   } 
   else 
  { 
      hideField(); 
  } 


//*** getTagFromIdentifierAndTitle *** 
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; 

}

14. There are other ways to find controls, such as using the returnObjById(id) function, but for whatever reason, Microsoft doesn’t recommend using this approach. On the other hand, in the SharePoint Community the getTagFromIdentifierAndTitle function is well known, well documented, and heavily used, so I recommend starting with this method whenever possible.

I hope that helps!

Tom Molskow