SharePoint 2013 — Перенос элементов списка с SharePoint 2010 на примере записей Блога

imageДля того, чтобы перенести содержимое записей Блога на базе SharePoint 2010 в Блог на базе SharePoint 2013 можно воспользоваться PowerShell. Последовательность действий может быть такая:

На стороне сервера SharePoint 2010

  • Выгружаем в csv-файл элементы списка Категории
  • Выгружаем в csv-файл элементы и содержимое (в отдельный каталог) библиотеки рисунков Фотографии
  • Выгружаем в csv-файл элементы и вложения (в отдельный каталог) списка Записи
  • Выгружаем в csv-файл элементы списка Заметки

На стороне сервера SharePoint 2013

  • Загружаем элементы списка Категории
  • загружаем элементы и содержимое библиотеки рисунков Фотографии
  • Загружаем элементы и вложения списка Записи
  • Загружаем элементы списка Заметки

        Ниже представлены два скрипта, написанных В.Земляковым , которые можно использовать для выгрузки из SP2010 и загрузки в SP2013 списков Категории, Записи, Заметки на примере списка Заметки. С помощью этих же скриптов мы выполняли перенос и других настраиваемых списков. Скрипты переносят элементы списков, даты создания и изменения, автора, вложения (протестировано только на списке Записи). Скрипты не переносят разрешения. Если у вас возникнут какие-то вопросы по работе скриптов в вашем конкретном окружении, не даю гарантии, что смогу на них ответить и возможно по некоторым из них лучше будет обратиться к автору в его блоге.

        Для переноса объектов, хранящихся в библиотеке документов/рисунков (в частности библиотека рисунков Фотографии) будет использоваться другая пара скриптов, которые я постараюсь опубликовать в последующих постах.
        Так как в рассматриваемом примере речь идёт о переносе элементов списков, которые создаются в процессе создания сайта по шаблону Блог, мы не упоминаем тот факт, что структура колонок списка в источнике и получателе должна быть идентична. Если с помощью данных скриптов вы заходите перенести кастомные настраиваемые списки, то на сайте-получателе перед загрузкой нужно будет создать список-получатель в котором колонки будут такими же как и в списке из которого была произведена выгрузка.
        Скрипт выгрузки данных из списка в csv-файл. Выполняется на стороне сервера SharePoint 2010

      #————————————————————-

      # $url — Сайт SharePoint

      # $listName — Название списка SharePoint

      # $csvFilePath — Имя csv-файла для загрузки данных в список

      # $Path — Каталог для выгрузки вложений для элементов списка

      # $columns — Специфичные колонки списка (колонки Title, Modified, Created, Author, Editor учитываются в скрипте)

      #————————————————————-

      #

      # Список шаблона "Блог" — "Записи"

      #

      $url = "http://SP2010.holding.com/KB"

      $listName = "Записи"

      $csvFilePathName = "Posts_Data.csv"

      $Path = "C:Temp"

      $columns = "Основной текст", "Число заметок", "Категория", "Опубликован", "Оценка (0-5)", "Число оценок"

      #

      $snapin = Get-PSSnapin | Where-Object {$_.Name -eq ‘Microsoft.SharePoint.Powershell’}

      if ($snapin -eq $null) {

        Write-Host "Загрузка оснастки SharePoint Powershell"

        Add-PSSnapin "Microsoft.SharePoint.Powershell"

      }

      #

      # Вспомогательные функции

      #

      function GetMultipleUserValue([Microsoft.SharePoint.SPFieldUserValueCollection] $userColl)

      {

        $str = ""

        for ($j = 0; $j -lt $userColl.Count; $j = $j + 1)  {

          $str = $str +$userColl[$j].User.LoginName+";"

        }

        $str = $str.substring(0, $str.lastindexof(";"))

        return $str

      }

      #

      function GetMultipleLookupValue([Microsoft.SharePoint.SPFieldLookupValueCollection] $lookupColl)

      {

        $str = ""

        for ($j = 0; $j -lt $lookupColl.Count; $j = $j + 1)  {

          $str = $str +$lookupColl[$j].LookupValue+";"

        }

        $str = $str.substring(0, $str.lastindexof(";"))

        return $str

      }

      #

      # Создаём подкаталог для выгрузки вложений

      #

      $web = Get-SPWeb $url

      $list = $web.Lists[$listName]

      $listPath = $Path+""+$list.RootFolder.Name

      if ($list.EnableAttachments -eq $true) {

          if (Test-Path -path $listPath) {

              Remove-Item $listPath -recurse

          }

          New-Item -ItemType directory -Path $Path -name $list.RootFolder.Name | out-null

      }   

      #

      # Создаём DataTable

      #

      $dataTable = New-Object System.Data.DataTable           

      $dataTable.Columns.Add("ID") | out-null

      $dataTable.Columns.Add("Title") | out-null

      $dataTable.Columns.Add("Modified") | out-null

      $dataTable.Columns.Add("Created") | out-null

      $dataTable.Columns.Add("Author") | out-null

      $dataTable.Columns.Add("Editor") | out-null

      if ($columns -ne "") {

          foreach ($columnName in $columns) { 

              $dataTable.Columns.Add($columnName) | out-null

          }   

      }

      $dataTable.Columns.Add("Url") | out-null

      $dataTable.Columns.Add("ParentFolder") | out-null

      $dataTable.Columns.Add("IsFolder") | out-null

      #

      # Загоняем в DataTable информацию о папках

      #

      $folders = $list.Folders

      foreach ($folder in $folders) {   

          $row = $dataTable.NewRow()       

          $row["Title"] = $folder.Name

          $row["Url"] = $folder.Url

          $row["ParentFolder"] = $folder.Folder.ParentFolder.Url

          $row["IsFolder"] = 1

          $row["Modified"] = $folder["Modified"]

          $row["Created"] = $folder["Created"]

          $row["Author"] = (Get-SPUser –web $web -Limit All | where{$_.ID -eq [int] $folder["Author"].split(";#")[0]}).loginname

          $row["Editor"] = (Get-SPUser –web $web -Limit All | where{$_.ID -eq [int] $folder["Editor"].split(";#")[0]}).loginname

          $dataTable.Rows.Add($row)        

      }

      #

      # Загоняем в DataTable информацию об элементах списка

      #

      $i = 0

      $count = $list.Items.count

      foreach ($item in $list.Items) {

          $i = $i + 1

          $row = $dataTable.NewRow()   

          $row["ID"] = $item["ID"]

          $row["Title"] = $item["Title"]   

          $row["Modified"] = $item["Modified"]

          $row["Created"] = $item["Created"]

          $row["Author"] = (Get-SPUser –web $web -Limit All | where{$_.ID -eq [int] $item["Author"].split(";#")[0]}).loginname

          $row["Editor"] = (Get-SPUser –web $web -Limit All | where{$_.ID -eq [int] $item["Editor"].split(";#")[0]}).loginname

          $row["Url"] = $item.Url.Substring(0, $item.Url.LastIndexOf(‘/’))  

          $row["IsFolder"] = 0

          #

          # Добавляем специфические поля для этого списка

          #

          if ($columns -ne "") {

              foreach ($columnName in $columns) { 

                  if ($item[$columnName] -ne $null) {

                      if ($item[$columnName].GetType().Name -eq "SPFieldUserValueCollection") {

                          $row[$columnName] = GetMultipleUserValue([Microsoft.SharePoint.SPFieldUserValueCollection]$item[$columnName])    

                      }

                      elseif ($item[$columnName].GetType().Name -eq "SPFieldLookupValueCollection") {

                          $row[$columnName] = GetMultipleLookupValue([Microsoft.SharePoint.SPFieldLookupValueCollection]$item[$columnName])                    

                      }

                      else {

                          $row[$columnName] = $item[$columnName]

                      }               

                  }

                  else {

                      $row[$columnName] = ""

                  }       

              }       

          }   

          $dataTable.Rows.Add($row)       

          #   

          if ($i % 10 -eq 0)  {

              write-host "Выгружено" $i "записей из" $count                   

          }

          #

          # Выгружаем вложения элемента

          #

          if ($list.EnableAttachments -eq $true) {

              New-Item -ItemType directory -Path $listPath -name $item.ID | out-null

              foreach ($attachment in $item.Attachments) {

                  $file = $web.GetFile($item.Attachments.UrlPrefix + $attachment)

                  $bytes = $file.OpenBinary()           

                   $attachPath = $listPath+""+$item.ID+""+$attachment         

                   Write-host "Выгрузил " $attachment "для элемента списка" $item.Title‘, ID =’$item.ID

                   [System.IO.FileStream] $fs = new-object System.IO.FileStream($attachPath, "OpenOrCreate")

                   $fs.Write($bytes, 0 , $bytes.Length)

                   $fs.Close()

              }

          }

      }

      #

      # Вываливаем DataTable в csv-файл

      #

      $dataTable | Export-Csv ($Path+""+$csvFilePathName) -Encoding "Unicode" -Delimiter "`t" -Force

      $dataTable = $null

      write-host ‘Выгрузка завершена!!!’ -foregroundcolor "green"

      $web.Dispose()

      Скрипт загрузки. Выполняется на стороне сервера SharePoint 2013

      #————————————————————-

      # $url — Сайт SharePoint

      # $listName — Название списка SharePoint

      # $csvFilePathName — Имя csv-файла из которого будет выполняться загрузка данных в список

      # $Path — Каталог из которого будет выполняться загрузка вложений для элементов списка

      # $columns — Все специфичные колонки для списка (колонки Title, Modified, Created, Author, Editor учитываются в скрипте). Если не требуется задать $columns = ""

      # $columnUserFields — Специфические колонки списка с типом Пользователи/Группа. Если не требуется задать $columnUserFields = ""

      # $hash — Таблица соответствия полей с типом ‘Подстановка’ по принцыпу Колонка списка = Список подстановки. Если не требуется задать $hash = $null

      #————————————————————-

      #

      # Список шаблона "Блог" — "Записи"

      #

      $url = "http://SP2013.holding.com/KB"

      $listName = "Posts"

      $csvFilePathName = "Posts_Data.csv"

      $Path = "C:Temp"

      $columns = "Основной текст", "Число заметок", "Категория", "Опубликовано", "Оценка (0-5)", "Число оценок"

      $columnUserFields = ""

      $hash = @{"Категория" = "Категории"; "Число заметок" = "Заметки"}

      #

      # Замечание при переносе спика "Записи" шаблона "Блог":

      # Название колонки в sp2010 — Опубликован, в sp2013 — Опубликовано, поэтому перед загрузкой необходимо в файле Posts_Data.csv название столбца ‘Опубликован’ переименовать в ‘Опубликовано’

      #

      $snapin = Get-PSSnapin | Where-Object {$_.Name -eq ‘Microsoft.SharePoint.Powershell’}

      if ($snapin -eq $null) {

        Write-Host "Загрузка оснастки SharePoint Powershell"

        Add-PSSnapin "Microsoft.SharePoint.Powershell"

      }

      #

      # Вспомогательные функции

      #

      function AddAttachment($item, $filePath)

      {

        $bytes = [System.IO.File]::ReadAllBytes($filePath)

        $item.Attachments.Add([System.IO.Path]::GetFileName($filePath), $bytes)

        #$item.SystemUpdate()

      }

      #

      function GetMultipleUserValueForUserField

      {

        param ( $usersStr )

        $userColl = New-Object Microsoft.SharePoint.SPFieldUserValueCollection

        $userList = $usersStr.split(‘;’)   

        foreach($user in $userList) {

          $value = $web.Site.RootWeb.EnsureUser($user)

          $userValue = new-object Microsoft.SharePoint.SPFieldUserValue($web, $value.ID, $value.DisplayName)     

          $userColl.Add($userValue)

        }     

        return ,$userColl   #запятая нужна обязательно, а то не хрена не работает множественное добавление пользователей http://blog.tyang.org/2011/02/24/powershell-functions-do-not-return-single-element-arrays/

      }

      #

      function GetMultipleLookupValueForLookupField

      {

        param ( $lookupStr, $lName )

        $spList = $web.Lists[$lName]

       

        $valuelist = ""

        if ($lookupStr -like "*;#*" ) {

          $lookupColl = New-Object Microsoft.SharePoint.SPFieldLookupValue

          $value = $lookupStr.substring($lookupStr.indexof(";#")+2)

          #$value

          $spQuery = New-Object Microsoft.SharePoint.SPQuery

          $spQuery.Query = "'<Where><Eq><FieldRef Name=’Title’/><Value Type=’TEXT’>"+$value+"</Value></Eq></Where>’"

          if ($spList.GetItems($spQuery) -ne $null){   

              $result = $spList.GetItems($spQuery)[0];

              $lookupColl = new-object Microsoft.SharePoint.SPFieldlookupValue($result.ID, $lookupName)         

          }     

        }

        else {

          $lookupColl = New-Object Microsoft.SharePoint.SPFieldMultiChoiceValue

          $valuelist = $lookupStr.split(‘;’)   

          foreach($lookupName in $valuelist) {   

              $spQuery = New-Object Microsoft.SharePoint.SPQuery

              $spQuery.Query = "'<Where><Eq><FieldRef Name=’Title’/><Value Type=’TEXT’>"+$lookupName+"</Value></Eq></Where>’"

              if ($spList.GetItems($spQuery) -ne $null){   

                  $result = $spList.GetItems($spQuery)[0];

                  $value = new-object Microsoft.SharePoint.SPFieldlookupValue($result.ID, $lookupName)     

                  ,$lookupColl.Add($value)  

              }     

          }   

        }

         

        return ,$lookupColl   #запятая нужна обязательно, иначе не работает множественное добавление пользователей http://blog.tyang.org/2011/02/24/powershell-functions-do-not-return-single-element-arrays/

      }

      #

      function AddFolder() {

          param (

              $list,

              $ServerRelativeUrl,       

              $folderName

          )   

         

          $folder = $web.GetFolder($ServerRelativeUrl)   

          $folder = $list.AddItem($ServerRelativeUrl, [Microsoft.SharePoint.SPFileSystemObjectType]::Folder)

          $folder["Title"] = $folderName

          $folder["Modified"] = [datetime]::Parse($_.Modified, $ruCulture)

          $folder["Created"] = [datetime]::Parse($_.Created, $ruCulture)

          $Author = $web.Site.RootWeb.EnsureUser($_.Author)  

          $folder["Author"] = New-Object Microsoft.SharePoint.SPFieldUserValue($web, $Author.id, $Author.LoginName)

          $Editor = $web.Site.RootWeb.EnsureUser($_.Editor)  

          $folder["Editor"] = New-Object Microsoft.SharePoint.SPFieldUserValue($web, $Editor.id, $Editor.LoginName)        

          $folder.Update();            

      }

      #

      $spAssignment = Start-SPAssignment

      $web = Get-SPWeb $url -AssignmentCollection $spAssignment

      $users = Import-Csv -Delimiter "`t" -Path ($Path+""+$csvFilePathName)

      $list = $web.Lists[$listName]

      $ruCulture = [Globalization.cultureinfo]::GetCultureInfo("ru-RU")

      #

      $jj = 0;

      $columnLookupFields= new-object string[] $hash.Count

      foreach ($column in $hash.keys)

      {

          $columnLookupFields[$jj] = $column

          $jj++

      }

      #

      $i = 0

      $lookupCount = 0

      $count = $users.Count

      $item = $null

      $users | where {

          if ($_.IsFolder -eq "1") {       

              AddFolder -List $list -ServerRelativeUrl $_.ParentFolder -folderName $_.Title

          }

          else {       

              $currentFolder = $web.GetFolder($_.Url)

              $item = $list.items.Add($currentFolder.ServerRelativeUrl, [Microsoft.Sharepoint.SPFilesystemobjecttype]::File, $null)                            

              $item["Title"] = $_.Title  

              $item["FileLeafRef"] = $_.Title            

              $item["Created"] = [datetime]::Parse($_.Created, $ruCulture)       

              $Author = $web.Site.RootWeb.EnsureUser($_.Author) 

              $item["Author"] = New-Object Microsoft.SharePoint.SPFieldUserValue($web, $Author.id, $Author.LoginName)

              $Editor = $web.Site.RootWeb.EnsureUser($_.Editor) 

              $item["Editor"] = New-Object Microsoft.SharePoint.SPFieldUserValue($web, $Editor.id, $Editor.LoginName)

             

              if ($columns -ne "") {

                  foreach ($columnName in $columns) {             

                      if ($_.$columnName -ne "") {                             

                          $InternalName = ($list.Fields.GetField($columnName)).InternalName

                          $name = $_.$columnName                   

                          try {

                              $item[$InternalName] = [datetime]::Parse($name, $ruCulture);

                          }

                          catch [FormatException] {                 

                              if ($columnUserFields -contains $columnName) {                     

                                  $coll = GetMultipleUserValueForUserField $name

                                  $item[$InternalName] = $coll

                              }

                              elseif ($columnLookupFields -contains $columnName) {                     

                                  $coll = GetMultipleLookupValueForLookupField $name $hash.Get_Item($columnName)

                                  $item[$InternalName] = $coll

                                  $lookupCount = $lookupCount + 1

                              }

                              else {

                                  $item[$InternalName] = $name

                              }

                          }              

                      }         

                  }

              }

              $item["Modified"] = [datetime]::Parse($_.Modified, $ruCulture)

              $item.Update()

             

       

              # Загружаем вложения

              if ($list.EnableAttachments -eq $true) {

                  $fileEntries = [IO.Directory]::GetFiles($Path+""+$list.RootFolder.Name+""+$_.ID)

                  foreach($fileName in $fileEntries) {            

                      AddAttachment $item $fileName

                      write-host "Добавлен атач" $fileName

                  }               

              }

              $item.SystemUpdate()

              # Необходимо заменить url картинок, т.к. для записей стали новые ID-шники (выполняется только для списка ‘Записи’)

              if ($item["Основной текст"] -ne $null) {

                  $item["Основной текст"] =   $item["Основной текст"].Replace("Attachments/"+$_.ID, "Attachments/"+$item.ID)           

              }

                   

              $item.SystemUpdate()

              $i = $i + 1

              if ($i % 10 -eq 0)  {

                  write-host "Загружено" $i "записей из" $count

              }

          }   

      }

       

      $users = $null

      $web.Dispose()

      Stop-SPAssignment $spAssignment

      write-host ‘Загрузка завершена!!!’ -foregroundcolor "green"

       

      Добавить комментарий