Project Programmability

This blog focuses on customizations and programming for Project Web App, Project Server, Project Professional and Project Standard. Includes User Interface (UI) customizations, Project Server Interface (PSI) and Visual Basic for Applications (VBA) Programming. It also covers Business Intelligence.
 
 

  • Project Programmability and Business Intelligence

    Statusing Transactions (Partial Documentation)

    • 7 Comments

    Introduction

    Unlike the project Web Access “My Tasks” web part, the Statusing web service API restricts team member task assignment updates that combine with the create/reassign action to one per approval cycle. This means that once a create/reassign plus updated status is submitted it cannot be further updated until accepted or rejected by the Project Manager.

    This limitation is caused by the absence of “Node Consistency” functionality in the API. This component ensures that the task is kept schedule consistent during team member updates. The project Server 2007 architecture placed this component on the Project Web Access web front end server, rather than in the Project Server Interface business object layer, so as to deliver a responsive user experience in the UI.

    Unfortunately the application developer who is tasked with synchronizing status with an external system (such as an ERP or CRM system) has no means to detect this “blocked” status. We plan to add such a method in an upcoming release of Project Server. In the interim this documentation can be used to extend the Project Server Interface to add a web service/method to deliver the status update status.

    Note: This document contains interim documentation for tables in the Published database of a RTM-edition Project Server 2007 installation. Entities in this schema are subject to change without notice. This documentation is made available on a “best efforts” basis, Microsoft Product Support Services have not been trained in its usage and will not offer technical support for issues related to custom queries against this schema. This schema should not be updated by custom code, any updates to the data may break Project client cache code.

    Extending the Project Server Interface

    This is documented in the following Project Server 2007 Software Development Kit article.

    http://msdn2.microsoft.com/en-us/library/bb428837.aspx

    Note that any code will be required to connect to the Project Server 2007 Published database – in a single site farm this may safely be hard coded, however in a multi-site farm it is recommended that the developer implement a method for connecting to the correct published database, suggestions include:

    • Using the SharePoint site-id to index into an INI file with the correct connection string stored as an external string
    • Passing the database (and SQL Server name) as method arguments.

    Understanding the MSP_ASSIGNMENT_TRANSACTIONS Table

    All status updates are stored in the MSP_ASSIGNMENT_TRANSACTIONS table together with flags indicating the current state of the update. The flags necessary to locate a blocked task assignment are documented below.

    clip_image002[4]

    There are four ENUM fields that govern state, these are:

    Attribute Value Enumeration
    ASSN_TRANS_STATE_ENUM 0
    1
    2
    Not Submitted
    Submitted Pending Approval
    Approved or Rejected
    ASSN_TRANS_TYPE_ENUM 0
    1
    2
    3
    4
    5
    6
    7
    Task Assignment Update
    Declined Task Assignment
    Create Task Request
    Delegate Task Assignment Request
    Create Task Assignment Request
    Team Delegation Request
    Delete Task Request
    Delete Task Assignment Request
    ASSN_TRANS_ACTION_ENUM 0
    1
    2
    Pending
    Approved
    Rejected
    ASSN_TRANS_ERROR_ENUM 0
    1
    2
    3
    4
    5
    7
    Applied
    Undefined
    Conflict
    ProjectDeleted
    InvalidUpdate; InvalidDelegation
    InternalError
    Count

    So a blocked task assignment and will have ASSN_TRANS_STATE_ENUM = 1 (pending approval) and ASSN_TRANS_TYPE_ENUM = 2,3,4 (indicating a pending task assignment add/change)

    SQL Server query to test the status of a particular task assignment:
    SELECT TOP 1 ASSN_TRANS_STATE_ENUM 
    FROM MSP_ASSIGNMENT_TRANSACTIONS 
    WHERE ASSN_UID = '617633E6-8B2A-4620-BCAD-F82A95AD398D' -- Assignment UID 
    AND ASSN_TRANS_STATE_ENUM=1 
    AND ASSN_TRANS_TYPE_ENUM IN (2,3,4)
    Notes:

    If the task assignment status update is not blocked then no data will be returned; if it is blocked then a scalar value of integer 1 will be returned.

    See comments in the performance section before changing this query.

    Security Considerations

    PSI Extensions are responsible for implementing their own security. In this case there are mitigations which mean that additional permissions checks may be unnecessary:

    • All callers must be authenticated users making anonymous DoS attacks impossible
    • The proposed solution returns a single numeric result that indicates if the assignment is blocked (1) or not (null)
    • The argument is a UUID – these are very hard to predict/guess so it isn’t possible to cycle through a sequence hunting for hits
    • If an attacker discovers that a particular assignment UID is blocked then there is little they can do with that information
    • The call is extremely performant

    Note that it would be simple to make the call as the “interface user” and test for that in the PSI extension should further restrictions be required.

    Performance Notes

    The above query has been optimized for performance – strictly speaking the query is stronger than required as only the second task assignment status update is blocked by the pending approval. However checking for this first pending update would require the addition of a self-join to the query which would reduce performance considerably. This would test for the above condition AND a pending task assignment status update (ASSN_TRANS_TYPE_ENUM = 0). Provided the work is added in the same ChangeXML payload that changes the task assignment, it is superfluous.

    It is recommended that a query covering index be created on the MSP_ASSIGNMENT_TRANSACTIONS table to avoid both clustered index scans, secondary index scans or bookmark lookups as the table is indexed on a non-sequential UUID (so data access will be very random).

    The following index definition is suggested:

    CREATE NONCLUSTERED INDEX [CUSTOM_STATUS_SYNCH] ON [dbo].[MSP_ASSIGNMENT_TRANSACTIONS] 
    ( 
      [ASSN_UID] ASC, 
      [ASSN_TRANS_STATE_ENUM] ASC, 
      [ASSN_TRANS_TYPE_ENUM] ASC 
    ) ON [PRIMARY]
    

    The sample query (above) uses a TOP 1 clause to further reduce the SQL Server results processing (either no rows or a scalar result set will be returned).

    If you alter the query to return more data, or to use different search arguments then this index definition might need to change.

    Note that creating a stored procedure and using output parameters would further improve performance.

     

    Patrick Conlan

  • Project Programmability and Business Intelligence

    Working with Deliverables

    • 2 Comments

    The other day I had a request from an internal customer that wanted to create deliverables for a large number of tasks that already existed in their project plan. They wanted to be able to simply flag each task as a deliverable and have it published. They did not want to do all the steps involved with creating a deliverable. 

    They also wanted to tightly couple the task name and dates with the deliverable name and dates. Currently, if a deliverable is linked to a task, when the task’s dates change, the dates for the deliverable do not. This is by design to allow the project manager to intentionally make the change to the deliverable dates since these dates are commonly published to a large audience. In this case, the user wanted the deliverable dates to change with the task dates with minimum user intervention.

    To get started, I created a flag enterprise custom field. The custom field that I created was "Pub Deliverable" and it is a task custom field. I added the field to the Gantt Chart view in Project Professional:

    Next, I wrote the following VBA macro:

    Sub Create_Flagged_Tasks_As_Deliverables()
       
        Dim t As Task
        Dim fPub As String

        For Each t In ActiveProject.Tasks

            ' This gets the flag value from the Enterpise Custom Field
            fPub = t.GetField(FieldNameToFieldConstant("Pub Deliverable"))
           
            If fPub = "Yes" Then
               
                ' If the task has this deliverable GUID, then there is no deliverable
                If t.DeliverableGuid = "00000000-0000-0000-0000-000000000000" Then
                    DeliverableCreate t.Name, t.Start, t.Finish, t.Guid
                Else
                    DeliverableUpdate t.DeliverableGuid, t.Name, t.Start, t.Finish
                End If
           
            Else
           
                If t.DeliverableGuid <> "00000000-0000-0000-0000-000000000000" Then
                    DeliverableDelete (t.DeliverableGuid)
                End If
               
            End If
           
        Next t
           
    End Sub

    This macro loops through all the tasks. If the flag field "Pub Deliverable" is set to yes, then it either creates or updated the deliverable. If it is set to no and there is a deliverable associated with the task, the deliverable is deleted.

    Before you can run this code, you will need to publish and create a workspace for your project. To run it, follow these steps:

    1. Open your Project Plan

    2. Press Alt+F11 – This will open the VBA Editor

    3. Double click on ThisProject Object:

    4. Copy the VBA code into the Object

    5. Run it by clicking on the Play button:


    With this solution, the user can simply flag each task that they want published as a deliverable and run the macro. If you want to have this code executed regularly without user intervention, you might want to consider placing this code in an event handler (VBA Event Handler Example).

    Chris Boyd

  • Project Programmability and Business Intelligence

    Checking Errors

    • 3 Comments
    Here is a great recommendation from Jim Corbin:

    There are two main places to check for configuration and runtime errors when you are developing solutions for Project Server. The Unified Logging Service (ULS) trace logs can be more detailed than the application event log.

    · Application events   In the Start menu on the Project Server computer, click Run, and then type eventvwr. In the left pane of the Event Viewer window, click Application to see the events logged by Project Server, Windows SharePoint Services, ASP.NET, SQL Server, custom event handlers, and other applications. The Project Server event sources include ProjectQueueService and pjevtsvc.

    · ULS You can configure the ULS trace log to record specific or all categories and levels of activities in Project Server and SharePoint. To view the trace logs, you can use Windows Notepad, Microsoft Excel, or the Log Viewer add-in feature for SharePoint. Log Viewer is a useful download that is available from CodePlex.

    To configure the ULS trace log for a specific Project category:

    1. Open the SharePoint 3.0 Central Administration application, click Operations, and then click Diagnostic logging in the Logging and Reporting section.

    2. In the Event Throttling section, select a specific category such as Project Server - Server-Side Events. If you select Project Server - General, all Project categories will be logged.

    3. Select the Verbose level for the least critical event to report in the trace log.

    Caution   Run verbose logging only when you need it. Especially on a production server, select only a specific category. The size of logs can grow to be large. To turn off all logging, select the empty category and None for the trace log least critical event. To record relatively few events, select High or Monitorable.

    4. Use the default path for the trace logs, for example, C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS\. If you use the Log Viewer add-in for SharePoint, it looks for trace logs in the default path.

    5. The default maximum number of log files to maintain is 96.

    6. The default number of minutes to use a log file is 30. That is, ULS tracing creates a new log file after 30 minutes. Log files include the date and time in the filename, for example, SERVERNAME -20070424-1612.log.

    To use the Log Viewer add-in for SharePoint:

    1. Download and install the Log Viewer feature from CodePlex SharePoint 2007 Features. See the Releases tab for the list of downloads. The release notes include installation instructions.

    2. The Log Viewer is a global feature. After it is installed, click Operations on the Central Administration page, and then click View Unified Logging Service in the Utilities section.

    3. On the Unified Logging Service (ULS) Logs page, select a file to view, and then select the Project Server category. That shows all of the specific categories such as Project Server Queue, Project Server Server-Side Events, Project Server Reporting, and so forth.

    4. To see all events in the ULS log, leave the trace severity drop-down list blank. If you select Verbose, that shows only the verbose level events.

    5. Click Go.

    Log Viewer add-in for SharePoint showing a ULS log for Project

    68-4526-aeaa-db69b79e60da.gif

  • Project Programmability and Business Intelligence

    Getting at the Task Time Phased Data

    • 3 Comments

    I have been asked many times how to get the task time phased data from the PSI. Unfortunately there is no way to get this through the PSI. I suggest that you either go to the RDB for this information or the cubes. Here is a quick example.

    I created a project with one task and broke the work down over a week:

    clip_image002

    I saved and published the project so that it would make its way into the reporting database. Here is the query I wrote to retrieve this data:

    SELECT     
      MSP_EpmTask_UserView.TaskName,
      MSP_EpmAssignmentByDay_UserView.TimeByDay,
      MSP_EpmAssignmentByDay_UserView.AssignmentWork
    FROM         
      MSP_EpmAssignmentByDay_UserView 
        INNER JOIN MSP_EpmTask_UserView 
    ON MSP_EpmAssignmentByDay_UserView.TaskUID = MSP_EpmTask_UserView.TaskUID WHERE (MSP_EpmTask_UserView.TaskName = 'Task 1')

    Here is the result of the query:
    image

    Chris Boyd

  • Project Programmability and Business Intelligence

    Task Start and Finish Dates

    • 3 Comments

    When working with the task start and finish dates via the Project PSI, you might find some strange behaviors. It is not that it is strange, it is that these two fields are used by the scheduling engine to calculate your project's schedule. Hopefully this post will give you some insight to how to work with these two fields and why they may not be set to values that you expect.  

    When you first create a task, you can set the start date and finish date for the task. The below sample code shows you how to create a new task and how to set these fields:

    dsP = new WSProject.ProjectDataSet();

    WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();
    // Set the requied fields
    taskRow.PROJ_UID = projGuid;
    taskRow.TASK_UID = taskGuid;
    taskRow.TASK_NAME = "Example Task 3"

    // Set the start and finish dates
    taskRow.TASK_START_DATE = new DateTime(2007, 01, 20);
    taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 20);

    taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

    dsP.Task.AddTaskRow(taskRow);

    projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);


    The above sample code sets the start and finish date for the task to be January 20th, 2007. When I publish the project and view it in Project Center Drill Down, this is what I get:

    You might notice that the start date and finish date are not set to January 20th, but instead January 17th. This is because the start date of the project is set to January 17th. When the scheduling engine works out the schedule, it looks at the task I just created and determines that it has no constrains, thus it can be started right when the project begins. Thus the scheduling engine changes the start and finish date to January 17th.

    Now, lets create another task that is dependent on the one we just created. This time, we will make it's start and finish date January 31st, 2007:

    // Create a second task

    dsP = new WSProject.ProjectDataSet();
    taskRow = dsP.Task.NewTaskRow();

    Guid task2Guid = Guid.NewGuid();
    jobGuid = Guid.NewGuid();

    // Set the requied fields
    taskRow.PROJ_UID = projGuid;
    taskRow.TASK_UID = task2Guid;
    taskRow.TASK_NAME = "Example Task 4"

    // Set the start and finish dates
    taskRow.TASK_START_DATE = new DateTime(2007, 01, 31);
    taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 31);

    taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

    dsP.Task.AddTaskRow(taskRow);

    // Here we make it dependent on the task we created before

    WSProject.ProjectDataSet.DependencyRow dependRow = dsP.Dependency.NewDependencyRow();

    dependRow.PROJ_UID = projGuid;
    dependRow.LINK_PRED_UID = taskGuid;
    dependRow.LINK_SUCC_UID = task2Guid;
    dependRow.LINK_UID = Guid.NewGuid();

    dsP.Dependency.AddDependencyRow(dependRow);

    projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

    PublishProject(projGuid);

    Again you will notices that the schedule engine has moved the task forward to January 18th:

    This is because the dependency we added to the new task on the one we had previously created.

    Lets say that you have a task that you need to schedule, but you know it cannot start before a certain date, due to some external factors from your project. In this case, you do not want the scheduling engine to move your task forward beyond that date. In this case, we need to set the TASK_CONSTRAINT_DATE and TASK_CONSTRAINT_TYPE fields. The below sample shows how to do this:

    // Create a task with a constraint
    dsP = new WSProject.ProjectDataSet();

    WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();
    // Set the requied fields
    taskRow.PROJ_UID = projGuid;
    taskRow.TASK_UID = taskGuid;
    taskRow.TASK_NAME = "Example Task"

    // Set the start and finish dates
    taskRow.TASK_START_DATE = new DateTime(2007, 01, 22);
    taskRow.TASK_FINISH_DATE = new DateTime(2007, 01, 22);

    taskRow.TASK_CONSTRAINT_DATE = new DateTime(2007, 01, 22);
    taskRow.TASK_CONSTRAINT_TYPE = (short)Library.Task.ConstraintType.StartNoEarlierThan;
    taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

    dsP.Task.AddTaskRow(taskRow);

    projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

    PublishProject(projGuid);

    Here is what we get:

    So finally we are able to create a task and have it start on a particular date, but there is a catch. You can only put one type of constraint on your task. Here are a list of constraint types that you can use:

     

    Constraint Type Description
    AsLateAsPossible Schedules the task as late as it can without delaying subsequent tasks. Use no constraint date.
    AsSoonAsPossible Schedules the task to start as early as it can. Use no constraint date.
    FinishNoEarlierThan Schedules the task to finish on or after the constraint date.
    FinishNoLaterThan Schedules the task to finish on or before the constraint date.
    MustFinishOn Schedules the task to finish on the constraint date. Once selected the task will not be moveable on the timescale.
    MustStartOn Schedules the task to start on the constraint date. Once selected the task will not be movable on the timescale.
    StartNoEarlierThan Schedules the task to start on or after the constraint date.
    StartNoLaterThan Schedules the task to start on or before the constraint date.

     

    Hopefully you have a somewhat of an idea about creating a task and how the start and finish date is affected by the scheduling engine. Now, lets take a look at updating a task's start and finish date. If you need to update a tasks start or finish date, you will quickly learn that you cannot simply read the project data set, find the task you want to update in the task table and update the start and finish date fields like this:

    dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_START_DATEColumn] = new DateTime(2007, 12, 03);

    You will quickly run into the following runtime exception:

    Column 'TASK_START_DATE' is read only.

    As the exception states, this is because the start date and finish date are read only fields. These fields are read only because they are calculated fields and cannot be set when updating a project data set. 

    So how can you get around this? Again, you can place constraints on the dates like we did when creating tasks. The scheduling engine will honor the constraint when calculating the schedule, but remember, there are other factors that affect the calculation. Such as the number of resource assigned to the tasks and the amount of work required to complete the task. So if you constrain your start date, it will affect your finish date. This is why you can only place one constraint on a task. The below example shows how you can update a task that must start on January 15th, 2007:

    dsP = projWS.ReadProject(projGuid, ProjOutlookConnector.WSProject.DataStoreEnum.WorkingStore);

    dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_CONSTRAINT_TYPEColumn] = (short)Library.Task.ConstraintType.MustStartOn;
    dsP.Tables[dsP.Task.TableName].Rows[1][dsP.Task.TASK_CONSTRAINT_DATEColumn] = new DateTime(2007, 01, 15);

    projWS.QueueUpdateProject(Guid.NewGuid(), sessGuid, dsP, false);

    PublishProject(projGuid);

    Here is what you will see in PWA after publishing the project:

    We have primarily focused on the factors that affect the start date. Just like the start date, the finish date is affected by many factors that the scheduling engine takes under consideration. For example, the finish date is affected by number of resources assigned to the task, calendar exceptions, such as weekends, specific exceptions in individual resource calendars, and the amount of work assigned required to complete the task.

    These are only some basic examples. Project's schedule engine is very complex and there are a number of factors that affect the start and finish date of a task. Hopefully I have given you some insight why your start and finish dates change.

    Chris Boyd

    Technorati Profile
  • Project Programmability and Business Intelligence

    ANNOUNCING: Microsoft Project 2010 Demonstration and Evaluation Installation Pack for RTM is HERE!

    • 2 Comments

    This is a great news! We have just released the Microsoft Project 2010 Demonstration and Evaluation Installation Pack http://go.microsoft.com/?linkid=9713956 that builds on top of 2010 Information Worker Demonstration and Evaluation Virtual Machine http://go.microsoft.com/?linkid=9728417  that SharePoint team has released recently. And yes the Virtual Image that has to be downloaded, imported and running prior to installing “our” Microsoft Project 2010 Demonstration and Evaluation Installation Pack.

    We also advice to watch the following webcast: Project 2010 Virtual Image, Getting Started Quickly (Level 100) 

    Highlights

    - End to end project lifecycle

    clip_image001

    - New Business Intelligence story!

    clip_image002

    - Built on top of common 2010 Information Worker Demonstration and Evaluation Virtual Machine http://go.microsoft.com/?linkid=9728417  using NEW Project 2010 Demo Installation Platform

    clip_image003clip_image004

    Demo storyline

    It follows the life of a project from inception through to completion! Demo storyline offers a comprehensive overview of the new and existing capabilities in:

    · Microsoft Project Professional 2010

    · Microsoft Project Server 2010

    · Microsoft SharePoint 2010 products and technologies

    · Microsoft Office 2010 Products

    More information about the Project 2010 Demo Solution in this comprehensive XPS document (also available on the download page http://go.microsoft.com/?linkid=9713956)

    Project 2010 Demo Installation Platform

    We have published the entire source code of the Project 2010 Demo Installation Platform http://code.msdn.microsoft.com/Project2010DemoPack so us and partners could extend on it and built future demo packs for Project 2010!

    Q&A

    Q: Do I need to download, import and run the 2010 Information Worker Demonstration and Evaluation Virtual Machine (http://go.microsoft.com/?linkid=9728417) before installing the Microsoft Project 2010 Demonstration and Evaluation Installation Pack?

    A: Absolutely yes. Refer to this comprehensive XPS document for more details.

    Q: Could I install this Microsoft Project 2010 Demonstration and Evaluation Installation Pack on any other VM, including Project 2010 Beta?

    A: No.

    Q: Is there anything around evaluation period and expiration I need to pay attention to?

    A: Please follow information included with 2010 Information Worker Demonstration and Evaluation Virtual Machine http://go.microsoft.com/?linkid=9728417 to properly understand procedure like re-arming and activation so you can prevent lot of unpleasant surprises!!!

    Q: Any recommended hardware for good performance?

    A: Yes -  we specify the additional HW requirements in this comprehensive XPS document. We recommend Solid State Drive for great performance. More about HW we use for demoing here.

    Q: How long does it take to install the Microsoft Project 2010 Demonstration and Evaluation Installation Pack on top of 2010 Information Worker Demonstration and Evaluation Virtual Machine?

    A: If the above VM is already running and working properly it takes up to 30 minutes. If you are using Solid State Drive it’s usually around 10 minutes.

    Q: What is in the Microsoft Project 2010 Demonstration and Evaluation Installation Pack?

    A: We have packaged the following content: 4 core Project databases, 1 SharePoint Content database, 1 OLAP Database, number of WSP customizations (check the Solution Starter webcast series here if you want to learn more), additional demo files and PowerShell script for configuring and deploying the whole solution. So that’s it in a nutshell. Check this link for more details http://code.msdn.microsoft.com/Project2010DemoPack.

    Q: Could I only extract the Microsoft Project 2010 Demonstration and Evaluation Installation Pack?

    A: Yes, we have included that option as well based on the demand, but it’s intended for expert use only.

    Q: What if I have additional questions about this Project 2010 Demo Solution?

    A: You have several options – please check this webcast and search or post your questions in this forum.

  • Project Programmability and Business Intelligence

    Improve the Performance of Building the Project Server Data Analysis Cube

    • 3 Comments

    Jack Li has passed along a great tip on how to improve the performance of building the Project Server Data Analysis Cube: 

     

    Recently we have worked with a big enterprise customer using Project Server. They ran into an issue where Project Server reporting component which uses Analysis Server ran very slow during cube population. Eventually, the issue was tracked down to a single query.  The query would take 17 hours to finish for 1 year of data. nHowever, if one applied force order to the query, it would finish within minutes.

     

    Customer had tight deadline and need a solution fast. It would be easy if one could just modify the query to add force order option.  Unfortunately, the query was generated by Analysis Service based on the cube definition. In other words, it couldn’t  be changed.

     

    Enter into plan guide for the  rescue. SQL Server 2005 gives you various means to influence the query plan for a query without adding hints to the query itself directly. You don’t need to change the query which may not be possible without changing the application.

     

    The simplest one is the use use sp_create_plan_guide stored procedure to add a query hint like force order etc.

     

    Here is exactly what we did for our customer:

     

    1)    We  used profiler trace to trace the exact query

    2)    We copied the exact query text and use sp_create_plan_guide to create the plan guide:

     

    EXEC sp_create_plan_guide N'guide_forceorder',

        N'<exact query>',

        N'SQL',

        NULL,

        NULL,

    N'OPTION (force order)'

     

     

    Steps are fairly easy yet it is tricky to implement. If you are not doing it correctly, SQL Server may not use the plan guide you just created.  Here are a few things you need to watch for:

     

    1)    ensure you have the exact text.  Even if you miss a space character, the plan won’t match.   To ensure you get exact text, you should launch  profiler trace while running the application to get the query.   See http://msdn2.microsoft.com/en-us/library/ms188255.aspx for more details.

     

    2)    There are two ways you can verify if SQL actually uses your plan guide. The first one obviously is that your query finishes faster.  Another way is that you will see PlanGuideDB word in the xml plan. So if you do set showplan_xml on and then run the query, you will get xml showplan. If you search the text, you will find PlanguideDB.  

     

    There are more advanced ways to use plan guide including parameterization or use plan. Please refer SQL Server 2005 books online for these advanced topics.

     

     

  • Project Programmability and Business Intelligence

    Writing a PSI Extension for Project Server 2010

    • 2 Comments

    The blog articles How to make PSI Extensions in Project Server 2010 - Part I and  Part II show how to create and use a simple PSI extension that reads a list of timesheets for the current user, by calling both the GetCurrentUserUid method and the ReadTimesheetList method in the extension. The code in the articles requires using the undocumented Microsoft.Office.Project.Server.Interfaces.dll and Microsoft.Office.Project.Server.Schema.dll assemblies, creates WCF channels for the Resource and Timesheet services, and then returns an XML string of the results.

    The blog articles show more information about using WCF development in Project Server than the Project 2010 SDK includes. For background information about why PSI extensions in Project Server 2010 are different than extensions in Project Server 2007, read those articles.

    The PSI Extensions in Project Server 2010.docx article in the attachment (PSIExtension.zip) shows how to create and use a PSI extension that makes the same calls as in the previous blog, but with the following differences:

    • Use the Resource and Timesheet proxy service files, instead of the undocumented assemblies.
    • Configure the services programmatically, similar to the same way shown in Walkthrough: Developing PSI Applications Using WCF, instead of creating a WCF ChannelFactory.
    • Return a TimesheetListDataSet, instead of a string.
    • Use an app.config file for the client, as with any other PSI service, instead of creating a ChannelFactory.

    The PSIExtension.zip attachment includes the draft article, complete code of the extension and a test application, and examples of the PSIExtensions.svc and web.config files for the PSI.

    --Jim

  • Project Programmability and Business Intelligence

    Project Server 2007 Timesheet Data Population Tool

    • 1 Comments
    Technorati tags: , ,

    Bonjour,

    The Project Server 2007 timesheet data population tool has been released on CodePlex: http://www.codeplex.com/EPMTSdatapop

    The Project Server 2007 Timesheet Data Population Tool enables you to simulate timesheet entries in your farm. This tool can help you perform scalability studies of your PS architecture and validate the sizing of an existing architecture (by measuring timesheet queue throughput for instance). This tool can also be used to test timesheet customization, for instance the Timesheet Tied-mode code sample on Codeplex. This powerful tool should not be run a production environment!

    The Timesheet Data Population tool is a console application written in C#.  It uses standard PSI (Project Server Interface) web service methods to populate timesheets.

    Please refer to the latest version of the Project Server Software Development Kit (SDK) for more information on the PSI methods and how to use them.

    This solution starter was written initially to perform Project Server 2003 vs. Project Server 2007 benchmarks, and has been used since to perform scalability studies and to test timesheet customizations.

    A special thank you to Isabel Bernardos and Steven Haden for helping me write and test the tool during PS 2007 scalability studies for large European customers. 

    If you are aware of any useful tools/solutions for Project and Portfolio Server 2007 and you would like to share them with the community via CodePlex please send me an email.


    About CodePlex

    CodePlex is Microsoft's open source project hosting web site. You can use CodePlex to create new projects to share with the world, join others who have already started their own projects, or use the applications on this site and provide feedback. A word about Microsoft’s role: Microsoft does not control, review, revise, endorse or distribute the third party projects on this site. Microsoft is hosting the CodePlex site solely as a web storage site as a service to the developer community.

    Q&A

    Q: Is the tool supported?

    A: There is no support in terms of CSS/PSS. We expect the support being a CodePlex community effort. Please note that the customization code uses standard supported web service calls available out of the box in EPM2007.

    Q: Is the tool free?

    A: Yes.

    Q: Can I distribute the tool and the source code to customers and partners?

    A: Customers and Partners can use both. Please go to CodePlex to agree on the license terms

    Q: Can a partner distribute the tool and code as is?

    A: No, but partners can point their customer to the website to download it.

    Q: Can a customer install the customization and use it?

    A: Yes the customer can, but he/she is responsible for testing it and running it.

    Q: Can I suggest changes to it?

    A: Yes, join the CodePlex community or send us an email: epmssdev@microsoft.com

    Q: Will this tool be distributed in other ways (i.e. DVDs)?

    A: No.

    Q: What skills do I need to modify or change the tool?

    A: C#, Project Server Interface, and a good understanding of the EPM 2007 data schema.

    Q: I’m trying to modify the code and do have questions. Who do I ask?

    A: Go to the Discussions forums on CodePlex.

    Q: What are all the EPM projects released on CodePlex?

    A. Check this: http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=epm

    Regards,

    Christophe Fiessinger

  • Project Programmability and Business Intelligence

    Publishing Projects based off a Project Custom Field Value

    • 3 Comments

    Hello,

    As part of the development process for the next version of Project, we are heavily relying on Project to manage all the work that is happening across team. As part of the process, we require up to date status reports. All the work is spread across 40 project plans, so we cannot rely on PMs publishing projects daily. To ensure the status reports are up to date, we publish all the projects nightly by running a custom application as a scheduled Windows task:

     

    image

    Since we only want to publish our team's projects and cannot publish other teams projects on the server, we tag all of our team projects with text custom fields that have associated lookup table to ensure that everyone on the team is using the same tags:

    image

    To setup the custom field and lookup tables:

    1. Log onto Project Server as an Administrator
    2. Click on "Server Settings" then click on "Enterprise Custom Field Definition"
    3. Scroll to the bottom of the page and click "New Lookup Table". We created a lookup table called "Office Division", which has all the divisions within Office:

      image 
    4. Next, create a custom field, which we called "Office Division", and associate it to the lookup table:

      image

    The application to publish the projects nightly is attached to this post. It is a fairly simple application. At the top of the program class, we have set a few constants. If you wanted to try out this application, you should just have to change these constants and compile the application. These constraints are self explanatory:

    const string ls_projURL = "http://Office/PWA/";     // Server URL
    const string ls_CustomField = "Office Division";    // Custom Field 
    const string ls_LookupTableValue = "Project";       // Value in the lookup table

    Once we had the application built, we simple set up a scheduled task in Windows to run the application nightly:

    image

    Chris Boyd

  • Project Programmability and Business Intelligence

    Creating Deliverable Reports

    • 0 Comments

    I have had many questions with regards to the Deliverables feature and reporting. If your not familiar with Deliverables, I suggest you take a look at my blog post on the Project blog:

    http://blogs.msdn.com/project/archive/2007/02/24/deliverables.aspx


    Just like all other project data, when a project plan is published, the data makes it way to the reporting database. This allows you to create some very useful reports on deliverables and dependencies. To get started with reporting, you may want to read through this post:

    http://blogs.msdn.com/project_programmability/Default.aspx?p=2

    In this post, I am only going to provide some background information on Deliverables and a couple of queries to get you started with creating your own reports. To begin with, these are the views and tables that are most commonly used for Deliverable reports:

    MSP_EpmProject_UserView

    This view shows all the projects. Commonly you will join the Project UID in this view with the Project UID or the Relationship UID from the other views. By doing this you can get information about the project the deliverable or dependency is associated with, such as the name of the project.
    MSP_WssDeliverableToProjectLinks_UserView

    This view lists all the published deliverables, not the dependencies. In this view you can get information such the UID for the project a deliverable is associated with and the start and finish date of a deliverable.
    MSP_WssDeliverableToTaskLinks_UserView

    This is the same at the MSP_WssDeliverableToProjectLinks_UserView except that is has additional fields for deliverables that are linked to tasks. This allows you to report on task details for the associated deliverable. For example, you could use the task information to write a report that shows all deliverables where the deliverable finish date is before the task finish date.
    MSP_WssListItemAssociation

    This view shows all the different associates with risks, issues and deliverables. Here you are going to want to look at the relationship type ID. The relationship type ID tells you if it is a deliverable or a dependency and if it is linked to a task or not. It is also where you can find if a dependency exists.
    MSP_WssRelationshipType

    This table lists the different types. These types refer to risks, issues and deliverables. For deliverables and dependencies, the following types are important:

    Relationship Type ID

    Description

    11 This is a deliverable that is linked to a task.
    12

    This is a dependency on a deliverable that is linked to a task. 

    13

    This is a deliverable for a project. It is not linked to any task within the project.

    14

    This is a dependency on a deliverable for a project. It is not linked to any task within the project.

    There are a set of common queries that user tend to want when creating a report for deliverables. This first query is a simple list of all the deliverables and what project they are associated with:

    SELECT 
    	ProjectName As 'Project Name', 
    	Title As 'Deliverable', 
    	StartDate As 'Start Date', 
    	FinishDate As ' Finish Date'
      FROM 
    	MSP_WssDeliverableToProjectLinks_UserView 
    	Inner Join MSP_EpmProject_UserView 
          	On 	MSP_WssDeliverableToProjectLinks_UserView.ProjectUID =
    MSP_EpmProject_UserView.ProjectUID
    
    

    The following query lists all the projects that have taken dependencies on a deliverable for given project. For the query to work, you need to set ProjectSelect.

    SELECT     
    	DeliverableProj.ProjectName AS SelectedProject,
    DependancyProj.ProjectName AS DependentProject,
    DeliverableLinks.Title, DeliverableLinks.StartDate, DeliverableLinks.FinishDate FROM MSP_EpmProject_UserView AS DeliverableProj INNER JOIN MSP_WssListItemAssociation ON DeliverableProj.ProjectUID =
    MSP_WssListItemAssociation.ProjectUID INNER JOIN MSP_EpmProject_UserView AS DependancyProj ON MSP_WssListItemAssociation.RelatedProjectUID =
    DependancyProj.ProjectUID INNER JOIN MSP_WssDeliverable AS DeliverableLinks ON MSP_WssListItemAssociation.ListItemUID = DeliverableLinks.DeliverableUniqueID WHERE (MSP_WssListItemAssociation.ProjectUID
    <> MSP_WssListItemAssociation.RelatedProjectUID) AND (DeliverableProj.ProjectName = @ProjectSelect)

    This last query lists all the projects that a given project is dependent on. Again, you need to set ProjectSelect for the query to work.

    SELECT     
    	DependancyProj.ProjectName AS SelectedProject,
    DeliverableProj.ProjectName, DeliverableLinks.Title, DeliverableLinks.StartDate, DeliverableLinks.FinishDate FROM MSP_WssListItemAssociation INNER JOIN MSP_EpmProject_UserView AS DependancyProj ON MSP_WssListItemAssociation.RelatedProjectUID = DependancyProj.ProjectUID INNER JOIN MSP_EpmProject_UserView AS DeliverableProj ON MSP_WssListItemAssociation.ProjectUID = DeliverableProj.ProjectUID INNER JOIN MSP_WssDeliverable AS DeliverableLinks ON MSP_WssListItemAssociation.ListItemUID = DeliverableLinks.DeliverableUniqueID WHERE (MSP_WssListItemAssociation.RelatedProjectUID <> MSP_WssListItemAssociation.ProjectUID) AND (DependancyProj.ProjectName = @ProjectSelect)

    To take a look at the last two queries in real reports, check out the Project Give and Get Reports in the Report Pack:

    http://blogs.msdn.com/project/archive/2007/01/30/sql-server-reporting-services-report-pack-for-project-server-2007.aspx

    This should be a good start with creating Deliverable reports. If you come up with some interesting queries for creating Deliverable reports, please share them by posting them as comments!

    Chris Boyd

     

    Tags:

  • Project Programmability and Business Intelligence

    Creating a Task Hierarchy

    • 1 Comments

    The following questions has been asked:

    "[...] is there a way to set up the task hierarchy within a single project?"

    and the answer is YES! To create a hierarchy within a single project, you have to set the outline level for the sub tasks. The below example creates two task, Summary Task and Sub Task. For the Summary Task, we do not set the outline level, we just create it as normal task. The Sub Task is where you set the outline level. In this example we set the outline level to 2:


    Connection conn = new Connection("http://chboyd01/pwa");

    WSProject.Project projWS = (WSProject.Project)conn.GetWebService(Connection.Project);

    Guid sessGuid = Guid.NewGuid();
    Guid jobGuid = Guid.NewGuid();
    Guid taskGuid = Guid.NewGuid();

    Guid projGuid = GetProjectUidFromProjectName("Excel");

    projWS.CheckOutProject(projGuid, sessGuid, "");

    WSProject.ProjectDataSet dsP;

     

    // Create a task with a constraint

     

    dsP = new WSProject.ProjectDataSet();

    WSProject.ProjectDataSet.TaskRow taskRow = dsP.Task.NewTaskRow();

     

    // Set the required fields

    taskRow.PROJ_UID = projGuid;
    taskRow.TASK_UID = taskGuid;
    taskRow.TASK_NAME =
    "Summary Task";

    taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

    dsP.Task.AddTaskRow(taskRow);

    projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

    // Create a second task

    dsP = new WSProject.ProjectDataSet();

     

    taskRow = dsP.Task.NewTaskRow();

    Guid task2Guid = Guid.NewGuid();

    jobGuid = Guid.NewGuid();

    // Set the required fields

    taskRow.PROJ_UID = projGuid;
    taskRow.TASK_UID = task2Guid;
    taskRow.TASK_NAME =
    "Sub Task";

    // Set the start and finish dates

    taskRow.TASK_START_DATE = new DateTime(2007, 01, 31);
    taskRow.TASK_FINISH_DATE =
    new DateTime(2007, 02, 03);

    taskRow.TASK_OUTLINE_LEVEL = 2;

    taskRow.AddPosition = (int)PSLibrary.Task.AddPositionType.Last;

    dsP.Task.AddTaskRow(taskRow);

    projWS.QueueAddToProject(jobGuid, sessGuid, dsP, false);

    PublishProject(projGuid);

    The below screen shot is the result of running the above sample code:

    Chris Boyd

     

    Technorati tags: , , ,
  • Project Programmability and Business Intelligence

    Reading Assignment Enterprise Custom Field Values with VBA

    • 2 Comments

    Hello,

    There has been a number of people asking how to read assignment enterprise custom field values with VBA. In fact, we ran into this issue internally with our dogfood efforts and fixed it in SP1. So, if you need to get/set assignment custom field values, the first step is to download SP1:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=cec3e1e2-d802-4a03-bc78-05c48472559b&displaylang=en

    Once you have SP1 installed, it is fairly easy to read assignment enterprise custom fields. When you read and set task and resource enterprise custom fields, you use the GetField and SetField methods in VBA. To read and set the assignment values you don't use the GetField and SetField, but instead use the name of the enterprise custom field as a property of the assignment.  There are a couple of caveats, however:

    • The field name can't contain spaces in the name
    • When you're writing your code, you won't get auto complete to show you the field name. This is because the property isn't a part of the type library and therefore isn't early bound.  As long as you pass in a valid field name, however, then the code will late bind to it. 

    Here is a short example. Suppose your custom Field name is "ecfName", here is how you would read it:

    For Each T in ActiveProject.Tasks

      If Not (T is Nothing) Then

        For Each A in T.Assignments

          assignCFVal = A.ecfName

        Next A

      End If

    Next T

    Chris Boyd

  • Project Programmability and Business Intelligence

    Update of Project 2010 SDK–Online and Download

    • 0 Comments

    The Project 2010 SDK download and the MSDN online release are both updated. The updates have the same URLs as previous releases:

    New conceptual / how-to topic:

    ·Topic updates for MSDN online, since the last update on March 7, 2011:
    20 conceptual and how-to topics have updates. Most changes are relatively minor; the Change History table at the bottom of each topic shows significant changes.

    • Assn Element
    • ChangeList Elements
    • ChangeList Schema Reference
    • Developing Project Server Workflows
    • How to: Create a Project Server Event Handler and Log an Event
    • How to: Create a Proxy Assembly for WCF Services (SP1 note)
    • How to: Modify the Ribbon in PWA
    • Introduction to the ChangeList Schema and Statusing ChangeXML
    • Introduction to the SetAssignmentWorkData Schema
    • Prerequisites for ASMX-Based Code Samples (SP1 note)
    • Prerequisites for WCF-Based Code Samples (SP1 note)
    • Project 2010 SDK Documentation (overview of the Project 2010 SDK)
    • Project Server 2010 Programming Tasks
    • Project Server Error Codes
    • SetAssignmentWorkData Elements
    • SetAssignmentWorkData Schema Reference
    • Supported Project Fields and Field Information for Statusing ChangeXML (updated the valid change types for the Actual Overtime Work and Remaining Overtime Work fields)
    • Tables of VBA Object Model Changes
    • Walkthrough: Developing PSI Applications Using WCF
    • What's New for Developers in Project 2010 (programmability changes for SP1)

    600 managed code types (classes that include new descriptions for one or more properties, methods, and events) are updated. There are new code samples for the following PSI methods:

    • QueueDeleteProjects
    • ReadResource
    • UpdateStatus
    • ReadProjectStatus
    • SubmitStatusForResource
    • ReadStatusForResource
    • ReadEventHandlerAssociationsForEvent
    • UpdateEventHandlerAssociations
    • CreateEventHandlerAssociations

    New / updated items in the Project 2010 SDK download, which was last updated March 7:

    • Project2010SDK.chm is an HTML Help file that includes the same updated content that is online. In the managed code reference section, 99.8% of the types and members now have descriptions (26,530 out of a total 26,576 topics). That is up from 77.7% at RTM.
    • WINPROJ.DEV.hxs remains unchanged from the March update of VBA Help. There are instructions for replacing the local VBA Help file that was shipped with the Project RTM release.
    • IntelliSense files are updated for the PSI proxy assembly and the Project Server assemblies, to show descriptions of classes and members while programming in Visual Studio. The type and member descriptions have the same updates as in the HTML Help file (and in MSDN online).
    • The Microsoft.Office.Project.Server.Library.dll assembly is updated for distribution with third-party solutions for SP1.
    • Event handler solution: TestProjectEventHandlers.
    • Test application for the Queue System: UsingQueueSystem shows an example of when to wait for the queue, and when you don’t need to wait.
    • ProjTool has a minor update, so the functionality of the Project Details dialog matches the description in Using the ProjTool Test Application.
    • New PSI code samples include complete WCF-based solutions for the following events: ProjectEventReceiver: OnCreating, OnCreated, OnSaved. Other new solutions show the use of the following PSI methods: QueueDeleteProjects, CreateEventHandlerAssociations, UpdateEventHandlerAssociations, ReadEventHandlerAssociationsForEvent, using the ReadResources and ReadResource methods to get the RBS custom field, creating a changeXml parameter for a different resource with the UpdateStatus method, and using SubmitStatusForResource and ReadStatusForResource.
  • Project Programmability and Business Intelligence

    Debugging a Project Server Workflow in Visual Studio 2010

    • 3 Comments

    The How to: Install and Test a Project Server Workflow article in the Project 2010 SDK needs information about how to debug a workflow. Because Visual Studio 2010 can install a workflow solution on the local Project Server computer during development and testing, you can use Visual Studio to attach to a process that the workflow uses.

    After you deploy the workflow project in Visual Studio, on the Debug menu, click Attach to Process. In the Attach to Process dialog box, check Show processes from all users and Show processes in all sessions.

    Following are considerations to choose the correct process:

    • If the workflow creates a project or does another operation that uses one of the Queue methods in the PSI (for example QueueCreateProject), the process uses the Project Server Queue Service. In the Attach to Process dialog box, click the Microsoft.Office.Project.Server.Queuing.exe processes.

      Note:   There is a queue process for the application server and for each Project Web App instance. You can attach to all the queue processes, or check the ULS log for the ID of the queue process, and then convert that into a decimal value. For example, if the Microsoft.Office.Project.Server ID is 0x0FFC in the ULS log, the Microsoft.Office.Project.Server.Queuing.exe process ID is 4092.
    • When you submit or restart the workflow, the workflow runs in a w3wp process. Click one or more of the w3wp.exe processes . You can sometimes determine which w3wp process is involved, and find the process ID as in the previous note. Otherwise, attach to all of the w3wp processes.
    • If the workflow uses an approval process that includes many approvers, it might run under the SharePoint timer process. Click the OWSTIMER.EXE process . This is not common.

    When you attach to the correct process, a breakpoint remains as a solid red dot in the left of the code pane. If you do not attach to the correct process, the breakpoint turns into a hollow red circle with yellow caution indicator, and the tooltip for the breakpoint states, “The breakpoint will not currently be hit. No symbols have been loaded for this document.”

    When you click Attach, Visual Studio is ready to catch a breakpoint that you set in the workflow code.

  • Project Programmability and Business Intelligence

    Project Initiation Phase using InfoPath & Forms Services

    • 1 Comments

    Christophe just passed along some information about a new solution starter on CodePlex:

    Hello,

    A new solution starter that demonstrates how to leverage InfoPath & Forms Services as well Windows Workflow Foundation (hosted by SharePoint) to create your own project initiation phase has been released on CodePlex.

    The project initiation phase is different for every customers and organizations. It typically requires a set of custom attribute to be filled in a web based custom form; and then it needs to go through a custom approval process workflow reviewed by all key decision makers. InfoPath Forms services combined with a SharePoint’s sequential workflow enables you to achieve this business need. This solution starter also demonstrates the added value of deploying Project Server 2007 in a SharePoint Server farm (using InfoPath Forms Services).

    The goal of this solution starter is thus to provide the following two code samples:

    • InfoPath Form with managed code that issues Project Server Interface calls to populate and submit form data
    • SharePoint sequential workflow that leverages the form created earlier to create a custom workflow

    This solution starter requires Project Server 2007, InfoPath and Forms Services 2007, and Visual Studio 2008.

    Step 1 – Fill out and submit Project Initiation Form

    Step 2 – Approve data submitted in Step 1 and create Project in PS 2007

    Resulting data in Project Server 2007

    clip_image001 clip_image002 clip_image003

    This solution starter was created for a presentation I delivered at the 2008 Office Developer Conference.

    If you are aware of any useful tools/solutions for Project and Portfolio Server 2007 and you would like to share them with the community via CodePlex please send me an email.


    About CodePlex

    CodePlex is Microsoft's open source project hosting web site. You can use CodePlex to create new projects to share with the world, join others who have already started their own projects, or use the applications on this site and provide feedback. A word about Microsoft’s role: Microsoft does not control, review, revise, endorse or distribute the third party projects on this site. Microsoft is hosting the CodePlex site solely as a web storage site as a service to the developer community.

    Q&A

    Q: Is the tool supported?

    A: There is no support in terms of CSS/PSS. We expect the support being a CodePlex community effort. Please note that the customization code uses standard supported web service calls available out of the box in EPM2007.

    Q: Is the tool free?

    A: Yes.

    Q: Can I distribute the tool and the source code to customers and partners?

    A: Customers and Partners can use both. Please point them to CodePlex as they have to agree on the license terms

    Q: Can a partner distribute the tool and code as is?

    A: No, but he can point his customer to the website to download it, so he makes sure that the customer agrees with the license terms.

    Q: Can a customer install the customization and use it?

    A: Yes the customer can, but he/she is responsible for testing it and running it.

    Q: Can I suggest changes to it?

    A: Yes, join the CodePlex community or send us an email: epmssdev@microsoft.com

    Q: Will this tool be distributed in other ways (i.e. DVDs)?

    A: No.

    Q: What skills do I need to modify or change the tool?

    A: C#, Project Server Interface, and a good understanding of the EPM 2007 data schema.

    Q: I’m trying to modify the code and do have questions. Who do I ask?

    A: Go to the Discussions forums on CodePlex.

    Q: What are all the EPM projects released on CodePlex?

    A. Check this: http://www.codeplex.com/Project/ProjectDirectory.aspx?ProjectSearchText=epm

    Regards,

    Christophe Fiessinger

  • Project Programmability and Business Intelligence

    Technical Resources on Workflow/Demand Management in Project Server 2010

    • 1 Comments

    Introduction

    This blog entry is designed to try and capture all of the different pieces of information that exists right now regarding workflows in Project Server 2010.  Based on the feedback we are in process of creating a dedicated “Demand Management” resource center on Microsoft TechNet that will became the “one-stop” shop for all your technical and developer resources for Demand Management, including Workflows in Project 2010.

    Technet

    Demand Management in Project Server 2010

    http://technet.microsoft.com/en-us/projectserver/ff899331.aspx

    SDK

    Developing Project Server Workflows:

    http://msdn.microsoft.com/en-us/library/ee767694(v=office.14).aspx

    Out of the Box Sample Workflow Source Code:

    Download the SDK: http://www.microsoft.com/downloads/details.aspx?FamilyID=46007f25-b44e-4aa6-80ff-9c0e75835ad9&displaylang=en and find the source code in the “Samples\Workflow\SampleProposal2” directory

    Sharepoint Office Task Class:

    http://msdn.microsoft.com/en-us/library/microsoft.office.workflow.actions.officetask.aspx

    Using InfoPath Forms in a Workflow:

    http://msdn.microsoft.com/en-us/library/ms573938(v=office.14).aspx

    Blogs:

    Introduction to Demand Management:

    http://blogs.msdn.com/b/project/archive/2009/11/13/project-2010-introducing-demand-management.aspx

    End User level Walkthrough of the Out of the Box Sample Workflow:

    http://blogs.msdn.com/b/project/archive/2010/03/19/video-walkthrough-of-the-out-of-the-box-sample-proposal-workflow.aspx

    How to use the Skip to Stage Feature:

    http://blogs.msdn.com/b/project_programmability/archive/2010/02/10/how-to-use-the-skip-to-stage-feature-in-project-server-2010-workflows.aspx

    Debugging a Project Server Workflow in Visual Studio 2010

    http://blogs.msdn.com/b/project_programmability/archive/2010/07/15/debugging-a-project-server-workflow-in-visual-studio-2010.aspx

    Solution Starters (Open Source Solution Starters)

     Microsoft Project 2010 Solution Starters

    http://code.msdn.microsoft.com/P2010SolutionStarter

    Recorded Videos:

    Demand Management Overview:

    http://www.microsoft.com/showcase/en/US/details/31184ff3-f797-4647-985f-4ccd873d71fb

    Workflow Deep Dive:

    http://www.microsoft.com/showcase/en/US/details/34f2e816-bec5-4a5a-a7f8-b356dac292fc

    Webcasts:

    Demand Management Overview:

    Part 1:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13490

    Part 2:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13493

    Part 3:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13491

    Part 4:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13492

    Workflow Deep Dive:

    Part 1:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13332

    Part 2:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13333

    Tailored Tools for Workflow Creation:

    http://www.microsoft.com/events/series/epm.aspx?tab=Webcasts&seriesid=51&webcastid=13337

    Project Forum:

    http://social.msdn.microsoft.com/Forums/en-US/category/projectserver2010,projectprofessional2010/

    Project Server 2010 Demonstration Virtual Machine Image Download:

    http://www.microsoft.com/downloads/details.aspx?FamilyID=f48eacb9-6ea7-4aca-bc10-d3677ef81a9d&displaylang=en

    Hitchhiker’s Guide to Demand Management (white paper)

    http://technet.microsoft.com/en-us/library/ff973112.aspx

  • Project Programmability and Business Intelligence

    Adding a Project to a Category

    • 3 Comments

    Brian Smith from PSS has passed along this sample that we thought might be helpful:

    The scenario here is that you have a lookup table that shows the categories you want users to select from when creating a project, and then the GUID for the "real" security category is held in the description for the lookup table value.  You make the CF that feeds from the Lookup Table a required Project Level text field.  The Project.Created event fires and the dataset is read - the custom field identified and the GUID of the security category is then used to add the project to the security category.

    No error checking or exception handling is shown - you can do this bit. You would also need to set the categories to the rule "only projects...".  I've hardcoded my lookup table and a reference required to the Microsoft.Office.Project.Server.Library and Events. A Web References to LookupTable, Project, Security and LoginWindows is also required.

    The code will run as the user running the services - so you will either need that account to have PWA permissions or to change to use impersonation.

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Diagnostics;
    using System.Text;
    using Microsoft.Office.Project.Server.Events;
    using Microsoft.Office.Project.Server.Library;

    namespace TestEventHandler
    {

        public class AutoCategory:ProjectEventReceiver
        {

            public override void OnCreated(PSContextInfo contextInfo, ProjectPostEventArgs e)
            {

                // cfGuid holds CF for Project Category
                Guid cfGuid = new Guid("9bbc698f-5c1d-4f8d-a3d0-163006416bf2");

                // ltGuid holds LT for Categories
                Guid ltGuid = new Guid("625bab60-4427-4f0b-941b-9860d1293338");

                // lt_Struct_Uid gets the id for the selected LT value
                Guid lt_Struct_Uid = new Guid("00000000-0000-0000-0000-000000000000");

                // securityCategoryGuid gets the Security Categorty Guid from the Descriptio field in the lookup table
                Guid securityCategoryGuid = new Guid("00000000-0000-0000-0000-000000000000");

                // 32 is used to just get the CF entities from the readProjectEntities
                const int PROJECT_ENTITY_TYPE_PROJECTCUSTOMFIELD = 32;

                Guid SECURITY_CATEGORY_OBJECT_TYPE_PROJECT = new Guid("1771B1C0-6E26-4FB3-A480-C798AB506E82");

                WebSvcLoginWindows.LoginWindows loginWindows = new TestEventHandler.WebSvcLoginWindows.LoginWindows();
                WebSvcProject.Project project = new TestEventHandler.WebSvcProject.Project();
                WebSvcSecurity.Security security = new TestEventHandler.WebSvcSecurity.Security();
                WebSvcLookupTable.LookupTable lookupTable = new TestEventHandler.WebSvcLookupTable.LookupTable();

     

                //login to Project Server - this assumes the event service has a login with permissions

                // Impersonation would be better
                loginWindows.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/LoginWindows.asmx";
                loginWindows.Credentials = CredentialCache.DefaultCredentials;
                loginWindows.Login();

                // Get the dataset
                project.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/Project.asmx";
                project.Credentials = CredentialCache.DefaultCredentials;

                lookupTable.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/LookupTable.asmx";
                lookupTable.Credentials = CredentialCache.DefaultCredentials;

                security.Url = @"https://SERVER_NAME/ProjectServer/_vti_bin/PSI/security.asmx";
                security.Credentials = CredentialCache.DefaultCredentials;

                WebSvcProject.ProjectDataSet dsProjectDataSet = new TestEventHandler.WebSvcProject.ProjectDataSet();

                dsProjectDataSet = project.ReadProjectEntities(e.ProjectGuid, PROJECT_ENTITY_TYPE_PROJECTCUSTOMFIELD, TestEventHandler.WebSvcProject.DataStoreEnum.WorkingStore);

                for (int i = 0; i < dsProjectDataSet.ProjectCustomFields.Count; i++)
                {
                    if (dsProjectDataSet.ProjectCustomFields[i].MD_PROP_UID == cfGuid)
                    {
                        lt_Struct_Uid = dsProjectDataSet.ProjectCustomFields[i].CODE_VALUE;
                    }
                }

                Guid[] arrayLtUid = new Guid[1]{ltGuid};
                WebSvcLookupTable.LookupTableDataSet dsLookupTable = new TestEventHandler.WebSvcLookupTable.LookupTableDataSet();
                dsLookupTable = lookupTable.ReadLookupTablesByUids(arrayLtUid, false, 1033);

                for (int i = 0; i < dsLookupTable.LookupTableTrees.Count; i++)
                {
                    if (dsLookupTable.LookupTableTrees[i].LT_STRUCT_UID == lt_Struct_Uid)
                    {
                        securityCategoryGuid = new Guid(dsLookupTable.LookupTableTrees[i].LT_VALUE_DESC.ToString());
                    }
                }           

    WebSvcSecurity.SecurityCategoriesDataSet dsSecurityCategories
       = new TestEventHandler.WebSvcSecurity.SecurityCategoriesDataSet();

    // Read the existing values for the security category into the dataset
    dsSecurityCategories = security.ReadCategory(securityCategoryGuid);

                // Get a new objects row to put the created project into

                WebSvcSecurity.SecurityCategoriesDataSet.SecurityCategoryObjectsRow dsSecurityCategoryObjectsRow
    = dsSecurityCategories.SecurityCategoryObjects.NewSecurityCategoryObjectsRow();

                //Set the values
                dsSecurityCategoryObjectsRow.WSEC_OBJ_TYPE_UID = SECURITY_CATEGORY_OBJECT_TYPE_PROJECT;
                dsSecurityCategoryObjectsRow.WSEC_CAT_UID = securityCategoryGuid;
                dsSecurityCategoryObjectsRow.WSEC_OBJ_UID = e.ProjectGuid;

                // Add the row to the dataset and then pass to SetCategories to update
                dsSecurityCategories.SecurityCategoryObjects.AddSecurityCategoryObjectsRow(dsSecurityCategoryObjectsRow);

                // Create an EventLog instance and assign its source.
                EventLog myLog = new EventLog();
                myLog.Source = "Project Event Handler";

                // Get information from the event arguments, and

                // write an entry to the Application event log.
                string userName = contextInfo.UserName.ToString();
                string projectName = e.ProjectName.ToString();
                string secCatUid = securityCategoryGuid.ToString();
                int eventId = 3652;
                string logEntry;

     

                logEntry = "User: " + userName +

                        "\nProject: " + projectName +

                        "\nSecurity Category Uid: " + secCatUid;

                    myLog.WriteEntry(logEntry, EventLogEntryType.Information, eventId);

                security.SetCategories(dsSecurityCategories);           

            }
        }
    }

     

  • Project Programmability and Business Intelligence

    Microsoft.Office.Project.Server.Schema

    • 2 Comments

    When working with Project Server Events, you may need to reference Microsoft.Office.Project.Server.Schema. Unfortunately, you will not find it in \Program Files\Microsoft Office Servers\12.0\Bin where you can find other common DLLs for Project Server.  For this DLL, you will need to copy it from the GAC:

    1.      Open Visual Studio Command Prompt

    2.      cd %windir%\assembly\GAC_MSIL\Microsoft.Office.Project.Schema\12.0.0.0*"

    3.      Copy Microsoft.Office.Project.Schema.dll to a directory outside of the GAC

    4.      Go back to Visual Studio and create a reference to Microsoft.Office.Project.Schema.dll from the directory you copied it to

    Just one thing to keep in mind; you may need to copy the DLL from the GAC again if a Project Server update is installed.

    Hope this helps,

    Chris

  • Project Programmability and Business Intelligence

    Visual How To: Creating a Custom Web Parts for Project Server 2007

    • 2 Comments

    We’ve added a “Visual How Tos” section to the online SDK, with the first video:  Creating Custom Web Parts for Project Server 2007.

    Overview  

    A Web Part is a modular unit of information that has a single purpose and is a basic building block of a Web Part Page. Project Web Access uses many Microsoft Office Project Server 2007 Web Parts and can be easily extended with custom Web Parts.

    Web Parts in Windows SharePoint Services 3.0 improve upon earlier versions of Web Part technologies. You can use Windows SharePoint Services 2.0 Web Parts and ASP.NET 2.0 Web Parts. You can also use Web Parts in shared Web Part Page documents in a project workspace or team site. The shared documents are stored and managed on a computer running Windows SharePoint Services that is provisioned by Project Server. This Office Visual How To article shows the creation of a custom Web Part for Project Server 2007 that you can use to display the upcoming tasks for a specified project. The code presented in this article is based on the "No PWA Reference" Web Part sample that is included in the Microsoft Office Project 2007 SDK download.

  • Project Programmability and Business Intelligence

    Adding a Web Reference Using Visual Studio Orcas Beta 2

    • 1 Comments

    Lately I have been playing around with VS Orcas Beta 2; primarily to play around with VSTO support for Project Client. When trying to add a web reference to our web services (PSIs), at first I could not find the option to do it in the VS IDE. After digging around, I figured it out. Here are the steps to adding a web reference to one of the PSI web services in Visual Studio Orcas Beta 2:

    1. Right Click on Service Reference and Select Add Service Reference...

    image

    2. Click the Advanced Button:

    image

    3. Click the Add Web Reference Button:

    image

    This will bring up the familiar web reference UI from Visual Studio 2005 and you can add the web reference just like you did in the past.

    Chris Boyd  

  • Project Programmability and Business Intelligence

    Security in Project Server 2010–What about Custom Permissions?

    • 8 Comments

    SharePoint Server 2010 handles user authentication through claims processing, which is a new feature for SharePoint and Project Server. SharePoint handles both Windows authentication and Forms authentication for Project Server users. For authorization, you can use the ReadResourceAuthorization and SetResourceAuthorization methods in the Resource service of the PSI. Because you probably don’t often change security authorization settings for users, you would normally go to the Manage Users page in Project Web App to select a user and set the global and category permissions.

    The Security business object in Project Server (with programmatic access through the PSI Security service) manages security groups, categories, templates, and the global Project Web App permissions. The Security service can add existing permissions or remove permissions from the sets available for Project Server users. However, the Security service does not have a method for creating a custom permission. For example, if you created a Project Server extension that updates a Siebel CRM system, you might want a custom permission that enabled users to use that extension.

    In Office Project Server 2007, you can create custom global and category permissions by modifying security tables in the Published database. Custom permissions show in the PWA lists of permissions, where Project Server administrators can secure the 3rd-party extension the same way they secure other Project Server features. The Walkthrough: Creating and Using Custom Project Server Permissions article is the only SDK example where an exception is made for changing the Published database. 

    NOTE:  The Project team would like some feedback on the importance of custom permissions. If you need to create custom permissions in Project Server, please respond to this post.

     In Project Server 2010, that process for creating custom permissions still works as it did in Project Server 2007. In future versions of Project Server, no modifications to tables in the Published, Draft, or Archive databases will be supported. Custom permissions and secure links that rely on table modifications still work in Project Server 2010, but that process will be deprecated. As an alternative, you may have to create your own user interface to manage custom permissions, or use claims augmentation in a custom application. For more information, see Claims Provider.

    Thanks,
    --Jim

    For more information about Project Server security, including a discussion of global and category permissions, see the Project Server Security Primer in the Project Server 2007 SDK and Security and protection for Project Server 2010 in TechNet.

  • Project Programmability and Business Intelligence

    Getting a Project GUID on the Cheap

    • 1 Comments

    Many people have requested for a complementary method to GetProjectNameFromProjectUid where they can pass in a project name and it returns the project's GUID. Unfortunately it did not make it into the Project API. Since it has been requested many times, I figured that it would be useful to post a method, GetProjectUidFromProjectName, which did just that:

    public static Guid GetProjectUidFromProjectName(string projectName)
    {
      Guid projectGUID;

      WSProject.ProjectDataSet readProjDs = projWS.ReadProjectStatus(
                                                                                                Guid.Empty,
                                                                                                WSProject.DataStoreEnum.WorkingStore, 
                                                                                                projectName, 
                                                                                                0
                                                                                                         );

      if (readProjDs.Project.Rows.Count == 1)
      {
        projectGUID = new Guid(readProjDs.Project[0].PROJ_UID.ToString());
      }
      else
      {
        throw new Exception("No Project by the name: " + projectName + " Found");
      }

      return projectGUID;

    }  

    First thing to note is that projWS is defined elsewhere and it is a connection to the Project Web Service. See my earlier post on Getting Started with the PSI on how to make the connection to the Project Web Service.

    To get the GUID we are going to use the ReadProjectStatus method, as it is the cheapest call to make to get the project's GUID. As you will see, this method takes 4 parameters. The first parameter is the project GUID. In this case, we pass in an empty GUID because that is what we are looking for. Passing in an empty GUID tells Project Server not to search for a project by the GUID.  

    The second parameter is the store to get the project GUID from. Here we have the option of getting the GUID from the working, published or archived store. In this example, I am getting it from the working store, since I want to get the GUID for projects that are actively being worked on and may or may not have been published. Note that this will also get projects that have been published, since they exist in both stores with the same GUID. You may want to change the store based on your requirements.

    The third parameter is the name of the project. This is passed into our GetProjectUidFromProjectName method.

    The last parameter is the type of project. There a number of different project types:

    http://msdn2.microsoft.com/en-us/library/microsoft.office.project.server.library.project.projecttype.aspx

    In most cases 0, which represents standard projects, will be the correct project type.

    The ReadProjectStatus returns a project dataset. If the number of rows returned for the project table is equal to 1, than we have found a project with the given name and we can return the GUID for the project. If the number of rows is not equal to one, than no project by the name was found and we throw an exception.

    Hope this helps,

    Chris Boyd

  • Project Programmability and Business Intelligence

    Does your DEMO laptop with Intel Core i3/i5/i7 CPU bluescreens?

    • 0 Comments

    Thanks to my friend Hans Bellen from UMT and the Microsoft Virtualization Team – we have the final solution for your issues:

    Symptoms:

    Running Windows 2008 R2 w/ Hyper-V on Core i3/i5/i7 CPU and performance graphic card with WDDM driver installed. After Hyper-v is started the machine bluescreens.

    Resolution:

    1. Disable the Intel Turbo Boost in the BIOS or in the Windows 2008R2 if you are dual-booting or the option is not available in the BIOS. To disable the Turbo Boost in Windows Server 2008 R2 – open Device Manager, locate Intel(R) Turbo Boost Technology Driver, disable it.
    2. Get the Windows 2008 R2 SP1 – now available in Beta here http://technet.microsoft.com/en-us/evalcenter/ff183870.aspx

    10/20/10 – UPDATE

    I just have been setting up the Lenovo T410 for the Hands-on Lab for our upcoming Barcelona event and here is some learning:

    • After native nVidia driver from Lenovo site was installed the machine constantly blue screened with Hyper-v enabled even with the “Intel(R) Turbo Boost Technology Driver” disabled
    • Installing SP1 did fix the problem and I’m running my VM and multi-monitor config successfully now
    • Small trick I learned – once you install the nVidia driver you are not able to see anything on the screen or the machine blue screens (nvlddmkm.sys) when booted - to recover – just disable the virtualization in the BIOS and reboot. As Hypervisor service will not run the machine will behave ok and it gives you chance to install SP1 Smile
  • Project Programmability and Business Intelligence

    How to use the “Skip to Stage” Feature in Project Server 2010 Workflows

    • 5 Comments

    Introduction

    The skip to stage feature is designed to allow administrators the ability to restart a workflow and have it attempt to skip along the workflow until it reaches a particular stage. A common scenario for this functionality is when a project has progressed to a specific point in a workflow, but needs to be pushed back to a previous stage due to any number of reasons, such as, a new stage was inserted that needs to be addressed, certain fields need to be changed that are exposed only in previous stages, etc.

    Project Server workflows, like SharePoint workflows, must always be executed linearly. They cannot begin execution at random locations within a workflow. Neither can they “jump” from one point to another point, unless coded to do so within the workflow. The skip to stage functionality cannot circumvent this limitation. As such, the issue with restarting a workflow and attempting to push it to a particular point is that any activities which “stopped” the workflow before will continue to do so again. For Example, activities such as SetProjectStage, OnProjectSubmit, OnProjectCommit, the officeTask, ect, will still cause the workflow to dehydrate and give control back to the user. Although for the SetProjectStage activity we have done some extra work and put logic inside it so that it can be skipped, so long as there are no required fields left in the stage

    Therefore, to fully work with the skip to stage functionality you will need to wrap activities within “if statements”. When an administrator restarts a workflow and chooses to skip to a certain stage, we pass into the workflow two properties. The first property indicates that a skip stage command has been sent, and the second property contains the stage Guid that the workflow should stop at. Our SetProjectStage activity reads these two variables and skips if the first variable is set to true, and if the current stage is not the stage that is set in the second property. However, it won’t skip if there are required fields in the stage. So you will need to mimic this behavior around your other activities. You should wrap all of the activities between the SetProjectStage activities (not including the SetProjectStage activity) with an ifElseActivity statement that checks the first Property.

    Customizing Workflows in Visual Studio to work with skip to stage

    To make any workflow work correctly with the skip to stage functionality an “if statement” should be placed around all of the activities between each of the SetProjectStages. The key example of when this would be necessary is for the office task activities.

    Screen shot of example workflow:

    clip_image003

    In the above example the “ifElseActivity1” is used to bypass the leadApproval sequence activity, which contains all of our approval activities.

    As you can see from the above screen shot, it is the “if statement” that we need to figure out how to code. In order to do so, we need to be aware of the two properties that are passed into the workflow during a skip to stage event:

    WorkflowContext.SkipToStage : Boolean : If true, a skip to stage functionality has been requested

    WorkflowContext.StageUid : Guid : Guid of the stage the workflow should skip to

    Steps for creating the workflow:

    1. Insert and set the properties of a SetProjectStage activity

    · You will need to set the “AlwaysWait” property to True in order for the Skip to Stage scenario to properly work.

    · If you do not set the Always wait property to true the workflow may not be able to skip to and stop at previous stages.

    clip_image004[9]

    2. Insert an IfElseActivity

    3. Have the activity check the “projectSequence1.WorkflowContext.SkipToStage” variable.

    · If variable is set to false, execute all activities

    · Else, bypass

    clip_image006

    clip_image007

    The WorkflowContext.StageUid is not needed for the “If Statement” but is there in case you wish to check what stage the user is trying to skip to.

    *The complete above example is found in the attached Visual Studio solution.*

    Administration: Initiating the Skip to Stage feature

    To attempt to force a project to skip to a particular stage, do the following within Project Server.

    1. Log into Project Server as an Administrator

    2. Go to Server Setting

    clip_image008[4]

    3. Click on “Change or Restart Workflows”

    clip_image009[7]

    4. In the top drop down, select the EPT that the project(s) that you would like to restart and skip to a stage belong to.

    5. Select the project(s) which you would like restart and skip to stage from the left panel and add them to the right panel.

    clip_image011

    6. Check the “Restart current workflow for the selected projects” option

    clip_image012[4]

    a. Alternatively you can also select the “Associate projects with a new Enterprise Project Type:” option. If you select an Enterprise Project Type that has a workflow associated with it, you can then select which stage in that workflow the project(s) should attempt to skip to.

    7. Next select which stage the project(s) should attempt to skip to

    a. Skip until the current workflow stage

    i. Selecting this option will tell the projects to attempt to skip until they reach the stage that the project(s) are in currently

    b. Skip to a particular workflow stage & then selecting a particular stage

    i. Selecting this option will tell the projects to attempt to skip until they reach the stage that has been selected

    ii. If the selected stage does not exist, the workflow will stop at the very first opportunity.

    8. Press OK

    9. The project restart jobs will be sent to the queue, and the projects will attempt to restart and skip.

    Skip to Stage Example

    Expected behavior of the skip to stage can be summed up by the following example.

    · A workflow has 3 stages

    · All stages are marked as “AlwaysWait”

    · Project is on Stage 2

    · Stage 1’s required custom fields are filled out

    · Stage 2’s required custom fields are not filled out

    · Stage 3’s required custom fields are not filled out

    Administrator will go and:

    o Restart Skip to current stage

    § This will make the workflow restart and stop at stage 2

    o Restart Skip to stage 1 (trying to make the workflow stop on a stage where all of the require custom fields are filled out)

    § This will make the workflow stop at stage 1 and wait for submit

    o Restart Skip to stage 3 (trying to make it jump over stage 2 even though its required custom fields are not yet filled out)

    § Workflow will stop at stage 2

    § Workflow will not be able to skip stage2 if it has required fields.

    § If you really want to skip it, you need wrap the SetProjectStage as well in an if/else skip condition, which checks the SkipToStage variable and the StageUid variable.

    o Restart Skip to stage 5 (trying to make the workflow stop on a stage that does not exist)

    § Workflow will stop at stage 1. This is because of the combination of “Destination stage” doesn’t exist & current stage=”Always wait”.

    Conclusion

    This feature has been designed and created to address the majority of our customer needs when it comes to being able to skip between stages. In this blog we reviewed there are two steps to use this feature. The first is to correctly develop your workflows to be able to skip over the activities that are between the SetProjectStage activities. This is done by wrapping the activities within an ifElse activity. And the second stage is to restart the workflows and select the stage the project should attempt to skip to. This is done with Project Server --> Server Settings --> Change or Restart Workflows.

    If you have any additional questions please feel free to post comments, and I will follow up accordingly.

Page 2 of 11 (255 items) 12345»