Table of Contents

Migration Reference

This page provides the technical reference for what each migration script migrates out-of-the-box, and how to extend them via configuration.

For the procedural steps that wrap these scripts, see Migration Process.

Project Online

Exporting data

The export script (ExportAllProjects.ps1) does not need to be modified, but its -ProjectFilter accepts OData expressions to limit the export.

OData operators

Operator Syntax
Equals eq
Not equals ne
Greater than gt
Greater than or equal to ge
Less than lt
Less than or equal to le

Examples

Filter value Syntax
Text EnterpriseProjectTypeName eq 'Major Project'
Numbers ProjectFixedCost gt 0
Guids EnterpriseProjectTypeId eq guid'7473ef8c-9f25-e911-afb0-00155da06b17'
Booleans ProjectEnterpriseFeatures eq true
Date ProjectStartDate gt datetime'2024-09-01T00:00:00Z'

The Project Online OData feed can be browsed at:

https://<tenantname>.sharepoint.com/sites/pwa/_api/ProjectData

Resources

OOTB script

.MPP Table Altus Table
Resource Entry sensei_bookableresource
.MPP Field Altus Field Details Example
Name sensei_name First name, surname Lucius Fox
User Logon Account sensei_user First name, surname Lucius Fox
Max. Units sensei_targetutilization Default value set 100
Type sensei_resourcetype Default value set Named
Role sensei_primaryrole Default value set Unclassified
Calendar GUID sensei_enterprisecalendar Default value set Default Calendar

Extending ImportResources.ps1

The script can be extended to migrate the following field types:

Project Online type Dataverse type Sub-type
Cost Currency
Date (date only) Date and time Date only
Date (date and time) Date and time Date and time
Duration Whole number Duration
Flag Choice Yes/no
Number (whole) Whole number
Number (decimal) Decimal
Text (single line) Single line of text Text
Lookup (single select) Lookup Text
Lookup (multi select) Lookup (many-to-many) Text

Only the following parts of each block need to be updated:

Attribute Details
Project Online field Display name as it appears in Project Online.
Altus field Logical name of the Altus field.
Default.ps1 reference Alias defined in Default.ps1 for lookup tables and choices.
Additional Altus variables Relationship name, related table collection name, related table primary key (multi-select only).
Code blocks
# Cost
$costValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Cost Field'
if ($costValue) { $resourceBody['ce_resourceexamplecostfield'] = ($costValue -as [decimal]) }

# Date (date only and date/time both use this pattern)
$dateValue = Get-ReportingCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Date Field'
if ($dateValue) {
    $resourceBody['ce_resourceexampledatefield'] = ($dateValue -as [datetime]).ToString("yyyy-MM-dd")
}

# Duration
$durationValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Duration Field'
if ($durationValue) {
    $resourceBody['ce_resourceexampledurationfield'] = [int][double]$durationValue
}

# Flag → Flag
$cfValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Flag Field'
if ($cfValue) {
    $ynValue = ($cfValue -eq 'true')   # must be $true / $false, not 1 / 0
    $resourceBody['ce_resourceexampleflagfield'] = $ynValue
}

# Lookup → Flag
$cfValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Choice Field'
if ($cfValue) {
    $ynValue = ($cfValue -eq 'Yes')
    $resourceBody['ce_resourceexampleflagfield2'] = $ynValue
}

# Number (whole or decimal)
$numberValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example Number Field'
if ($numberValue) { $resourceBody['ce_resourceexamplenumberfield'] = [int][double]$numberValue }

# Text (single line)
$textValue = Get-ResourceCustomFieldTextValue -ProjectResource $ProjectResource `
    -CustomFieldName 'Resource Example text field'
if ($textValue) { $resourceBody['ce_resourceexampletextfield'] = [string]$textValue }

# Lookup → Choice
Set-ResourceChoiceField -ResourceBody $resourceBody -ProjectResource $ProjectResource `
    -POLCustomFieldName 'Resource Example Choice Field' `
    -ChoiceName 'choice_YesNo' `
    -DataverseFieldName 'ce_resourceexamplechoicefield'

# Lookup (single select)
Set-ResourceLookupField -ResourceBody $resourceBody -ProjectResource $ProjectResource `
    -POLCustomFieldName 'Resource Example Lookup Field' `
    -LookupName 'lookup_EmploymentStatus' `
    -DataverseFieldName 'ce_ResourceExampleLookupField'

# Lookup (multi select / many-to-many)
Set-ResourceManyToManyRelationship -ResourceBody $resourceBody -ProjectResource $ProjectResource `
    -POLCustomFieldName 'Resource Example Multiselect Lookup Field' `
    -LookupName 'lookup_MultiValueTable' `
    -RelationshipName 'ce_sensei_bookableresource_ce_ExampleMultiSelectLookup_ce_ExampleMultiSelectLookup' `
    -RelatedTableCollectionName 'ce_examplemultiselectlookups' `
    -RelatedTablePrimaryKey 'ce_examplemultiselectlookupid'
Note

The -DataverseFieldName argument is case-sensitive for the lookup helpers.

Projects

OOTB script

.MPP Table Altus Table
Task Entry (Task Level 0) sensei_project
.MPP Field Altus Field Details Example
Task Name sensei_name Where TaskID = 0 Adelaide Fitness Project
N/A sensei_projecttype Default value set Major Project
N/A sensei_externalprojectid Set the GUID = Project Online GUID ProjectDesktop_d14bae12-39b3-e911-b07b-00155d9c3f18

Extending ImportProjects.ps1

The supported field types are identical to those listed for resources. The block patterns are also identical, but use the project helpers:

Resource helper Project helper
Get-ResourceCustomFieldTextValue Get-ReportingCustomFieldTextValue
Set-ResourceChoiceField Set-ProjectChoiceField
Set-ResourceLookupField Set-ProjectLookupField
Set-ResourceManyToManyRelationship Set-ProjectManyToManyRelationship
$resourceBody / $ProjectResource $Project / $ReportingProject

Example (single-select lookup):

Set-ProjectLookupField -ProjectBody $Project -ReportingProject $ReportingProject `
    -POLCustomFieldName 'Example Lookup Field' `
    -LookupName 'lookup_TeamName' `
    -DataverseFieldName 'ce_ExampleLookupField'

Tasks

OOTB script

.MPP Table Altus Table
Task Entry sensei_task
.MPP Field Altus Field Example
Task Name Name Identify Goals and Objectives
Resource Names Assigned To Project Manager
Start Start 2-12-19
Finish Finish 6-12-19
% Complete Percent Complete 25%
Work Effort (Hours) 40
Remaining Work Effort Remaining (Hours) 30
Actual Work Effort Completed (Hours) 10
Duration Duration (Days) 5 days
Type Task Type Fixed Units
Task Mode Manually Schedule Yes
Notes Notes Goals were discussed
Deadline Due Date 6-12-19
Summary Summary No
Milestone Milestone No
Locked Locked No

Mapping of custom fields

There is no script block to update for tasks. The end-to-end process is:

  1. Create the task custom field in Altus.
  2. Choose an MS Project local field (e.g. Date4) and map it to the Altus task custom field.
  3. Run the Set-CustomFieldMapping.ps1 script to map the Project Online enterprise task custom field to the Project Desktop local field.

The local fields available in MS Project Desktop are limited (see Migration Process § 7 for the exact counts and the local fields reserved by Altus for Project).

Note

Cost and Duration custom task fields are not currently supported in the Altus task scheduler.

Lookup tables

LookupTablesToImport.ps1 is configured per source CSV with the following attributes:

Attribute Details
SourceFile CSV exported from ExportLookupTableData.ps1.
MapAsHierarchy $false for flat tables; $true for self-referential hierarchical tables.
TableLogicalName Dataverse table logical (singular) name.
TableCollectionName Dataverse table collection (plural) name.
NameField Dataverse logical name of the Name field.
DescriptionField (Optional) Dataverse logical name of the Description field.
PrevLevelLookupField (Hierarchical only) Self-referential lookup field.

Examples:

# Flat
@{
    SourceFile     = "LookupTable_Employment Status.csv"
    MapAsHierarchy = $false
    DataverseTable = @{
        TableLogicalName    = "ce_employmentstatus"
        TableCollectionName = "ce_employmentstatuses"
        NameField           = "ce_name"
        DescriptionField    = "ce_description"
    }
}

# Hierarchical
@{
    SourceFile     = "LookupTable_Skills.csv"
    MapAsHierarchy = $true
    DataverseTable = @{
        TableLogicalName     = "ce_skills"
        TableCollectionName  = "ce_skillses"
        NameField            = "ce_name"
        DescriptionField     = "ce_description"
        PrevLevelLookupField = "ce_parent"
    }
}

Cost rates

MS Project Altus
Resource Sheet Bookable Resources
Cost Rate Table A Bookable Resource > Rates
MS Project field Altus display Altus internal
Standard Rate Rate (Hourly) sensei_rate
Effective Date Effective Date sensei_effectivedate

The publish script also migrates time-phased rates. There is no mechanism to extend this mapping.

Baselines

Fields below are stored on sensei_taskbaseline:

MS Project field Altus display Altus internal
Baseline Start Baseline Start sensei_taskstart
Baseline Finish Baseline Finish sensei_taskfinish
Baseline Work Baseline Effort sensei_effort
Baseline Duration Baseline Duration sensei_duration

All 11 Project Online baselines (05 protected, 610 unprotected) can be migrated by re-running Publish-MPPsToAltus.ps1 with the relevant -BaselineNumber value:

.\Publish-MPPsToAltus.ps1 -BaselineNumber 0  -IsReportable $true
.\Publish-MPPsToAltus.ps1 -BaselineNumber 1  -IsReportable $true
# ...
.\Publish-MPPsToAltus.ps1 -BaselineNumber 10 -IsReportable $true

-IsReportable $true flags the baseline as the reportable baseline in Altus.

SharePoint Online

Risks

OOTB script

SharePoint List Altus Table
Risks sensei_risk
SharePoint field Altus field Example
Title sensei_name Requirements Not Clearly Defined
Description sensei_description Project requirements are incomplete or ambiguous…
DueDate sensei_duedate 30/04/2026 0:00
Status statuscode (1) Active
Category sensei_category (2) Category2
Probability sensei_likelihood 50%
Impact sensei_consequence 5
Exposure sensei_riskscore 2.5
Cost sensei_cost $10,000.00
Mitigation_x0020_plan sensei_mitigationplan Conduct workshops with stakeholders…
Contingency_x0020_plan sensei_contingencyplan Rebaseline scope and timeline…
Trigger_x0020_Description sensei_triggerdescription When the due date is lapsed…
Trigger sensei_trigger Date
Owner sensei_riskowner John Price
AssignedTo sensei_assignedto Marc Soester

Modified script (export.config.json)

Each custom field is described by a JSON block. Only the highlighted attributes need to change:

Attribute Details
spFieldInternalName SharePoint internal name.
entityAttribute Logical name of the Altus column.
type SharePoint type (see below).
choiceMap (Choice only) SharePoint label → Altus option set value (e.g. 955000000).
lookupEntity (Lookup only) Logical name of the related Altus table.
Code blocks
// Text
{ "_fielddetails": "Single line of Text",
  "spFieldInternalName": "ExampleTextField",
  "entityAttribute":     "ce_examplesptextfield",
  "type": "Text" }

// Date & Time
{ "_fielddetails": "Date and Time",
  "spFieldInternalName": "ExampleDateAndTimeField",
  "entityAttribute":     "ce_examplespdateandtimefield",
  "type": "DateTime" }

// Date Only
{ "_fielddetails": "Date Only",
  "spFieldInternalName": "ExampleDateOnlyField",
  "entityAttribute":     "ce_examplespdateonlyfield",
  "type": "DateOnly" }

// Decimal
{ "_fielddetails": "Decimal",
  "spFieldInternalName": "ExampleDecimalField",
  "entityAttribute":     "ce_examplespdecimalfield",
  "type": "Decimal",
  "divider": 2 }

// Whole number
{ "_fielddetails": "Whole Number",
  "spFieldInternalName": "ExampleNumberField",
  "entityAttribute":     "ce_examplespnumberfield",
  "type": "Number" }

// Lookup
{ "_fielddetails": "Lookup",
  "spFieldInternalName": "ExampleLookupField",
  "entityAttribute":     "ce_examplesplookupdecisioncategory",
  "type":         "Lookup",
  "lookupEntity": "DecisionCategory" }

// Money
{ "_fielddetails": "Money",
  "spFieldInternalName": "ExampleMoneyField",
  "entityAttribute":     "ce_examplespmoneyfield",
  "type": "Money" }

// Choice (OptionSet)
{ "_fielddetails": "OptionSet",
  "spFieldInternalName": "ExampleOptionSetField",
  "entityAttribute":     "ce_examplespoptionsetfield",
  "type": "OptionSet",
  "choiceMap": {
    "Resource":              955000000,
    "Scope":                 955000001,
    "Schedule":              955000002,
    "Technology":            955000003,
    "Other":                 955000004,
    "Business Process":      955000005,
    "Vendor":                955000006,
    "Management Escalation": 955000007
  }
}

// Yes/No (Boolean)
{ "_fielddetails": "Flag (Boolean)",
  "spFieldInternalName": "ExampleBooleanField",
  "entityAttribute":     "ce_examplespbooleanfield",
  "type": "Bool" }

Issues

OOTB script

SharePoint List Altus Table
Issues sensei_issue
SharePoint field Altus field Example
Title sensei_name Resource Overallocation
Discussion sensei_description Key developer assigned to multiple projects causing delays.
DueDate sensei_duedate 24/04/2026 00:00
Status statuscode (1) Active
Category sensei_category (3) Category3
Priority sensei_priority (2) Medium
AssignedTo sensei_assignedto John Price
Cost_x0020_Impact sensei_costimpact $10,000.00
Resolution sensei_resolution Rebalance workload and secure additional support.

Modified script

Identical to Risks – Modified script. Reuse the same JSON blocks.

Custom lists

Each custom list entry in export.config.json requires:

Attribute Details
spListTitle Title of the SharePoint list as shown in List Settings.
entityLogicalName Logical name of the Altus table.
projectLookupAttribute Lookup field on the Altus table that points to the project.
projectLookupEntityLogicalName Logical name of the project entity (typically ce_sensei_project).
projectLookupTextSource Source for the lookup text (e.g. Web.Title).
backlinkAttribute Attribute that stores the source SharePoint URL.
columnMap Array of field mappings (same structure as Risks/Issues).

Example:

{
  "spListTitle":                    "Actions",
  "entityLogicalName":              "ce_action",
  "projectLookupAttribute":         "ce_sensei_project",
  "projectLookupEntityLogicalName": "ce_sensei_project",
  "projectLookupTextSource":        "Web.Title",
  "backlinkAttribute":              "sensei_sourceitemurl",
  "columnMap": [
    { "spFieldInternalName": "Title",       "entityAttribute": "ce_name",        "type": "Text" },
    { "spFieldInternalName": "Description", "entityAttribute": "ce_description", "type": "Text" }
  ]
}

Documents

The document export script can be tuned with the following parameters:

Parameter Default What it controls
-ExcludeVersionHistory $true Set $false to include the full version history.
-DetailedMetadata $false Set $true to export all document metadata.
-ExcludeLibraries "Style Library,Preservation Hold Library,Form Templates,Recycle Bin,Site Assets" Comma-separated list of libraries to skip. Remove an entry to include that library.
-ExcludeFilePatterns @("*.aspx") File-name patterns to skip. Add patterns to skip more types.
-IncludeRootWeb (switch) Include the root web in the export.