Friday, 13 January 2017

Razl scripting with PowerShell

Razl, tool from Hedgehog Development, that was designed to transfer items between Sitecore instances and compare them, has some nice scripting features.

I needed to use Razl scripting for Sitecore upgrade process. I created new fresh Sitecore instance (it was big jump, from 6.5 to 8.1) and started preparing what should be moved to new database. Old instance had a lot of datasource items and huge amount of media library items. Transfer all of this things was huge deal and was processing for over a dozen of hours. I decided to make some changes in my approach.

Preparation of Sitecore instances

I was using Razl 3.0.5. Unfortunately I had some problems with my solution that I couldn't connect with this tool to the Sitecore that had all of solution code deployed, so I've created a clean instance of version 6.5 and a clean version of 8.1. I've changed the connection strings of this two to the correct solution databases and I used this two clean instances just for transferring purposes - worked like a charm. You might not have exact problem, but this is how I went through that.

Preparing Razl script file

First you have to prepare the script file in the Razl. You can do it just like in general, by adding tasks to Task List:


Then, instead of running transfer, you can click 'Export Tasks' button. You will be prompted to save the script file. Let's take a look into the one:
<?xml version="1.0" encoding="utf-8"?>
<razl>
  <connection name="SC65VanillaWithSW.Master" readOnly="false" install="true">
    <url>http://sc650vanilla/</url>
    <accessGuid>047c5600-e111-449c-9e2b-179b06f17190</accessGuid>
    <database>master</database>
    <path>C:\inetpub\wwwroot\sc650Vanilla\Website</path>
  </connection>
  <connection name="SC81VanillaForSW.Master" readOnly="false" install="true">
    <url>http://sc81u2vanillaforconnection/</url>
    <accessGuid>8db29355-a8d4-4102-969a-537cc8c54f30</accessGuid>
    <database>master</database>
    <path>C:\inetpub\wwwroot\sc81u2vanillaforconnection\Website</path>
  </connection>
  <operation name="CopyAll" source="SC65VanillaWithSW.Master" target="SC81VanillaForSW.Master">
    <!--Copy with overwrite '/sitecore/templates/SW', all missing parents and all child items from 'SC65VanillaWithSW.Master' to 'SC81VanillaForSW.Master'-->
    <parameter name="itemId">b80ae69f-4212-43e6-af97-2f86ddcddae1</parameter>
    <parameter name="overwrite">True</parameter>
    <parameter name="lightningMode">False</parameter>
  </operation>
  <operation name="CopyAll" source="SC65VanillaWithSW.Master" target="SC81VanillaForSW.Master">
    <!--Copy with overwrite '/sitecore/templates/User Defined', all missing parents and all child items from 'SC65VanillaWithSW.Master' to 'SC81VanillaForSW.Master'-->
    <parameter name="itemId">b29ee504-861c-492f-95a3-0d890b6fca09</parameter>
    <parameter name="overwrite">True</parameter>
    <parameter name="lightningMode">False</parameter>
  </operation>
  <operation name="CopyAll" source="SC65VanillaWithSW.Master" target="SC81VanillaForSW.Master">
    <!--Copy with overwrite '/sitecore/layout/Layouts/SW', all missing parents and all child items from 'SC65VanillaWithSW.Master' to 'SC81VanillaForSW.Master'-->
    <parameter name="itemId">2141e479-3f72-447c-9afa-3b4db1ea283d</parameter>
    <parameter name="overwrite">True</parameter>
    <parameter name="lightningMode">False</parameter>
  </operation>
</razl>

It has a two connections for the instances which will be used in transfer. It comes from the Razl configuration, where firstly I created that connections. Under that elements there is a list of operations with specified source instance, target instance, ID of the item and configuration of the operation type - in my case it will be CopyAll with overwriting the target instance.

As far as I knew at that time, there was no way to edit exported script with Razl, so I was editing it manually.

Preparing PowerShell run script

At last I wanted to have a PowerShell script that will run my transfer script with just one click. I have prepared a PSs that run razl.exe with specified scripts. For core database this is quite simple - set your directory where Razl script are located in:


For master database I decided to split Razl script into smaller parts, so the I was able to comment out some of them to run just specific ones:


Also these scripts log full log into specific files. So everything that happens while transfer is saved for analysis. Here is some example part of the log:

    1 13:00:31,579 INFO  CopyAll Started Id: 563a2ddb-ad89-4182-9706-eb1512abe0b1, Path: /sitecore/system/Field types/List Types/Google Maps Multilist, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core, Overwrite: True
   1 13:00:31,579 INFO  CopyAll Processing /sitecore/system/Field types/List Types/Google Maps Multilist
   1 13:00:31,580 INFO  CopyItem Started Id: 563a2ddb-ad89-4182-9706-eb1512abe0b1, Path: /sitecore/system/Field types/List Types/Google Maps Multilist, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:31,847 INFO  CopyItem Finish Id: 563a2ddb-ad89-4182-9706-eb1512abe0b1, Path: /sitecore/system/Field types/List Types/Google Maps Multilist, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:31,928 INFO  CopyAll processing children of /sitecore/system/Field types/List Types/Google Maps Multilist
   1 13:00:31,928 INFO  CopyAll Processing /sitecore/system/Field types/List Types/Google Maps Multilist/Menu
   1 13:00:31,929 INFO  CopyItem Started Id: 60daf681-8069-46a2-aa39-5490741f6cec, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:32,196 INFO  CopyItem Finish Id: 60daf681-8069-46a2-aa39-5490741f6cec, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:32,252 INFO  CopyAll processing children of /sitecore/system/Field types/List Types/Google Maps Multilist/Menu
   1 13:00:32,252 INFO  CopyAll Processing /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Show Map
   1 13:00:32,252 INFO  CopyItem Started Id: ce073686-11cb-4921-b4db-61c98bc1f54a, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Show Map, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:32,519 INFO  CopyItem Finish Id: ce073686-11cb-4921-b4db-61c98bc1f54a, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Show Map, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:32,576 INFO  CopyAll processing children of /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Show Map
   1 13:00:32,576 INFO  CopyAll Processing /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Select All
   1 13:00:32,577 INFO  CopyItem Started Id: bbe0cd71-aac7-47bc-971a-49265078d17c, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Select All, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:33,153 INFO  CopyItem Finish Id: bbe0cd71-aac7-47bc-971a-49265078d17c, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Select All, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:33,209 INFO  CopyAll processing children of /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Select All
   1 13:00:33,209 INFO  CopyAll Processing /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Deselect All
   1 13:00:33,209 INFO  CopyItem Started Id: b54acbc5-0fc0-4d6d-a863-0f8657e50504, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Deselect All, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:38,480 INFO  CopyItem Finish Id: b54acbc5-0fc0-4d6d-a863-0f8657e50504, Path: /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Deselect All, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core
   1 13:00:38,537 INFO  CopyAll processing children of /sitecore/system/Field types/List Types/Google Maps Multilist/Menu/Deselect All
   1 13:00:38,593 INFO  CopyAll Finish Id: 563a2ddb-ad89-4182-9706-eb1512abe0b1, Path: /sitecore/system/Field types/List Types/Google Maps Multilist, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core, Overwrite: True
   1 13:00:38,705 INFO  CopyAll Started Id: 5cee31bf-120d-4936-b9c6-930cbf63cb57, Path: /sitecore/system/Field types/Simple Types/Google Maps Single Point, From: SC65VanillaWithSW.Core, To: SC81VanillaForSW.Core, Overwrite: True

More info about Razl scripting is in official Razl documentation: https://hedgehogdevelopment.github.io/razl/script.html.

Tuesday, 10 January 2017

Sitecore Module - Dynamic Sitemap XML

After a lot of work spent on creating project specific sitemap xml implementations I have prepared my own generic sitemap xml module. It is based on original marketplace sitemap module but adds some new great features.


It has two main assumptions:
  • Flexible configuration - to give end user as many as possible configuration options, because it is easier to edit Sitecore items than edit and deploy config files.
  • Extensibility - code functionality should be extensible and override-able. It should be easy to extend or override functionality, without decompiling and copy-pasting a lot of code.

Specifying your own logic

To use or not to use marketplace module - that is the question! Most times main reason to write your own sitemap implementation is thought if there will be some custom tricky functionalities needed. Something like some static html pages or other links that exist outside Sitecore.

 
You can specify your own logic, that can add your custom items to the sitemap.

You should create class that implements IItemsProcessor interface, put it in your assembly and attach your class to the site configuration item, in format MyType, MyAssembly.


In this approach, main functionality of module can be easily changed. More info here https://github.com/ReoKzK/Sitecore.SharedSource.DynamicSitemap/wiki/Specifying-your-own-logic

Separation from content

I also decided to definitely separate sitemap things from the actual content. So deciding whether the item goes to sitemap or nor or setting the change frequency or priority, is set on the sitemap configuration item in Sitecore. This approach will keep your items clean. More info here https://github.com/ReoKzK/Sitecore.SharedSource.DynamicSitemap/wiki/Creating-new-sitemap-configuration

That's all :)

Module is uploaded to official Sitecore Marketplace https://marketplace.sitecore.net/Modules/D/Dynamic_Sitemap_XML_Module.aspx

Whole documentation is available here https://github.com/ReoKzK/Sitecore.SharedSource.DynamicSitemap/wiki

Library is also available at nuget:
Install-Package Sitecore.SharedSource.DynamicSitemap
Hope that my module will be useful and will improve your websites development process.