Introduction
This tip will give an overview to Sitecore developers about how to migrate data using Sitecore PowerShell scripts.
Background
When our client shared a plan to redesign the blog site, after discussion with the client, we came to know that we have to create new templates for blog site and have to migrate old data in new content items created by new templates, because the client wanted to not make any changes on existing blog site related Sitecore items templates.
We did brainstorming and thought about creating a new node by copying of existing template and content node and then start changing around new node. The challenge was linking between new node templates and new content items without any data lost at early stage. After some investigation, we came to know that we can utilize Sitecore PowerShell scripts for data migration. Initially, we were not fully aware of how many and how complex query we need to write to complete the full migration. We investigated more inside Sitecore PowerShell scripts extension and were able to write some very useful scripts and that was enough for us to go ahead with this approach.
Sitecore PowerShell extension module can download from Sitecore marketplace. This module can be installing as normal Sitecore package installation and after installation Power ISE can be accessed under development tools to write and execute scripts.
Power SEI screenshot for reference:
Reference Scripts
- We copied everything from old node, created a new node of templates and a new node of contents from the existing blog site node. Sitecore itself keeps all value type data in new node.
- In new node contents, all reference fields were still pointing to the old node. We write Sitecore PowerShell scripts to change new content items relationship from old templates to new templates and update association of reference fields to new assets templates.
Example Scripts
** In the below example, we first declare required path in variables, create functions to fetch assets like “GetAuthor”, “GetContentType”, “GetTags” etc, and lastly write script to migrate by consuming all.
*Old Node: OldBlogSite
*New Node: NewBlogSite
*Set all required path to traverse their children:
$master = [Sitecore.Configuration.Factory]::GetDatabase("master");
$oldBlogSiteAuthors = Get-ChildItem -Path
"master:\content\sites\OldBlogSite\Assets\Authors" -Recurse
$newBlogSiteAuthors = Get-ChildItem -Path
"master:\content\sites\NewBlogSite\Assets\Authors" -Recurse
$oldBlogSiteContentTypes = Get-ChildItem -Path
"master:\content\sites\OldBlogSite\Metadata\Enumerations\ContentType" -Recurse
$newBlogSiteContentTypes = Get-ChildItem -Path
"master:\content\sites\NewBlogSite\Metadata\Enumerations\ContentType" -Recurse
$oldBlogSiteTags = Get-ChildItem -Path
"master:\content\sites\OldBlogSite\Assets\Tags" -Recurse
$newBlogSiteTags = Get-ChildItem -Path
"master:\content\sites\NewBlogSite\Assets\Tags" -Recurse
*Function to get new node author id using old node author id to update article author Droplink fields:
function GetAuthor($authorsGuid)
{
$author = $oldBlogSiteAuthors | Where-Object { $_.ID -eq $authorsGuid };
return ($newBlogSiteAuthors | Where-Object { $_.Name -eq $author.Name }).ID;
}
*Function to get new node “content type” id using old node “content type” id to update article “content type” Droplink fields:
function GetContentType($contentItemPath)
{
$contentItem = Get-Item -Path
$contentItemPath.Replace("NewBlogSite","OldBlogSite");
$contentType = $oldBlogSiteContentTypes |
Where-Object { $_.ID -eq $contentItem.ContentType };
return ($newBlogSiteContentTypes |
Where-Object { $_.Name -eq $contentType.Name }).ID;
}
*Function to get new node tags using old node tags id to update article tags TreeListEx fields:
function GetTags($tags)
{
$tagArray = "";
$tags.Split('|') | ForEach-Object {
$tagArray += "|";
$this = $_.Trim();
$tag = $oldBlogSiteTags | Where-Object { $_.ID -eq $this };
$tagArray += ($newBlogSiteTags | Where-Object { $_.Name -eq $tag.Name }).ID;
}
return $tagArray.TrimStart('|');
}
*Script to update templates of specific article type and update association of reference fields of content items:
$articlePageTemplate =
$master.Templates["{DFE29F6A-B11F-411B-BD35-0629A1B23E26}"];
cd master:\content\sites\NewBlogSite\Home\Articles;
Get-ChildItem -recurse | ForEach-Object {
$this = $_;
switch($_.TemplateName)
{
"ArticlePage" { $this.ChangeTemplate($articlePageTemplate);
if($this.Author -ne $null ) {$author = GetAuthor($this.Author);
if($author -ne $null) { $this.Author = $author; }}
$contentType = GetContentType($this.ItemPath);
if($contentType -ne $null) {$this.ContentType = $contentType;}
if($this.Tags -ne $null ) { $tags = GetTags($this.Tags);
if($tags -ne $null) {$this.Tags = $tags}}
}
default {}
}
};
- The next challenge was to move child items of each article to different locations and to link those items to new container item, and finally container to specific article “
Treelist
” field.
Example Scripts
*Script to Move Items of Article to Another Location:
$master = [Sitecore.Configuration.Factory]::GetDatabase("master");
$listFolderTemplate = $master.Templates["{FD41B6C6-49EB-442C-BBF8-E809BB6251F6}"];
cd master:\content\sites\NewBlogSite\Home\Articles\2015;
Get-ChildItem -recurse | ForEach-Object {
$this = $_;
switch($_.TemplateName)
{
"ListArticlePage" {
$path = $this.ItemPath.Replace
("Home/Articles","Assets/Article Page Assets/Lists");
Copy-Item -Path $this.ItemPath -Destination $path.Replace($this.Name,"");
$this | Get-ChildItem -recurse| ForEach-Object {
Move-Item -Path $_.ItemPath -Destination $path ;
}
}
default {}
}
};
*Script to rename container items name as article name and associate items to container:
cd "master:\content\sites\NewBlogSite\Assets\Article Page Assets\Lists\2015";
Get-ChildItem -recurse | ForEach-Object {
$this = $_;
switch($_.TemplateName)
{
"ListArticlePage" {
$this.ChangeTemplate($listFolderTemplate);
$listArray = "";
$this | Get-ChildItem -recurse| ForEach-Object {
$listArray += "|";
$listArray += $_.ID;
}
$this.ContentBoxes = $listArray.TrimStart('|');
$newName = $this.Name + '-Container';
Rename-item -Path $this.ItemPath -NewName $newName
}
default {}
}
};
*Script to associate container item to specific article type Treelist field:
cd master:\content\sites\NewBlogSite\Home\Articles\2015;
Get-ChildItem -recurse | ForEach-Object {
$this = $_;
switch($_.TemplateName)
{
"ListArticlePage" {
$path = $this.ItemPath.Replace("Home/Articles",
"Assets/Article Page Assets/Lists") + '-Container';
$this.ContentBoxes = (Get-Item -Path $path).ID
}
default {}
}
};
We write few more scripts and all migration is done very easily, efficiently and quickly.
Conclusion
Sitecore developer can use Sitecore PowerShell scripts for large data migration or any complex modifications, which required invoking internal Sitecore APIs without writing any utility program. It’s a standard PowerShell syntax which is easy to understand and write.