Sitecore PowerShell

Sitecore, Utveckling

Clones and Sitecore PowerShell Extension

Our organisation is working on a new content structure and took a decision to do this by creating a new content tree by cloning the present one. When it was time to go live with the new content we found that when deleting the clone ID we lost a lot of information on the clone item. The only way to save the information on the fields were to break the inheritance and then delete the dependency to the master item. Doing that manually would have taken a huge amout of time on thousands of items in 16 languages. This was a great opportunity to figure out how to use the Sitecore PowerShell Extension!

It is a good idea to first set up a dev environment with production data and run the script on that environment to prevent the risk of destroying prod data. When the script is finished running, the NewHome Clone node should be disconnected from the master. Then it is easy to create a ordinary Sitecore Package of the content node and import that to the prod environment using the replace alternative.

The Sitecore setup is like the following:

  • Sitecore version 7.2
  • Partial Language Fallback is enabled on almost all fields
  • The renderings field {F1A1FE9E-A60C-4DDB-A3A0-BB5B29FE732E} is set to not shared but enabled Language Fallback to be able for the local markets to have their own layout. (Sitecore 8 has better options to handle this with the Final Renderings field).
  • The global editors have created a new structure in the default EN language. The changes should reflect on the language versions.
  • The renderings on the language versions should be reset to the EN definitions but only if the EN renderings is not empty (has default values specified below)

This is what we would like to achieve:

  • Remove the clone connection
  • The content in Language version fields are reset to EN values in case they had the same value as the EN version.
    The content in these fields are inherited from EN version using Language Fallback
  • The renderings field (the components on the item) is reset if it differ from the EN version but only if the EN version is not empty.
    This is to make all the changes that are done on the EN version reflected on the language versions.
    But some markets have their own localized items so they must remain
  • Display Name has been trimmed and all blank spaces at the trail are removed to make a proper URL without %20 or –
Sitecore PowerShell

Sitecore PowerShell Extension is a great tool to run PowerShell scripts directly on a Sitecore Instance saving a huge amount of repetetive manual work load.

The script does the following:

  1. Sets the start node to the NewHome item
  2. Then iterate through all the children items and versions
  3. Break the inheritance for the following fields on the cloned item (this is of course depending on the fields setup on your Sitecore environment)
    • Display Name
    • Title
    • Description
    • PromoHeader
    • PromoText
    • PromoImage
    • MenuTitle
    • Renderings (modules that is placed on the content page)
  4. After that it deletes the clone connection

Now the NewHome is disconnected from the master tree!

Ok then, now we want to clean up the mess (if any).

  1. Start another loop iterating through all the language versions of the NewHome node
  2. Identify the EN version of respectively item
  3. If the content in a language version field is the same as for the EN version, reset it. It is unnecessary to store the same info in the language version and it will also be more job later on not to be able to use Language Fallback; when editing an EN field we want it to automatically reflect on a language version field if the inheritance is not broken. We do this above on all the fields, but just in case there is an EN language version:
    • Display Name
    • Title
    • Description
    • PromoHeader
    • PromoText
    • PromoImage
    • MenuTitle
    • Renderings (modules that is placed on the content page)
  4. Finally we reset the layout to reflect the EN version. But only in case of the following:
    • There is actually an EN version
    • The EN version is not empty (with no modules pasted on it)
      This is because the markets have created language version items that is not present to the EN site. Sometimes we had to create an empty EN version to get the language version to be visible for some reason.

Additional to this, the script also trim the end of the display name in case there is any blank spaces added to the end of it. This is to get a proper URL with no %20 or – at the end.

Microsoft SQL Database Restore Script

I used this script to quickly restore the dev database with production data during the development of the PowerShell script.

RESTORE DATABASE [DATABASE72Sitecore_Core]
FROM  DISK = N'C:\Backup\DATABASE72Sitecore_Core.bak'
WITH  FILE = 1,
MOVE N'Sitecore.Core.Data' TO N'C:\SITE\Database\MDF\DATABASE72Sitecore.Core.MDF',
MOVE N'Sitecore.Core.Log' TO N'C:\SITE\Database\LDF\DATABASE72Sitecore.Core.ldf',
NOUNLOAD,  REPLACE,  STATS = 10
GO

USE [DATABASE72Sitecore_Core]
GO
CREATE USER [USER72] FOR LOGIN [USER72]
GO
USE [DATABASE72Sitecore_Core]
GO
EXEC sp_addrolemember N'db_owner', N'USER72'
GO

RESTORE DATABASE [DATABASE72Sitecore_Master]
FROM  DISK = N'C:\Backup\DATABASE72Sitecore_Master.bak'
WITH  FILE = 1,
MOVE N'Sitecore.Master.Data' TO N'C:\SITE\Database\MDF\DATABASE72Sitecore.Master.MDF',
MOVE N'Sitecore.Master.Log' TO N'C:\SITE\Database\LDF\DATABASE72Sitecore.Master.ldf',
NOUNLOAD,  REPLACE,  STATS = 10
GO

USE [DATABASE72Sitecore_Master]
GO
CREATE USER [USER72] FOR LOGIN [USER72]
GO
USE [DATABASE72Sitecore_Master]
GO
EXEC sp_addrolemember N'db_owner', N'USER72'
GO

RESTORE DATABASE [DATABASE72Sitecore_Web]
FROM  DISK = N'C:\Backup\DATABASE72Sitecore_Core.Web'
WITH  FILE = 1,
MOVE N'Sitecore.Web.Data' TO N'C:\SITE\Database\MDF\DATABASE72Sitecore.Web.MDF',
MOVE N'Sitecore.Web.Log' TO N'C:\SITE\Database\LDF\DATABASE72Sitecore.Web.ldf',
NOUNLOAD,  REPLACE,  STATS = 10
GO

USE [DATABASE72Sitecore_Web]
GO
CREATE USER [USER72] FOR LOGIN [USER72]
GO
USE [DATABASE72Sitecore_Web]
GO
EXEC sp_addrolemember N'db_owner', N'USER72'
GO

The ”cut the dependency of the Clone to the Master item”-script

$rootPath = "master:\content\COMPANY\NewHome"

$items = Get-ChildItem $rootPath -recurse -Version * -Language *
#$items = Get-Item $rootPath -Version * -Language *
ForEach ($item in $items) {
    
  $displayName = $item.DisplayName
  $item."__Display name" = $displayName + " "
  $item."__Display name" = $displayName.TrimEnd()

  $Title = $item.Title
  $item.Title = $Title + " "
  $item.Title = $Title

  $Description = $item.Description
  $item.Description = $Description + " "
  $item.Description = $Description

  $PromoHeader = $item.PromoHeader
  $item.PromoHeader = $PromoHeader + " "
  $item.PromoHeader = $PromoHeader

  $PromoText = $item.PromoText
  $item.PromoText = $PromoText + " "
  $item.PromoText = $PromoText

  $PromoImage = $item.PromoImage
  $item.PromoImage = $PromoImage + " "
  $item.PromoImage = $PromoImage

  $menuTitle = $item.MenuTitle
  $item.MenuTitle = $menuTitle + " "
  $item.MenuTitle = $menuTitle

  $renderings = $item.__Renderings
  $item.__Renderings = $renderings + " "
  $item.__Renderings = $renderings

  Reset-ItemField -Item $item -IncludeStandardFields -Name "__Source"
}

#$ENItem = Get-Item $rootPath -Language en

$ContentPageWide = '<r xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{34EDACDD-933A-442C-9488-70B4FE891810}" /></r>'
$ContentPageActiveSelected = '<r xmlns:p="p" xmlns:s="s" p:p="1"><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" s:l="{E6A2D7AC-AE27-4EBD-AA80-D594EBEEE9F1}" /></r>'
$ContentPageNarrow = '<r xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{E6A2D7AC-AE27-4EBD-AA80-D594EBEEE9F1}" /></r>'
    
$items = Get-ChildItem $rootPath -recurse -Version * -Language da-DK, de-AT, de-CH, de-DE, en-AU, en-GB, en-US, es-ES, fi-FI, fr-BE, fr-CH, fr-FR, it-IT, ko-KR, nb-NO, nl-BE, nl-NL, pt-BR, sv-SE, zh-CN
#$items = Get-Item $rootPath -Language da-DK, de-AT, de-CH, de-DE, en-AU, en-GB, en-US, es-ES, fi-FI, fr-BE, fr-CH, fr-FR, it-IT, ko-KR, nb-NO, nl-BE, nl-NL, pt-BR, sv-SE, zh-CN
ForEach ($item in $items) {
    
    $ENItem = Get-Item master: -ID $item.ID -Language en
    if($ENItem -ne $null) {
        if($item.DisplayName -eq $ENItem.DisplayName) {
            Reset-ItemField -Item $item -IncludeStandardFields -Name "__Display name"
        }
        
        if($item.Title -eq $ENItem.Title) {
            Reset-ItemField -Item $item -Name "Title"
        }
    
        if($item.Description -eq $ENItem.Description) {
            Reset-ItemField -Item $item -Name "Description"
        }
    
        if($item.PromoHeader -eq $ENItem.PromoHeader) {
            Reset-ItemField -Item $item -Name "PromoHeader"
        }
    
        if($item.PromoText -eq $ENItem.PromoText) {
            Reset-ItemField -Item $item -Name "PromoText"
        }
    
        #if($item.PromoImage -eq $ENItem.PromoImage) {
            Reset-ItemField -Item $item -Name "PromoImage"
        #}
    
        if($item.MenuTitle -eq $ENItem.MenuTitle) {
            Reset-ItemField -Item $item -Name "MenuTitle"
        }

        $itemRenderings = $item.__Renderings
        $ENitemRenderings = $ENitem.__Renderings
        if($itemRenderings -ne $ENitemRenderings) {
            if($ENitemRenderings -ne $ContentPageWide -and $ENitemRenderings -ne $ContentPageNarrow -and $ENitemRenderings -ne $ContentPageActiveSelected) {        
                Reset-ItemField -Item $item -IncludeStandardFields -Name "__Renderings"
            }
           
        }
    }
}

After successfully running the script I cleaned up the Renderings field on the language versions in case the renderings were the same as for the EN version.

$rootPath = "master:\content\COMPANY\NewHome"
$ContentPageWide = '<r xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{34EDACDD-933A-442C-9488-70B4FE891810}" /></r>'
$ContentPageActiveSelected = '<r xmlns:p="p" xmlns:s="s" p:p="1"><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" s:l="{E6A2D7AC-AE27-4EBD-AA80-D594EBEEE9F1}" /></r>'
$ContentPageNarrow = '<r xmlns:xsd="http://www.w3.org/2001/XMLSchema" ><d id="{FE5D7FDF-89C0-4D99-9AA3-B5FBD009C9F3}" l="{E6A2D7AC-AE27-4EBD-AA80-D594EBEEE9F1}" /></r>'

$items = Get-ChildItem $rootPath -recurse -Version * -Language da-DK, de-AT, de-CH, de-DE, en-AU, en-GB, en-US, es-ES, fi-FI, fr-BE, fr-CH, fr-FR, it-IT, ko-KR, nb-NO, nl-BE, nl-NL, pt-BR, sv-SE, zh-CN
ForEach ($item in $items) {
    $ENItem = Get-Item master: -ID $item.ID -Language en
    if($ENItem -ne $null) {
        $itemRenderings = $item.__Renderings
        $ENitemRenderings = $ENitem.__Renderings
        if($itemRenderings -eq $ENitemRenderings) {
            Reset-ItemField -Item $item -IncludeStandardFields -Name "__Renderings"
        }
    }
}

Microsoft Windows Media Player

The policy on our computer at work is that the Windows Login Screen shows up after a couple of minutes in case of user being inactive. Running the script and not working on the computer at the same time may cause the lock screen to show up and then the script may stop running in the background. I search for a solution on hacking the registry or local policy but the easiest way not conflicting with the companys policy (there is a reason for policies…) is to start the Windows Media Player, choose any music and run it using the repeat function. Then the lock screen will not appear and the PowerShell script may run util it is done! In my case it took about 5 hours…

Windows Media Player

Windows Media Player on repeat mode keeps the Windows 7 Login Lock Screen away and the PowerShell script that is running in a Browser Session may do its job until it is done.

,

By  -      


Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *