Blog Post

Project Support Blog
4 MIN READ

Project Online: CSOM and REST samples showing task indent and insert

DeletedBrianSmith's avatar
DeletedBrianSmith
Brass Contributor
Mar 06, 2019
First published on MSDN on Jun 10, 2016
Skipping back to Project Online for a brief interlude – I was working on a case where the requirement was to create summary tasks and sub task relationships in a plan using the REST API.  I started with the samples out on GitHub – and used the .NET samples first just to get my head around the syntax – then applied the same thing to the REST samples.  The samples can be found here:

  • https://github.com/OfficeDev/O365-Project-Online-.Net-Samples

  • https://github.com/OfficeDev/O365-Project-Online-REST-Samples


In the example just a single task is created (createprojects.cs and createprojects.ps1) – and for my practice I wanted to create a structure something like this:
Summary Task

Sub Task

Another Task

A task inserted in here

Another Task

The additional parameters needed to achieve this are ParentId – which creates a task indented under its ‘Parent’ – which therefore becomes a summary and AddAfterId – which allows you to set the position of the new task after an existing one.  Obviously you need to get the IDs of the tasks in question – and this is the GUID that represents the task – and not the ID you may see in Project (1,2,3 etc.).  In my case I’m doing this all in one place – so I have all the GUIDs – your scenario may ned you to read the project and get the IDs.

For the .NET example I used an array of GUIDs and just duplicated the TaskCreationInfomation sections in CreateProjects.cs and set the ParentId for the second task – and then set the final task to insert after task 3 with AddAfterId.  So my snippet of code looked like this with the interesting parts highlighted:


csom.DraftProject draft = project.CheckOut();
Guid[] taskId = new Guid[5];
taskId[0] = Guid.NewGuid();
taskId[1] = Guid.NewGuid();
taskId[2] = Guid.NewGuid();
taskId[3] = Guid.NewGuid();
taskId[4] = Guid.NewGuid();
csom.Task task0 = draft.Tasks.Add(new csom.TaskCreationInformation()
{
Id = taskId[0],
Name = "Summary " + taskName,
IsManual = false,
Start = project.StartDate.AddDays(1),
Duration = "5d"
});

csom.Task task1 = draft.Tasks.Add(new csom.TaskCreationInformation()
{
Id = taskId[1],
Name = "sub " + taskName + " 1",
IsManual = false,
Start = project.StartDate.AddDays(1),
Duration = "4d",
ParentId = taskId[0]

});
csom.Task task2 = draft.Tasks.Add(new csom.TaskCreationInformation()
{
Id = taskId[2],
Name = taskName  + " 2",
IsManual = false,
Start = project.StartDate.AddDays(1),
Duration = "3d"
});
csom.Task task3 = draft.Tasks.Add(new csom.TaskCreationInformation()
{
Id = taskId[3],
Name = taskName + " 3",
IsManual = false,
Start = project.StartDate.AddDays(1),
Duration = "2d"
});
csom.Task task4 = draft.Tasks.Add(new csom.TaskCreationInformation()
{
Id = taskId[4],
Name = "Inserted " + taskName + " 4",
IsManual = false,
Start = project.StartDate.AddDays(1),
Duration = "1d",
AddAfterId = taskId[2]
});

draft.Update();

The created plan looked like this:



The REST example is pretty much the same – I used the existing CreateProjects.ps1 and duplicated the REST request and POST sections for each of my tasks.  I did find that unless the POST that creates the task with the task ID had completed – and gone through the queue (The aptly named Project Update from PSI job…) – that I’d get a 403 error thrown – so if just running through the example best to use PowerShell ISE and run each section separately.  If coding for real then you’d need to check the queue.

My REST example code:
# Task parameters as JSON payload
$taskid0 = [Guid]::NewGuid()
$body = "{
'parameters': {
'Id': '$taskid0',
'Name': 'Summary_Task_$taskid0',
'Notes': 'Created from PowerShell using REST API',
'Start': '2016-01-04T08:00:00',
'Duration': '5d'
}
}"

# ReST request to create a task
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add" $body

# Task parameters as JSON payload
$taskid1 = [Guid]::NewGuid()
$body = "{
'parameters': {
'Id': '$taskid1',
'Name': 'Task_$taskid1',
'Notes': 'Created from PowerShell using REST API',
'Start': '2016-01-04T08:00:00',
'Duration': '5d',
'ParentId': '$taskid0'
}
}"

# ReST request to create a task
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add" $body

# Task parameters as JSON payload
$taskid2 = [Guid]::NewGuid()
$body = "{
'parameters': {
'Id': '$taskid2',
'Name': 'Task_$taskid2',
'Notes': 'Created from PowerShell using REST API',
'Start': '2016-01-04T08:00:00',
'Duration': '5d'
}
}"

# ReST request to create a task
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add" $body

# Task parameters as JSON payload
$taskid3 = [Guid]::NewGuid()
$body = "{
'parameters': {
'Id': '$taskid3',
'Name': 'Task_$taskid3',
'Notes': 'Created from PowerShell using REST API',
'Start': '2016-01-04T08:00:00',
'Duration': '5d'
}
}"

# ReST request to create a task
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add" $body

# Task parameters as JSON payload
$taskid4 = [Guid]::NewGuid()
$body = "{
'parameters': {
'Id': '$taskid4',
'Name': 'Insert_Task_$taskid4',
'Notes': 'Created from PowerShell using REST API',
'Start': '2016-01-04T08:00:00',
'Duration': '5d',
'AddAfterId': '$taskid2'
}
}"

# ReST request to create a task
Post-ReSTRequest $SiteUrl "ProjectServer/Projects('$projectid')/Draft/Tasks/Add" $body

And the resulting plan:



As mentioned – these are just snippets but you should be able to see where you could use these in createprojects.cs from the .NET samples and createproject.ps1 from the REST samples.  Also I did find a couple of typos in the REST sample which should be getting fixed – lines 11 and 12 should reference $SiteUrl and not $siteUrl – and the POST to add tasks (line 41) should be Draft/Tasks and not just Tasks.  You will also obviously need to set your own Site Url – this is set in pwaInstanceUrl in CreateUpdateProjectSample.cs in the .NET samples, and for the REST samples update $SiteUrl in createproject.ps1 and set your user account in ReST.ps1.

Very basic stuff – and forgive my sloppy duplication of code but hopefully it will help someone understand ParentId and AddAfterId.
Published Mar 06, 2019
Version 1.0

1 Comment