28 June, 2022

Sitecore Docker - xdbautomationworker, cortexprocessingworker, xdbsearchworker unhealthy in Docker Desktop 4.9.1

Back to blogging after a month of learning and completing certifications. June has been a month of Certifications in Sitecore community. :) 

Containers for Sitecore development has reduced the onboarding time for new team members and it is easy to bring up and bring down a Sitecore environment without impacting much on the hosting environment. 

When Docker Desktop works, everything is fine. When it does not, sometimes we have to spend hours to find the root cause especially in an office laptops where company policies are applied. That's been the case after Docker Desktop 4.7+ onwards. 

ERROR: for cortexprocessingworker Container "22039ee585b5" is unhealthy. ERROR: for xdbautomationworker Container "22039ee585b5" is unhealthy. ERROR: for xdbsearchworker Container "22039ee585b5" is unhealthy. ERROR: Encountered errors while bringing up the project.

Recently encountered this issue with Docker Desktop 4.9.1. There are multiple ways mentioned in the below links.

We followed the below step to resolve the issue. 

  • Open Windows Defender Firewall with Advanced Security
  • Click Windows Defender Firewall Properties. 
  • Go to Publish Profile, click Customize in Protected network connections. 
  • Uncheck any network connections starting with name - vEthernet
  • Start the containers again. 
Few experts in the community mentioned that there are other alternatives. Trying to gather the details and reference those solutions here. 

04 June, 2022

Create, package and publish a Sitecore CLI Plugin

We (SitecoreWarriors) had a chance to participate in Sitecore Hackathon 2022 and we peeked into how the Sitecore's official plugins are created and how a new plugin can be created using Extensibility package provided by Sitecore. In this article, I wanted to explain few steps to create a new plugin, package it and publish it to or any other private package manager. 

  1. Create Plugin Project - .NET Core Class Library
  2. Create Management Service - .NET Framework 4.8 Class Library
  3. Package and Publish Plugin 

Create Plugin Project
  • In order to create a plugin, we need to create a .NET Core Class Library. 
  • Project type should be Microsoft.NET.Sdk
  • From Sitecore Package source, add the following packages.

    • Sitecore.Devex.Client.Cli.Extensibility
      • This package helps to create an extension to the Sitecore CLI
      • Adds base for SubCommand options
    • Sitecore.DevEx.Serialization.Client
      • Enables us to use SitecoreApiClient which helps to send and receive response from Sitecore through management service. 
      • Helps to generate the API request along with access token and send it to Sitecore. 
      • Not sure why but Sitecore may move this piece out of Serialization Client package and create it as a standalone package to avoid this dependency.
  • Next step is to implement ISitecoreCliExtension interface which will let us to register Commands. As part of this sample application, we are trying to create a Job plugin which can retrieve the jobs list from Sitecore. 

  • Then we can create new SubCommand class inheriting SubcommandBase from Sitecore.Devex.Client.Cli.Extensibility package. This will let us to override the handle method to implement the logic to call Sitecore API for this SubCommand.

  • In the SubCommand implementation, use SitecoreApiClient and trigger the request to Sitecore Management API.  

Create Management Service
  • Sitecore Management Service gets the request from CLI and execute the request in Sitecore Context. 
  • Authentication token obtained from CLI login is sent as part of the Bearer token. 
  • Depending upon the solution, the dependencies changes. In this case, we needed Sitecore.Kernel, Sitecore.DependencyInjection package. 
  • Management services uses GraphQL. Queries and Mutations.

    Queries are the GraphQL equivalent to GET calls in REST. mutations represent the state-changing methods in REST (like DELETEPUTPATCH, etc).

  • In this example, we are just getting Jobs list. So we can go with query. Implement Sitecore.Services.GraphQL.Schemas.SchemaProviderBase from Sitecore.Services.GraphQL and override CreateRootQueries which in turn returns the data to be returned to CLI. Logic is get the jobs list from JobManager and return the results. 

  • Build the class library along with configuration and package it as Sitecore Package to be installed via Installation Wizard. 
Package and Publish Plugin

We can create package 
In this article, I will explain how we can package it using NuGet Package Explorer.
  • We need to prepare the package content. Package should have the plugin library (.dll). Please note that DLL name and the plugin name should match otherwise we may get errors. Refer this article for more details - Sitecore CLI Extension Development - Possible errors and solution
  • Once the NuGet Package Explorer is downloaded and opened, choose Create a new package. 

  • Go to Edit menu and click Edit Metadata. 
    • Add the plugin name in the ID field
    • Create a new folder called plugin
    • Add plugin class library and few other assemblies like Sitecore.DevEx.Serialization.Client and Microsoft.Extensions.Http to the plugin folder. 

  • Go to, create a new account, login to the account, click on your username and go to API keys. 

  • Create a new API key. Provide a key name and click create. Copy the generated key and save it securely. 

  • Go back to the NuGet package explorer, go to File and click Publish. Enter the copied API key in the Publish Key or PAT field and then click publish. It should be published immediately and it may take 10 minutes for the package to be available in the search results. 

How to install the plugin and use it
  • Install the management service package created in the second step in Sitecore CM using installation wizard. 
  • Once the package is available in search results, you can login to CLI using dotnet sitecore login
  • Install the plugin using dotnet sitecore plugin add -n SitecorePlugin.Custom and plugin will be installed in your workstation. 

You can refer our Hackathon submission here.  

30 May, 2022

Download multiple media files from various folders through Sitecore PowerShell

Sitecore PowerShell has a way to retrieve a media item from media library. Send-File. You pass the ID or the path of media item and file will be downloaded using Send-File command. 

PS master:\> Get-Item "master:/media library/Logo/Blog" | Send-File -Message "Blog"

In order to download all the media items from a folder, SPE has a script out of the box in the context menu. Select the folder --> Scripts --> Download. This will download all the media items, zip it and download it. Please note that the space in the file name will be replace with %20. 

We had a requirement where we need to download a list of media items from various folders. We had the list of media item path and ID in a CSV. If we loop through each ID and trigger Send-File, PowerShell should prompt a window for each file to download the file. Since we had more than 300+ items, clicking download button on each prompt is not a good solution. We used -NoDialog parameter to skip the prompt but Sitecore hangs after the first media download. As per this article, if we pass on the -NoDialog, Sitecore hangs for some reason. 

So we went through the Download script (/sitecore/system/Modules/PowerShell/Script Library/SPE/Maintenance/Media Library Maintenance/Content Editor/Context Menu/Download) which is provided out of the box. We modified to send the list of items to be downloaded via CSV. 

Our CSV had one column with ID as header. Listed all the media items IDs to be downloaded. Below script will retrieve each items based on CSV, zip it using OOTB script and download it. 

09 May, 2022

Empower Content Authors to Copy Final to Shared Layout using a button in Content Editor ribbon

Sometimes Sitecore content authors would like to merge the layout from Final to Shared Layout so that the structure of the page can be common across all the languages. In this article, we can empower the content authors to copy Final to Shared layout themselves using a click of a button in the Content Editor ribbon using Sitecore PowerShell (SPE). 

Step 1: Add Integration Point & Module

With Sitecore PowerShell (SPE), there are multiple integration points available that may be added to modules. In this case, we need to add it as a Chunk in Presentation Ribbon. 
  • Add PowerShell Script Module in Script Library folder with a name. Example: Sample

  • In the newly Sample PowerShell Script Module item, add a Integration Point Libraries. This will open a window to select the integration points. In this dialog, choose Content Editor - Ribbon. This will add the ribbons which are available in this system as Script Library

  • In the Presentation item, add a PowerShell Script Library called Merge Layout. This will be the name of the chunk in the Presentation ribbon. And then add a PowerShell script item called Final to Shared. We can set an icon in the Appearance section of this item to match with the purpose of this button. In this case, we are merging the layout so I chose Arrow merge (/~/icon/office/32x32/arrow_merge.png).

  • In the script body, we can add this simple script to get the current item and then call Merge-Layout command. The Merge-Layout command takes all the layout information stored in the FinalLayout field and merges into the SharedLayout field. The FinalLayout field is reset after the merge completes. This will be done only in the current language. In case if other languages are having final layout, additional script should be added to remove the Final Renderings field values in other languages. 

  • We can add Show Rule as "Where the item has a layout". We can also add Enable Rule to be specific to ACL of the project. For non-admins to use this button, I suggest to add whether the item is locked and locked by me. This will let the non-admins to run this script without any issues. 
  • In order to remove all the empty Ribbon libraries, go to Sample PowerShell Script Module item, right click, scripts, Purge Empty Libraries. This will remove all the empty Script Libraries. 

Step 2: Sync with Core database

Some integrations need to be synced with the Core database through the PowerShell ISE. 
  1. Open Sitecore PowerShell ISE from Launch Page. 
  2. Go to Settings Ribbon, Rebuild All button, Sync Library with Content Editor Ribbon. This will sync the newly created integration to sync with Core database. 

Since there are Show and Enable rule, if the selected item matches the rules, then button will show in the Presentation tab and we can merge the layout from Final to Shared layout by clicking the button. 

29 April, 2022

Shared Fields & Publish Related Items - Possible Impact

Shared fields (includes Shared Layout) and Publish related items may lead to unexpected results to the content in target database.  

First, let's talk about Shared Fields.

  1. Shared fields are shared by all versions in all languages.
  2. Shared field changes will be published even though the latest version of the item is not in final workflow state. 
  3. Shared field values cannot be staged in a draft workflow state unless we use publishing restrictions. 
  1. Item has a Shared field of type checkbox. Version 1 of the item has this field checked. 
  2. Version 1 is approved and published. 
  3. User creates Version 2 and it is in draft state. User updates the Shared field checkbox to unchecked. 
  4. Keeping the item in draft state, user publish the item and Sitecore will complain that the version is not in final state so it will publish the Version 1 instead. 
  5. Version 1 will be published along with the Shared field checkbox changes (unchecked).

It is known and expected that Sitecore will publish the Shared field changes along with the previously approved item version.

Second, let's talk about the publish related items. 


    1. Site has two languages: English and German. 
    2. All the items have 1 language version each and they are approved and published.
    3. Content author A creates a new version (draft state) in SiteHome item and updates the Shared field from unchecked to checked. Also added a component in Shared Layout so that it is applicable for all the languages. 
    4. Content author B adds Blog item as a link in the CTA item and publishes CTA item with publish related items option. Deep scan is disabled in the configuration. 

    List of items which are published by Sitecore:
    Publishing Item: {AF584191-45C9-4201-8740-5409F4CF8BDD} Skipped /sitecore/system/Languages/en
    Publishing Item: {F68F13A6-3395-426A-B9A1-FA2DC60D94EB} Skipped /sitecore/templates/System/Language
    Publishing Item: {15D7E7A7-36CF-4FE4-938D-229098EDD7E4} Skipped /sitecore/templates/System/Language/Data
    Publishing Item: {49E5E8F3-ED4A-4A06-ABE1-B9408951DEE9} Skipped /sitecore/templates/System/Language/Data/Charset
    Publishing Item: {990596CE-0024-43F3-BF4C-A991BFA69B45} Skipped /sitecore/templates/System/Language/Data/Code page
    Publishing Item: {60669E54-7B9C-4B55-A0C4-8F25059D8B94} Skipped /sitecore/templates/System/Language/Data/Dictionary
    Publishing Item: {8728D8FF-66D9-40C2-8B34-C4FC1466942E} Skipped /sitecore/templates/System/Language/Data/Encoding
    Publishing Item: {892975AC-496F-4AC9-8826-087095C68E1D} Skipped /sitecore/templates/System/Language/Data/Fallback Language
    Publishing Item: {C437E416-8948-427D-A982-8ED37AE3F553} Skipped /sitecore/templates/System/Language/Data/Iso
    Publishing Item: {0620F810-9294-4F14-AF9F-F5772EFCA0B2} Skipped /sitecore/templates/System/Language/Data/Regional Iso Code
    Publishing Item: {BB50A232-0C2C-48E5-B291-A8DA2ACCB8FE} Updated /sitecore/content/Home/SiteHome/Page 1/CTA
    Publishing Item: {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Skipped /sitecore/content/Home
    Publishing Item: {77FAC5E0-CE1B-4707-994B-1B36304A1E82} Updated /sitecore/content/Home/SiteHome
    Publishing Item: {7C63C8F3-28D4-4CCC-9EEC-915CB1931492} Skipped /sitecore/content/Home/SiteHome/Page 2
    Publishing Item: {8749DC20-2620-4211-A3A8-A6F3B872B8DD} Skipped /sitecore/content/Home/SiteHome/Page 2/Blog
    Publishing Item: {AE76A034-9491-4B83-99F5-39F227D6FB59} Skipped /sitecore/templates/Sample/Sample Item/Data
    Publishing Item: {75577384-3C97-45DA-A847-81B00500E250} Skipped /sitecore/templates/Sample/Sample Item/Data/Title
    Publishing Item: {2AC61A5A-016B-4EF4-AD27-F7C2837937CC} Skipped /sitecore/templates/Sample/Sample Item/Data/Flag
    Publishing Item: {A60ACD61-A6DB-4182-8329-C957982CEC74} Skipped /sitecore/templates/Sample/Sample Item/Data/Text
    Looking at the above list, these three items are included for a reason. 

    Skipped:  /sitecore/content/Home
    Updated: /sitecore/content/Home/SiteHome
    Skipped:  /sitecore/content/Home/SiteHome/Page 2

    The Blog item is a related item for CTA item. In order to publish the related item "Blog", Sitecore parse the parent items till the Sitecore's root item (/sitecore), publish it first and then publish the Blog item. 

    Reason: In order to maintain the same content tree in the target database, Sitecore publishes every parent items of related item before publishing the related item. 


    The SiteHome item (version 2) which is in draft and has changes to a Shared field and the Shared Layout (__Renderings) are also published though it is not ready to be published. Sitecore publishes version 1 with Shared field changes to Target database.

    Any out of the box configuration? 

    Reached out to a Sitecore MVP and also raised Sitecore support to see if there is an out of the box option to skip these parent items if the target database already has the same content tree. There is no configuration available to skip these items. Sitecore support also agree that if the content tree is same in target database, there is no reason to publish these parent items and unnecessarily publish these staged shared field changes. 

    Sitecore support registered a feature request to change the default Sitecore behavior that can cause problems at the site by publishing changes that are not in the final workflow state so that it can be considered for future implementation and provided a reference number. 

    Possible approach to fix this issue:

    We can customize the <getItemReferences> pipeline to add a logic to allow a parent of related items to be published if it isn’t present in the target database. The processor "GetItemReferencesProcessor" can be tweaked to prevent publishing the parent items of the related item if the content tree matches with the source database. There will be a significant impact to the publish performance. I will create another blog once I have a working prototype with this implementation. 

    Comment if you have any thoughts on this article. 

    blockquote { margin: 0; } blockquote p { padding: 15px; background: #eee; border-radius: 5px; } blockquote p::before { content: '\201C'; } blockquote p::after { content: '\201D'; }