I am working on a script, which shall update Enterprise Custom Fields and Lookup Tables for Project Server 2013, using PSI. The script gets the settings from XMLfiles which were exported from one system and then updates the settings on another system.
The procedure is the following: The skript gets the current LookupTableDataSet from the target system. It then adds, modifies or deletes lookup tables, entries and masks on that dataset. Builtin lookup tables were not modified in any way. Finally it passes the modified dataset to the UpdateLookupTables method to update the target system.
Problem: The target system keeps returning an "LookupTableAlreadyExists" error. It does this for all lookup tables that have been modified or not changed. Lookup tables that were deleted or added to not throw this error.
Here is the code:
$defaultLookupsEN = @("Cost Type", "Department", "Health", "RBS", "Relative Importance", "Project Impact")
function updateLookupTables($dataset) {
$importPath = "$inXMLPath\LookupTables.xml"
$lookupTablesXML = Import-Clixml $importPath
$existingLookupTableNames = $dataset.LookupTables.Rows.LT_NAME
$existingLookupTablesFullData = $dataset
$existingTableIDs = $dataset.LookupTables.Rows.LT_UID
foreach ($lookupTable in $lookupTablesXML) {
if ($existingLookupTablesFullData.LookupTables.LT_UID.Contains($lookupTable.LT_UID)) {
# if source table already exists on target system, update existing table
# Do not update built-in lookup tables
if($lcid -eq 1031 -and $defaultLookupsDE.Contains($lookupTable.LT_NAME)){
continue;
}
if($lcid -eq 1033 -and $defaultLookupsEN.Contains($lookupTable.LT_NAME)){
continue;
}
# Get current lookup table by UID
$lookupRow = $existingLookupTablesFullData.LookupTables.Rows | ? {$_.LT_UID -eq $lookupTable.LT_UID}
#add lookup values from xml
$lookupRow.LT_NAME = [string] $lookupTable.LT_NAME
$lookupRow.LT_SORT_ORDER_ENUM = [int] $lookupTable.LT_SORT_ORDER_ENUM
$lookupRow.LT_PRIMARY_LCID = [int] $lookupTable.LT_PRIMARY_LCID
$lookupRow.LT_FILL_ALL_LEVELS = [boolean] $lookupTable.LT_FILL_ALL_LEVELS
} else {
# if source table does not exists on target system, create new table
# Do not update built in lookup tables
if($lcid -eq 1031 -and $defaultLookupsDE.Contains($lookupTable.LT_NAME)){
continue;
}
if($lcid -eq 1033 -and $defaultLookupsEN.Contains($lookupTable.LT_NAME)){
continue;
}
$lookupRow = $existingLookupTablesFullData.LookupTables.NewLookupTablesRow();
#add lookup values from xml
$lookupRow.LT_UID = [Guid] $lookupTable.LT_UID
$lookupRow.LT_NAME = [string] $lookupTable.LT_NAME
$lookupRow.LT_SORT_ORDER_ENUM = [int] $lookupTable.LT_SORT_ORDER_ENUM
$lookupRow.LT_PRIMARY_LCID = [int] $lookupTable.LT_PRIMARY_LCID
$lookupRow.LT_FILL_ALL_LEVELS = [boolean] $lookupTable.LT_FILL_ALL_LEVELS
$existingLookupTablesFullData.LookupTables.AddLookupTablesRow($lookupRow);
$ltName = $lookupRow.LT_NAME
}
}
for($i = 0; $i -lt $existingLookupTablesFullData.LookupTables.LT_UID.Length; $i++) {
# remove Lookup tables which are not in source file
if(!$lookupTablesXML.LT_UID.Contains($existingLookupTablesFullData.LookupTables.Rows.LT_UID[$i])) {
$existingLookupTablesFullData.LookupTables.Rows[$i].delete()
}
}
}
function writeLookupTableDataset($lds) {
$lookupSvc.UpdateLookupTables($lds, $false, $true, $lcid);
}
function readExistingLookupTablesDS(){
return $lookupSvc.ReadLookupTables([system.string]::empty , 0 , $lcid);
}
#------------------- Main Function ---------------------------------
$tablesTarget = readExistingLookupTablesDS
#update the lookup tables and add the rows to the dataset
updateLookupMasks $tablesTarget
updateLookupEntries $tablesTarget
updateLookupTables $tablesTarget
writeLookupTableDataset $tablesTarget
Here is a readout from the lookup tables:
$lds.LookupTables.Rows | select LT_NAME, RowState
LT_NAME RowState
------- --------
Deleted
Cost Category Modified -Error
Cost Origin Modified -Error
Cost Rate Currency Modified -Error
Internal Modified -Error
Cost Account Modified -Error
Project Impact Unchanged -Error
Department Unchanged -Error
Deleted
Cost Type Unchanged -Error
Health Unchanged -Error
RBS Unchanged -Error
Relative Importance Unchanged -Error
Domains Added
Test LT Added
Here the Error message (I included the names of the lookup tables at the beginning of each line for better understanding):
<errinfo>
<dataset name="LookupTableDataSet">
<table name="LookupTableMasks">
Cost Category <row LT_UID="dc2f5020-beae-e911-842b-00155dc61919" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="bbe7bf04-abc8-e911-842b-00155dc61919" /></row>
Cost Origin <row LT_UID="85417926-beae-e911-842b-00155dc61919" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="bce7bf04-abc8-e911-842b-00155dc61919" /></row>
Cost Rate <row LT_UID="8986cd2f-beae-e911-842b-00155dc61919" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="bde7bf04-abc8-e911-842b-00155dc61919" /></row>
Internal <row LT_UID="2215a93c-beae-e911-842b-00155dc61919" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="bee7bf04-abc8-e911-842b-00155dc61919" /></row>
Cost Account <row LT_UID="8b6cfb6a-beae-e911-842b-00155dc61919" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="bfe7bf04-abc8-e911-842b-00155dc61919" /></row>
Project Impact <row LT_UID="e8bcec5d-8707-4048-8ff0-4d386457edf7" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c0e7bf04-abc8-e911-842b-00155dc61919" /></row>
Department <row LT_UID="e7397277-1ab0-4096-b2dd-57029a055ba4" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c1e7bf04-abc8-e911-842b-00155dc61919" /></row>
Cost Type <row LT_UID="0000e630-4965-42b3-a697-88f060891b22" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c2e7bf04-abc8-e911-842b-00155dc61919" /></row>
Health <row LT_UID="0000a4aa-160e-499a-905f-d498472dfb35" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c3e7bf04-abc8-e911-842b-00155dc61919" /></row>
RBS <row LT_UID="00008e67-65a3-4898-baaa-d82d995bbb02" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c4e7bf04-abc8-e911-842b-00155dc61919" /></row>
Relative Importance <row LT_UID="5ad95f2a-cb3e-43d4-b42b-faf2db138590" LT_MASK_STRUCT_LEVEL="1"><error id="11076" name="LookupTableAlreadyExists" uid="c5e7bf04-abc8-e911-842b-00155dc61919" /></row>
</table>
</dataset>
</errinfo>
The error was in the updateLookupTableMasks
function.
To be more efficient the function originally deleted all the lookup table masks and created new ones with the updated information. It turns out that this leads to the error. The lookup table masks had to be modified in place.
Therefore my solution was to write an additional function, which checks if a lookup table mask already exists on the server and only add a new one if it does not.