Friday 7 August 2015

Migrate Sharepoint List with its metadata(excluding Items) in Cross Domain Environment(i.e from DEV Server to PROD Server.)

I have done R&D on this and came to know that we cannot access the sharepoint site in Cross domain Environment(i.e Site Hosted in Server-1 cannot be accessible in Server-2), through powershell and vice-versa. If there is any solution, then please let us know.

I would suggest to please read patiently before going through code.

Approaches that got FAILED 

1) Export .cmp file of the List from Source(DEV Server) and Import the .cmp file to Destination List(PROD Server)

Limitation--List Successfully created with all fields including lookup also, inspite the absence of                             Dependant list to which source list lookup field is pointing.

2) Save the List as Template from DEV Server Site and Import it in PROD Server sharepoint site.

Limitation--List Successfully created with all fields excluding the lookup fields.

Approach:
1) Extract List XML Schemas from Source site.
2) Iterate each List XML Schema whose have look up fields to update the target List ID and Field ID with their Titles,  As because during creating Lists in destination site it will be easy to create look up fields of the concerned Lists.
3) Keep those XML Schemas in a physical drive.
4) Get the content of each List schema in a loop.
5) Iterate each field in a particular List Schema and Create the List along with its Fields in destination site.
6) After creating all Lists in destination site, then create look up Fields in the concerned Lists.

Run below script i.e "Script_1.ps1"(Provide your SP List and Path of local drive) to extract all Lists and its Default View schema in XML format. 
Below Method Update the XML where the field type is "Lookup" by replacing the destination List ID and Column ID with there Title. 

Script_1.ps1

Add-PSSnapin Microsoft.SharePoint.PowerShell

function SetLookupField($SPSourceWeb, $SPSourceList, $ListTemplatePath, $AllItemsViewTemplatePath){

$ListTemplateXML = [xml](get-content $ListTemplatePath)
$AllItemsViewTemplateXML = [xml](get-content $AllItemsViewTemplatePath)
$ViewFieldNames = $AllItemsViewTemplateXML.View.ViewFields.FieldRef.Name
foreach ($node in $ListTemplateXML.List.Fields.Field) 
{
$fieldName = $node.Name
if($ViewFieldNames -contains $fieldName)
{
if($node.Type -eq "Lookup")
{
try{
$TargetLookupListId = $node.List
$TargetLookupListName = $SPSourceWeb.lists[[GUID]($TargetLookupListId)]
$node.List = $TargetLookupListName.Title
$ListTemplateXML.Save($ListTemplatePath)
    }
catch{
Write-Host "List- $($SPSourceList.Title): Column Name- $($fieldName)  Already Exists :("
        }
}
}
}
}

#Write all the list names which you want to migrate from source site to destination site.
$lists = @("List1","List2","List3","ListN")
$SPSourceWeb = Get-SPWeb "<Source Web in DEV Domain>"

foreach($list in $lists)
{
 $SPSourceList = $SPSourceWeb.Lists[$list]

 #Extract the XML Schema of the current list.
 $SPSourceListSchema = $SPSourceList.SchemaXml

 #Save the XML Schema of the current list in Local Drive.
 Write-Output $SPSourceListSchema > E:\LocalDrive\$list.xml
 $ListTemplatePath = "E:\LocalDrive\$list.xml"

 #Get the Default view of the current list
 $SPSourceListDefaultView = $SPSourceList.DefaultView

 #Extract the XML Schema of current list Default view
 #Condition: If you want to create only those columns which are present in Default view
 $SPSourceListViewSchema = $SPSourceList.Views[$SPSourceListDefaultView].SchemaXml

 #Save the XML Schema of the current list Default view in Local Drive.
 Write-Output $SPSourceListViewSchema > E:\LocalDrive\$($list)_View.xml
 $AllItemsViewTemplatePath = "E:\LocalDrive\$($list)_View.xml"

 #Basic purpose of calling below method is to update the field in list XML which is of Lookup Type.
 SetLookupField $SPSourceWeb $SPSourceList $ListTemplatePath $AllItemsViewTemplatePath

}

Then Run below script i.e "Script_2.ps1"(Manually Provide your Lists and Path of  local drive where the xml files get stored) to Create Lists and all columns with lookup columns in destination site.

Script_2.ps1

Add-PSSnapin Microsoft.SharePoint.PowerShell

function CreateList($SPDestSite, $listName, $ListTemplatePath, $AllItemsViewTemplatePath){

$spWeb = Get-SPWeb -Identity $SPDestSite

#Get the server template content from "SourceListTemplateXML" file and create Lists and Libraries #according to Template---E.g If ServerTemplate = "100" Then it will create a Custom List and so on.
$SourceListTemplateXML = [xml](get-content $ListTemplatePath)
$ListSchema = $SourceListTemplateXML.List
$ServerTemplate = $ListSchema.ServerTemplate
$spTemplate = $spWeb.ListTemplates | Where-Object {$_.Type -eq $ServerTemplate}

#Get all available Lists in Destination site into a List collection.
$spListCollection = $spWeb.Lists

#Add/Create the list. If the list already exists then it will not create.
$spListCollection.Add($listName, $listName, $spTemplate)
Write-Host $listName
$path = $spWeb.url.trim()

$spList = $spWeb.Lists[$listName]

#Get the content in XML format of both List and its Default View
$ListTemplateXML = [xml](get-content $ListTemplatePath)
$AllItemsViewTemplateXML = [xml](get-content $AllItemsViewTemplatePath)

foreach ($node in $ListTemplateXML.List.Fields.Field)
{
$fieldName = $node.Name
$ViewLists = $AllItemsViewTemplateXML.View.ViewFields.FieldRef.Name
if($ViewLists -contains $fieldName)
{

if(($node.Type -ne "Lookup") -and (!($spList.Views[$spList.DefaultView].ViewFields.Exists($node.Name) -eq $true)))
{

try{
$spList.Fields.AddFieldAsXml($node.OuterXml, $true,[Microsoft.SharePoint.SPAddFieldOptions]::AddFieldToDefaultView)
}
catch{
Write-Host "List- $($SPSourceList.Title): Column Name- $($fieldName) Already Exists :("
}
}

}
}
$spList.Update()
}

function CreateMissingLookUpColumns($SPDestSite, $listName, $ListTemplatePath, $AllItemsViewTemplatePath)
{
$SPWeb = Get-SPWeb -Identity $SPDestSite
$SPList = $SPWeb.Lists[$listName]

$TargettemplateXml = [xml](get-content $ListTemplatePath)
$AllItemsViewTemplateXML = [xml](get-content $AllItemsViewTemplatePath)

foreach ($node in $TargettemplateXml.List.Fields.Field)
{
$fieldName = $node.Name
$ViewLists = $AllItemsViewTemplateXML.View.ViewFields.FieldRef.Name

if($ViewLists -contains $fieldName)
{

if(($node.Type -eq "Lookup") -and (!($SPList.Views[$SPList.DefaultView].ViewFields.Exists($node.Name) -eq $true)))
{
try{
$TargetLookupListName = $node.List
$SourceLookupListSchema = $TargettemplateXml.List
$SourceLookupListName = $SourceLookupListSchema.Title
$TargetlookupColumn = $node.ShowField
$SourceColumnLookupName = $node.Name
$LookUpRequiredValue = $node.Required
$IndexedValue = $node.Indexed
$LookupList= $spWeb.Lists[$TargetLookupListName]

$fieldXml='<Field Type="Lookup" DisplayName="' + $SourceColumnLookupName + '" Required="' + $LookUpRequiredValue + '" Indexed="'+$IndexedValue+'" ShowField="'+ $TargetlookupColumn +'" StaticName="'+ $SourceColumnLookupName +'" List="' + $LookupList.id + '" Name="' + $SourceColumnLookupName +'"></Field>'

$spList.Fields.AddFieldAsXml($fieldXml,$true,[Microsoft.SharePoint.SPAddFieldOptions]::AddFieldToDefaultView)
}
catch{
Write-Host "Duplicate Column"
}
}

}
}
$spList.Update()
}

$lists = @("List1","List2","List3","ListN")
$SPDestSites = @("<Destination Site URL>")


#Create Lists
foreach($list in $lists)
{

$ListTemplatePath = "E:\LocalDrive\$list.xml"
$AllItemsViewTemplatePath = "E:\LocalDrive\$($list)_View.xml"
$listName = $list
CreateList $SPDestSite $listName $ListTemplatePath $AllItemsViewTemplatePath

}

#Create Missing Look Up Columns from created lists
foreach($list in $lists)
{
$ListTemplatePath = "E:\LocalDrive\$list.xml"
$AllItemsViewTemplatePath = "E:\LocalDrive\$($list)_View.xml"
$listName = $list
CreateMissingLookUpColumns $SPDestSite $listName $ListTemplatePath $AllItemsViewTemplatePath

}


NOTE: If the list-1 contains Lookup Columns that are connected with List-2 then the both lists must be added.

Happy Powershelling..... :) This may help you.

Thanks
Asish

3 comments:

  1. When you say metadata, do you mean Managed Metadata? Or metadata for all items in the list?

    ReplyDelete
  2. Sorry for late Reply.
    Here Metadata represents all columns/fields in a List.

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete