Quantcast
Channel: Second Life of a Hungarian SharePoint Geek
Viewing all articles
Browse latest Browse all 206

Importing multi-level Lookup Tables using PowerShell

$
0
0

Recently I’m working quite a lot with Project Server 2013. My tasks include – beyond development – creation of methods that supports the continuous delivery of the results from the development environment to the test and production environments. I found that my old friend, PowerShell is an invaluable tool in this field as well.

Recently I had to solve a problem, where we had a rather complex, multi-level lookup table (RBS) on the development server, and we had to transfer the same structure on each deployment to the test server. Typing the same structure via the UI each time would have been a very boring and time consuming activity.

If we export the structure via the UI to Excel,

image

the result looks like this:

image

However, when we try to paste the values to the lookup list via the UI, the fields are shifted to the right: the values in the Level field become to the values of the Value field, the Value becomes to the Description, and the original Description is lost, making the whole pasting worthless.

image

I found a very useful PowerShell script on the blog of Paul Mather (the code is available in the TechNet Script Center as well). This script utilizes the PSI interface, however is limited to a single level of values, no hierarchical lookup tables.

I’ve extended the sample using the generic Stack object of the .NET Framework, pushing and popping the Guids of the parent items, and importing the value of the Description field as well. Otherwise most of the code was borrowed from, and the functionality is identical to the original version of Paul. As input file, a TAB separated text file is used without field name headers, including the Level, Value and Description fields, in the case above, for example:

1    Value 1    Desc 1
2    Value 1_1    Desc 1.1
3    Value 1_1_1    Desc 1.1.1
2    Value 1_2    Desc 1.2
3    Value 1_2_1    Desc 1.2.1
2    Value 1_3    Desc 1.3

This sample is limited to lookup tables with character-based code sequences.

The PowerShell script that enables the mulit-level import:

  1. #Get lookup table values to add
  2. $values = Get-Content "C:\Data\PowerShell\RBSValues.txt"
  3.  
  4. #Specify Lookup table to update
  5. $lookupTableName = "RBS"
  6. $lcid = 1033
  7. $emptyString = [String]::empty
  8. $svcPSProxy = New-WebServiceProxy -Uri "http://sp2013/pwa/_vti_bin/PSI/LookupTable.asmx?wsdl" -UseDefaultCredential
  9. $lookupTableGuid = ($svcPSProxy.ReadLookupTables($emptyString, 0, $lcid).LookupTables  | ? {$_.LT_NAME -eq $lookupTableName }).LT_UID
  10. $lookupTable = $svcPSProxy.ReadLookupTablesbyUids($lookupTableGuid, 1, $lcid)
  11. #get lookup table count
  12. $lookuptableValues = $svcPSProxy.ReadLookupTablesbyUids($lookupTableGuid, 0, $lcid).LookupTableTrees
  13. $count = $lookuptableValues.Count + 1
  14. #update lookup table…
  15. $stack = New-Object System.Collections.Generic.Stack[Guid]
  16. $lastLevel = 1
  17.  
  18. $values | % {
  19.     $fields = $_ -split '\t+'
  20.         $level = $fields[0]
  21.         $text = $fields[1]
  22.         $desc = $fields[2]
  23.  
  24.     $guid = [Guid]::NewGuid()
  25.     # Write-Host Count: $count, text: $text, Guid: $guid, Level: $level, Last level: $lastLevel
  26.     $parentGuid = $lastGuid
  27.     If ($lastLevel -lt $level) {
  28.         $stack.Push($lastGuid)
  29.         # Write-Host Parent GUID Pushed: $parentGuid
  30.     }
  31.     Else {
  32.         While (($stack.Count -ge ($level)) -and ($stack.Count -gt 1)) {
  33.             # Write-Host Popping level ($stack.Count + 1)
  34.             $parentGuid = $stack.Pop()
  35.             # Write-Host Parent GUID Popped: $parentGuid
  36.         }
  37.         If ($stack.Count -gt 0) {
  38.             $parentGuid = $stack.Peek()
  39.             # Write-Host Parent GUID Peeked: $parentGuid
  40.         }
  41.     }
  42.  
  43.  
  44.     $LookupRow = $lookuptable.LookupTableTrees.NewLookupTableTreesRow()
  45.     If (-Not [String]::IsNullOrEmpty($desc)) {
  46.         $LookupRow.LT_VALUE_DESC = $desc
  47.     }
  48.     $LookupRow.LT_STRUCT_UID = $guid
  49.     $LookupRow.LT_UID = $lookupTableGuid
  50.     $LookupRow.LT_VALUE_TEXT = $text
  51.     If ($level -gt 1) {
  52.         # Write-Host Parent GUID set: $parentGuid
  53.         $LookupRow.LT_PARENT_STRUCT_UID = $parentGuid
  54.     }
  55.     $LookupRow.LT_VALUE_SORT_INDEX =  ($count++)
  56.     $lookuptable.LookupTableTrees.AddLookupTableTreesRow($LookupRow)
  57.  
  58.     $lastGuid = $guid
  59.     $lastLevel = $level
  60. }
  61.  
  62. $Error.Clear()
  63. Try
  64.     {
  65.         $svcPSProxy.UpdateLookupTables($lookuptable , 0 , 1 , $lcid)
  66.     }
  67. Catch
  68.     {
  69.         Write-Host "Error updating the Lookup table, see the error below:" -ForeGroundColor Red -BackGroundColor White
  70.         Write-Host "$error" -ForeGroundColor Red
  71.     }
  72. If ($Error.Count -eq 0)
  73.     {
  74.         Write-Host "The lookup table $lookupTablename has been updated with the values from the text file specified" -ForeGroundColor Green
  75.     }
  76. Else
  77.     {
  78.         Write-Host "The lookup table $lookupTablename has not been updated with the values from the text file specified, please see error" -ForeGroundColor Red -BackGroundColor White
  79.     }
  80. #force checkin in case of failure
  81. $Error.Clear()
  82. Try
  83.     {
  84.      $svcPSProxy.CheckInLookUpTables($lookupTableGuid, 1)
  85.     }
  86. Catch
  87.     {
  88.         If ($error -match "LastError=CICONotCheckedOut")
  89.             {
  90.     
  91.             }
  92.         Else
  93.         {
  94.             Write-Host "Error checking the Lookup table, see the error below:" -ForeGroundColor Red -BackGroundColor White
  95.             Write-Host "$error" -ForeGroundColor Red
  96.         }
  97.     }

The script includes a lot of Write-Host cmdlets to enable tracking of the process. These are commented in the version above. You are free to either use or delete these lines as you wish.

Note: Don’t forget to alter the file path, the URI and the lookup table name, and the LCID as well, if you are working with a non-English version of PWA.



Viewing all articles
Browse latest Browse all 206

Trending Articles