Sitecore PowerShell – Find Duplicate value in item field


I come across this type of need so may time in my entire career of Sitecore Development. Where I need to find the duplicate value in item’s field. I am writing this as note to me for my own future reference. Hopping this will also help my Sitecore community.

$dictionaryItems = Get-Item -Path 'master:' -Query "/sitecore/system/Dictionary//*[@@templateid='{6D1CD897-1936-4A3A-A511-289A94C2A7B1}']" | Select-Object -Property ID, DisplayName, @{Label="DictionaryKey"; Expression= {$_['Key']}}
$uniqueCollection = $null
foreach ($item in $dictionaryItems){
    if($uniqueCollection -Contains $($item.DictionaryKey)){
        Write-Host "Duplicate Field Value found in item ID  $($item.ID)"
    }
    else{
        $uniqueCollection += $item.DictionaryKey
    }
}

Happy Sitecore PowerShelling…!!!

References

Sitecore Launchpad icons missing


Recently, I am working on an upgrade project (which you must have been knowing if you read few of my recent blogs) and we encountered one very weird issue on Sitecore CM.

The Issue

After successful login to CM, the Launchpad is not showing any icons.

The Solution

First obvious thing I did was open the developer toolbar and inspected the icon image requests under the network tab and it was looking like below image.

All the request to icon images were getting HTTP500 internal server errors. Also observed that .aspx extension is being added at the end of the image extension. For example, /-/icon/LaunchPadIcons/48×48/desktop.png.aspx.

Just dig around the issue, and it turned out, we recently updated the Nuget page reference for the SharpZipLib library to the latest version 1.3.3 for one of the project in customization solution.

The OOTB(vanilla) Sitecore 10.2 also uses the same library but with different version of it.

We matched the version of ICSharpCode.SharpZipLib.dll with the version number come as Vanilla Sitecore Version 1.3.2 and magically all the icons on launch page started appearing again.

Happy Sitecore upgrade…!!!

Event Queue Trouble shooting


Recently we have got an weird issue reported by our content authors on production. They mentioned the content are not reflected on website after they been publish or even re-publish.

First I wanted to check does the Publishing service doing all right and publishing contents correctly. Checked and it was working absolutely fine. I did switch to web database and validated recently published content. After some initial trouble shoot, discovered on CDs, the cache is not been clearing upon successful publish.

This leads my thought to suspect event queue table may have been flooded with lots of entry and may need a clean.

Did a eventqueue table cleaning as mentioned here and things did not went to normal. Still published changes were not reflecting on the website.

Now, I need to dive into detail to understand what is happening in eventqueue table.

The Properties table holds the last event execution time stamp against all the CDs.

To get that last run timestamp follow below steps:

  1. go to your web app and open the Kudu advance tool.
  2. Navigate to Environment page from menu in header
  3. Get the Machine Name from System Info section
  1. Open SSMS and connect to Database
  2. Open new query window for the database which is configured as your Event Queue database( in our case we have configured dedicated one. By default it is web)
  3. Run below query to get the last run time stamp for that CD instance
SELECT * FROM Properties where Key LIKE '%WEB_EQSTAMP_<<MACHINENAME>>%' ORDER BY Value DESC
  1. Replace<<MACHINENAME>> in above query with machine name from step 3 above

Depending on how may instances your selected CD is running, it will show you that may rows (by default there will be two rows for each CD. one is for Production instance and another for pre-prod instance). The value column holds the Time stamp value of last run.

Now, that we have the last run time stamp for the CD, we can get the list of all pending events for this CD instance by running below query.

  SELECT * FROM EventQueue WHERE Stamp >= CONVERT(VARBINARY, <<TIMESTAMP>>) ORDER BY Created DESC

Replace the <<TIMESTAMP>> with the value from previous query.

By combining all queries together, the final query will look like below

SELECT * FROM EventQueue WHERE Stamp >= 
  (
    SELECT CONVERT(VARBINARY, Value) from [Properties] where [Key] = 'WEB_EQSTAMP_<<MACHINENAME>>'
  )
  ORDER BY [Created] DESC

After all this investigation, it is clear that CD servers are not triggering remote events registered in dedicated event queue table.

Did little more investigation and found out wrong event queue configuration files has been deployed to CDs accidentally and that was causing this behavior. We placed the correct config files for dedicated event queue and the peace has been established on CD role again.

Happy Event queue trouble shooting…!!!

References

Sitecore Unicorn Exclude Fields


While you have a high functional developers team working on multiple Sitecore projects with same code base, it is very vital to keep the local development environment as stable and functional as possible and also keep PR short.

While achieving that stage, we came across one small issue which is intern made me to write a blog in my journal what you are reading now.

The Issue

While reviewing PRs, we observed, there is one Unicorn’s .yml file come as default to quite a few PRs. The change it has got was just few fields updated.

After quick initial investigation, found out that yml file is nothing but one of the Data Exchange Framework(DEF) batch processing item in Sitecore content tree under system node.

After bit more investigation, it turns out the sitecore’s schedule task is triggering that DEF batch process. But that raise another question, why that schduler task item is not coming as changed item list as it is also source controled using Unicorn.

The Resolution

Lets focus on the second question for now, as it has quite a quick and simple answer.

The \App_Config\Include\Unicorn\Unicorn.config has one section called <fieldFilter> which takes care of it. As few frequently value changing fields has already been excluded from being serialized (smart stuff Unicorn Developers).

That section is looking like below

<fieldFilter type="Rainbow.Filtering.ConfigurationFieldFilter, Rainbow" singleInstance="true">
					<exclude fieldID="{B1E16562-F3F9-4DDD-84CA-6E099950ECC0}" note="'Last run' field on Schedule template (used to register tasks)" />
					<exclude fieldID="{52807595-0F8F-4B20-8D2A-CB71D28C6103}" note="'__Owner' field on Standard Template" />
					<exclude fieldID="{8CDC337E-A112-42FB-BBB4-4143751E123F}" note="'__Revision' field on Standard Template" />
					<exclude fieldID="{D9CF14B1-FA16-4BA6-9288-E8A174D4D522}" note="'__Updated' field on Standard Template" />
					<exclude fieldID="{BADD9CF9-53E0-4D0C-BCC0-2D784C282F6A}" note="'__Updated by' field on Standard Template" />
					<exclude fieldID="{001DD393-96C5-490B-924A-B0F25CD9EFD8}" note="'__Lock' field on Standard Template" />
				</fieldFilter>

So now, for my initial issue to fix , I simply have to add a field I wanted to exclude form being serializedin to this fieldFilter section.

So, I created new patch configuration file (as best practice suggests) an try to patch my new exclude fields under the node <fieldFilter>. At first, I did add the config like following

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:environment="http://www.sitecore.net/xmlconfig/environment/">
	<sitecore role:require="Standalone or ContentManagement">
		<unicorn>
			<defaults>
				<!--
					The field filter can be used to ignore fields when comparing or serializing (i.e. don't write them to disk).
					Commonly, metadata fields such as Last Updated will be ignored to prevent SCM conflicts.
				-->
				<fieldFilter>
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{985BA535-0F3E-4DA8-A768-A469026DE9DB}" note="'RequestedAt' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{6A2B2CBB-4338-4814-A8A9-9FECBB90456A}" note="'LastRunFinished' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{2AA5C591-FF55-411D-96C0-978BB2C58B94}" note="'Log' field of DEF's Pipeline Batch item" />
				</fieldFilter>
			</defaults>
		</unicorn>
	</sitecore>
</configuration>

But this has weird patching when I see showconfig.appx. It actually replaces first three entries form the original xml…!!!???

I did ask God(google) and found that sitecore sometime does not patch correctly if proper attributes are not used. Someone suggest to use hint attribute to control the patching.

I did replace my patching config attribute note with the hint and eureka….!!!

This is the final configuration patch file looks like.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:environment="http://www.sitecore.net/xmlconfig/environment/">
	<sitecore role:require="Standalone or ContentManagement">
		<unicorn>
			<defaults>
				<!--
					The field filter can be used to ignore fields when comparing or serializing (i.e. don't write them to disk).
					Commonly, metadata fields such as Last Updated will be ignored to prevent SCM conflicts.
				-->
				<fieldFilter>
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{985BA535-0F3E-4DA8-A768-A469026DE9DB}" hint="'RequestedAt' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{6A2B2CBB-4338-4814-A8A9-9FECBB90456A}" hint="'LastRunFinished' field of DEF's Pipeline Batch item" />
					<exclude patch:after="exclude[@fieldID='{001DD393-96C5-490B-924A-B0F25CD9EFD8}']" fieldID="{2AA5C591-FF55-411D-96C0-978BB2C58B94}" hint="'Log' field of DEF's Pipeline Batch item" />
				</fieldFilter>
			</defaults>
		</unicorn>
	</sitecore>
</configuration>

After this, Unicorn re-serialized the DEF pipeline batch items and happy days….!!!!

Note:

There is new feature “fieldTransforms” available in Unicorn 4.1 and later version but I have not able to get that working on my project setup. But, something worth exploring for next time.

References

DEF – Pipeline batch ribbon button issue


This is going to be a short blog for fixing issue I came across while working on custom pipeline creation and execution for Sitecore’s Data Exchange Framework(DEF or DxF).

The issue

While the Pipeline Batch item is selected, buttons on DATA EXCHANGE toolbar at top does not behave how they should.

Immediately after selecting pipeline item, I noticed all buttons in ribbon is visible and clickable. Secondly, clicking on Run Pipeline Batch Button does not works. I was neither starting execution of pipeline nor displaying any visible error messages. See below image for more details:

The fix

I started investigation and collecting events what could have done the damage. Found that before last deployment it was behaving the way it should be. Huuummm… that’s good hint, isn’t it? The last release just deployed files to CMS server. This is soothing to my ears as investment scope is drastically reduced to files. The content automatically gone out of equation.

To fix this, I tried install DEF SDK package first with just deploying file artifacts and skipping any content installation.

Unfortunately, that does not work ….!!! ūüė¶

Next best bet is obvious and try to re-install the DEF framework package with deploying files only.

And that does the trick ….!!!! (Dance)

Update:

The file \App_Config\Sitecore\DataExchange\Sitecore.DataExchange.Local.config was missing. Placing this file from Package has actually fixed the issue.

Happy Data Sync and import using Sitecore Data Exchange Framework. ūüôā

Sitecore CMS not showing graph on Launch pad


This morning when I login to one of none production environment I found that the graph was not loading on Sitecore CMS launch pad.

When I did into more details and found out the ajax request to get the data are failing with server error(HTTP-500). As shown in below image the response of the API call does not providing any information or clue.

Immediately, I jumped onto logs and found following entry in there.

 The remote server returned an error: (403) Forbidden.

The full exception looks like below.

50616 09:48:50 ERROR [Experience Analytics]: System.Net.WebException: The remote server returned an error: (403) Forbidden.
   at System.Net.HttpWebRequest.GetResponse()
   at Sitecore.Xdb.Reporting.Datasources.Remote.RemoteReportDataSourceProxy.GetData(ReportDataQuery query)
   at Sitecore.Xdb.Reporting.ReportDataProvider.c__DisplayClass18_0.b__1()
   at Sitecore.Xdb.Reporting.ReportDataProvider.GetCachedDataForQuery(ReportDataQuery query, Func`1 ifNotAvailableInCache, Nullable`1 ifModifiedSince)
   at Sitecore.Xdb.Reporting.ReportDataProvider.ExecuteQueryWithCache(ReportDataQuery query, ReportDataSource dataSource, CachingPolicy cachingPolicy)
   at Sitecore.Xdb.Reporting.ReportDataProvider.GetData(String dataSourceName, ReportDataQuery query, CachingPolicy cachingPolicy)
   at Sitecore.ExperienceAnalytics.Api.ReportDataService.ExecuteQuery(IReportQueryData queryData, CachingPolicy cachingPolicy)
   at Sitecore.ExperienceAnalytics.Api.ReportingService.RunQuery(ReportQuery reportQuery)
   at Sitecore.ExperienceAnalytics.Api.Http.AnalyticsDataController.Get(ReportQuery reportQuery)

Fix

After further investigation found out the Reporting keys were not aligned between CM and Reporting server in the ConnectionStrings.config file.

<add name="reporting.apikey" connectionString="84090dc97055b10532a054da067df368" />

Further reading

Sitecore Publishing Service – Part 2 – Install and Configure Module


Now that Publishing service is deployed, configure and up in Part – 1, the next bit is to install and configure Sitecore publishing service module in Sitecore CM and CD. This part is very simple and strait forward. So lets get started…

The Sitecore publishing module is nothing but Sitecore package and needs to be installed the same way as other Sitecore packages. This package contains all the necessary artifacts for this module to perform it’s job.

Download

The Sitecore Publishing Module can be downloaded from here.

Note

Just check the the version compatibility with Sitecore version where you wanted to implement this publishing service/module. For this you need to navigate to individual release page and check the compatibility detail at start of the page under the main heading.

Install publishing module

To install Sitecore publishing module, one can use OOTB Sitecore installation wizard.

==========================================================
***Important! Copy and save this information***
==========================================================
    BEFORE YOU CLICK NEXT:
    - Ensure you have installed and configured the Sitecore Publishing Service (this module only enables integration with the service)
        Documentation detailing how to install the service is available seperately.

        [Warning] This module will not work without a properly configured service instance.  No items will be able to be published.
    
    AFTER YOU CLOSE THE WIZARD:
    After the package is installed, follow these steps to complete the Sitecore Publishing Module installation:
    - Configure the service endpoints:
        Add a configuration file which overrides the 'PublishingServiceUrlRoot' setting to point to your service module        
        Make sure the address contains a trailing slash
        e.g.
            <?xml version="1.0" encoding="utf-8"?>
            <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
              <sitecore>
                <settings>
                  <setting name="PublishingServiceUrlRoot">http://sitecore.publishing/</setting>
                </settings>    
              </sitecore>
            </configuration>
    - Configure the Content Delivery Servers:
        Ensure that the following file is in the website 'App_Config/Modules/PublishingService' directory:
            * Sitecore.Publishing.Service.Delivery.config
        Ensure that the following files exist in the website 'bin' directory:
            * Sitecore.Publishing.Service.dll
            * Sitecore.Publishing.Service.Abstractions.dll
            * Sitecore.Publishing.Service.Delivery.dll

Note

Just before installation process starts, installer will prompt the information about configurations and artifacts needed for the Sitecore Module and services to work. As instructed, copy and save that instruction shown in above(From version 3.1.3).

Configure

Once installation of the module is successful, in CM perform following steps:

For CM

For example:

http://my-sitecore-publishing-service.azurewebsites.net/

Note

Make sure the URL is post-fix with forward slash(/) at the end.

For CD

  • Navigate to <website root>/App_Config/Modules/PublishingService folder in both the CM and CD app services
  • Copy Sitecore.Publishing.Service.Delivery.config file from CM to above folder in CD
  • Navigate to <website root>/bin folder in both the CM and CD app services
  • Copy below library files to CD’s bin folder from CM
    • Sitecore.Publishing.Service.dll
    • Sitecore.Publishing.Service.Abstractions.dll
    • Sitecore.Publishing.Service.Delivery.dll

At this point, the publishing will start working, if there is only one default Internet publishing target is there. The Publishing Module has overwritten few of Sitecore default settings for publishing. So after installation of publishing module, one may notice change in UI for the Publishing. Please read here for more details about visual changes and changes in types of publishing.

The last part -3 will cover some specific configuration for Azure PaaS environment and some advance setting of Sitecore Publishing Service. So stay tuned and enjoy content publishing….!!!

Content sync with RAZL script


Hi Sitecore Enthusiastic,

Recently come across very great strategy to sync content between two instances of Sitecore using a very powerful tool called Razl form Hedgehog.

Please read more about Razl here.

I have used this tool before mainly to compare the content between two different databases. For example production CM and Pre-production CM. Today, I came across very new and great features with latest version of Razl offering call tasks and executing task using Razl scripts.

It is offering content sync tasks to be exported in a file(or call script) as xml format and later one can use that to sync data in different environment using Razal script.

For more information about Razl task, read official document here.

The great part of this task is you can cherry pick what you want to sync out of the whole Sitecore content tree. You can go deep up to the field level with your sync task.

once you have a list of tasks ready, you simple can export that as script and execute it with command or create scheduler task to run that script using command and it will do the sync between source and target connections.

Razl.exe /script:Migrate.xml
Razl.exe /script:"c:\Site Migration\Razl.xml"

Even if you want to go one level further you can automate this sync task post publishing(perhaps not ideal, if frequent publishing is happening) or you can hook it post deploy task in you CD script(if your build contains TDS/unicorn content items).

You must be wondering this is great tool and great way to sync, but what if I am trying to sync big chunk of content items!!!???.
You can use another great feature of Razl called Lightening Mode(obviously you can configure this in you script as well). This mode really boost the performance of sync script if your CoplyAll task is configured to do bulk copying of items.

As far as logging concern, Razl Script mode will output actions as they happen to the command prompt, this output can be written to a text file if required using following command sample.

Razl.exe /script:"c:\Site Migration\Razl.xml" >> c:\logs\RazlScriptLogs.txt

Tip: Single arrow > will create the file if missing and if exist, overwrite the content of file.
Double  arrow >> will create the file if missing and if exist, it will append to the file.

If a log folder has been already configured in the Razl GUI than Script mode will also write to the log file under configured log folder.

Thanks for reading.

Happy Content Sync…!!!

Reference
Script – https://hedgehogdevelopment.github.io/razl/script.html
Connections – https://hedgehogdevelopment.github.io/razl/connections.html
Lightning mode – https://hedgehogdevelopment.github.io/razl/comparing.html#lightning-mode

Set dynamic datasource for template field in Sitecore multi-site


This is to share some of the tricks you can use while dealing with multi-sites with Sitecore CMS while designing content solutions.

While dealing with multi-site, we all come across scenario where we want data of some fields to be different per site based on where that item exist. In other words, want to load dynamic data in link types of fields for the data present in that local site.

Of course, the answer is use Sitecore query instead of fixed path. The trick I wanted to share is how to formulate that query.

Lets take one example(I feel if you explain with real life example, people are tend to understand more quickly).

My multi-site content information structure is laid out as follow:

Content

SiteA

Home (All the navigable pages goes here)

Configuration (Master settings for site and features)

Data Library (As name suggested this holds data for the site)

SiteB

Home

Configuration

Data Library

Now, lets assume you have SiteA for Asia-Pacific and SiteB for Europe and there are country data items present under Data Library for both respected sites as shown in picture below.

multi-site-information-structure

Now, you want¬†content editor to select only countries present under that site in field called “Supported Countries” for site’s Configuration¬†item.

sitea-configuration-for-country-items-as-datasource

You can have following Sitecore query as Source of field Supported Countries for the Site Configuration template.

query:./ancestor::*[@@templateid='{B8313310-198B-4596-9532-7E39BAB33503}']/Data Library/*[@@templateid='{7CF67E0D-A30F-4C48-9247-69DE07821520}']/*

Let’s dive in details about how this query is formulated. Before doing that, please¬†thoroughly go through image below.

sc-query-explained

The query is divided in the six parts:

  • Part 1: first part is query keyword, which informs Sitecore that the data source of this field is not just simple item path but complex Sitecore query.
  • Part 2: The the .(dot) present the current item. These items are highlighted in Red. In our example,¬†it is Configuration¬†item. As we are setting query for the field Supported Countries¬†of template Site Configuration. Configuration item under SiteA and SiteB is actual instance of template.
  • Part 3: This is the tricky part, form current item we are getting the list of all the ancestor items. For Configuration item under SiteA, the ancestors are SiteA, Content and Sitecore. For SiteB, ancestors to Configuration items are SiteB, Content and Sitecore.¬†These items are highlighted in violet color. Once we get the list of ancestors, we need to filter out the item which is of template type Site(id of this template is¬†{B8313310-198B-4596-9532-7E39BAB33503}.
  • Part 4: From Filtered Site item, we need to dive in the the sub-tree of Library. To do this we can use the same method of filtering based on template id like we did in part 3 above, but this would be bit costly operation as we need to look for all children underneath site and then filter based on Site Data Library template. Here, I¬†have used fixed path instead, assuming all the sites in this content tree have to have a item called “Data Library”. This is to demonstrate, one can use fixed path query as well with¬†Sitecore query. These are highlighted in green color in content tree.
  • Part 5: The 5th¬†part is same as part 3, except looking for ancestors, it is looking for children and then filtering the child with the template id¬†{7CF67E0D-A30F-4C48-9247-69DE07821520}. This is to find folder type item of template Country Folder, which are¬†highlighted in Sky-blue color in content tree.
  • Part 6: The last part is to get the list of all¬†items under the Countries folder filtered in part 5 above. Here, I assuming none other item present under this folder except for template type Country. If you are looking for particulate type of items you can use filters to get those items. These items in content tree are highlighted in grey color as leaf nodes.

Tip:¬†Be cautious while using descendant or //* in field’s¬†datasource query. This is costlier read operations and may hit the performance of field rendering in Content editor.

Enjoy dynamic field data source and Sitecore query …!!!

Reference
https://sdn.sitecore.net/Reference/Using%20Sitecore%20Query/Sitecore%20Query%20Syntax.aspx

Content Editor – Create new version automatically on Edit


I came across very nice feature Sitecore CMS is providing out-of-box. This might be very useful strategy while doing the content population/editing.

Here, I am trying to configure Content Management(CM) or say Content Authoring(CA) server to automatically create newer version upon editing the item. This whole exercise can be divide in to two steps :

Step 1: Configure Locking is requited for item editing

To do this, you may need to open the web.config and check below setting’s value is set to “true” on CA server. The default value is true.


<setting name="RequireLockBeforeEditing" value="true" />

 

Step 2: Configure auto-creation of version for item

To get this thing working, default workflow must be assigned to the item for which automatic version creation should be enable while editing. As a start, you can use the default workflow provided by Sitecore /sitecore/system/Workflows/Sample Workflow and if you have required workflow ready you can utilize that. If you planning to utilize sample workflow, please also consider reading my this post.

The best practice is to assign default workflow to template’s standard values. Have a look to below image for more details.

Template Standard Values - Default Workflow

Tip: You may need to switch on the Standard Fields view form View Menu to see Workflow section.

Following code in WorkflowContext class of  Sitecore.Workflows.dll is actually responsible for creating version on editing.


public Item StartEditing(Item item)
{
	Error.AssertObject(item, &amp;quot;item&amp;quot;);
	if (!Settings.RequireLockBeforeEditing || Context.User.IsAdministrator)
	{
		return item;
	}
	if (this._context.IsAdministrator)
	{
		return this.Lock(item);
	}
	if (StandardValuesManager.IsStandardValuesHolder(item))
	{
		return this.Lock(item);
	}
	if (!this.HasWorkflow(item) &amp;amp;&amp;amp; !this.HasDefaultWorkflow(item))
	{
		return this.Lock(item);
	}
	if (!this.IsApproved(item))
	{
		return this.Lock(item);
	}
	Item item2 = item.Versions.AddVersion();
	if (item2 != null)
	{
		return this.Lock(item2);
	}
	return null;
}

All above works for non administrator users. By default, for admin user in Sitecore, they do not need to lock the item to edit so it does not triggers any workflow.

Happy Versioning…!!! ūüôā