Wednesday, October 23, 2019

Sitecore Docker Setup; "curl: (6) Could not resolve host"

Given the general Docker hype and the clear signals that as an industry containerization adoption will continue becoming more widespread, I decided to take Docker for another spin after several years ignoring it completely and begin fiddling with Sitecore Docker Images.

Sticking closely to the quick start guide on the community-driven Sitecore Docker Images repository - I ran into one snag:

curl: (6) Could not resolve host:
curl: (6) Could not resolve host:
curl: (6) Could not resolve host:
curl: (6) Could not resolve host:

The \docker-images\windows\9.0.2\sitecore-assets\Dockerfile itself only confirmed that a simple curl command initializes the download process from several hard-coded sources:

After some Googling, I found a post - Fix Docker's networking DNS config -by @nottrobin which outlined a similar error.

The key takeaway: this happens "usually because DNS lookups are failing in Docker images".

Their recommendation is to "change the DNS settings of the Docker daemon" by adding a new configuration file to /etc/docker/daemon.json - which I couldn't find.  Given that I'm using a Windows 10 machine and @nottrobin was using Linux, my guess is that there are path differences here. 

I ended up modifying the following file:

And adding a new "dns" parameter (pointing to Google's public DNS)

After saving and restarting Docker, the 'Could not resolve host' error no longer killed the build process. 🥳

Thursday, September 5, 2019

Azure Application Insights: Logs & Requests Viewer using Sitecore PowerShell Extensions

Last September, I wrote about accessing Sitecore Logs from Azure PaaS instances using the (now deprecated) AzureAILogs.html file provided by Sitecore. The knowledgebase article was updated in mid-January , 2019 – and the AzureAILogs.html file had been replaced with a new /sitecore/admin page dubbed AzureTools.aspx.

This updated admin page contains all the same functionality found in the AzureAILogs.html, with the addition of being able to pull log traces and requests from Application Insights.

Installation is easy: download the files, drop in the /sitecore/admin/AzureAILogs.aspx into the you’re your site’s root.

Admittedly, this admin page is great - but I could also see several aspects SPE being particularly useful (like the OOB SPE ListView - which would easily allow us to filter/sort/search through a series of log entries). An additional option to see raw color-coded logs would also be cool. 😊

Using the existing AzureTools.aspx as a general guide, we can re-create the GUI with general ease.

We’ll need:
1) Option to get Requests or Logs
2) Option to selected a Role (values pulled from API)
3) Option to control recency.
4) Option to control the severity.

The end result will consume the Application Insights REST API endpoints and allow a user to pull logs from Application Insights inside the CMS.

API Access

To start, we'll need to make sure we can work with the API by obtaining an Application Insights App ID and a corresponding App Insights API key  Sitecore's documentation already lists the.

Sitecore's documentation covers this but it's as simple as logging into Azure Portal and navigating to your Application Insights service. 

Under Configure, select 'API Access':

The Application Insights App ID will be displayed the following screen:

Copy this value and store it temporarily.

Click the 'Create API Key' button.
Give it a name and check the 'Read telemetry' checkbox.

After clicking 'Generate key', you'll have one opportunity to copy the 'App Insights API key'.  Copy and store this value temporarily.

Initial Communication with the API

Our script will utilize the two values to interact with the API.

Before building our UI in SPE, we'll need to confirm API communication by obtaining the server roles from Application Insights.  We can set a variable to call a function that will grab an ArrayList of roles:

Our function will build the URL, include the property URL authorization header containing the API key, and return an array list.

User Interface

Now that we have confirmed communication to the API and obtained our list of roles, we can pass the variable into a new function that will be responsible for building and displaying the UI:

The dialog should contain a series of radio buttons and checkbox lists, all of which will be used to provide options to build out another API call to obtain the traces or requests from AppInsights.

The output displays as follows:

Notice line 51 in the above snippet calls a Get-LogsOrRequests function which accepts a series of parameters from the dialog options upon selecting the OK button.

This function builds out the proper API URL and query parameters based on the passed the selected values passed in. Invoke-WebRequest is used to make the call to the API, which will return a JSON object of log entries from AppInsights based on those parameters.

Line 119 contains a final call to a function called 'Set-PostDialog' which provides options for displaying the results.

The output here is a ModalDialog with three buttons:

Selecting 'Script View' will display the results of the API in a color-coded Show-Result window:

Selecting 'List View' will process the results to an acceptable format for a standard SPE ListView result window (filtering, exporting, etc is obviously all included here):

Finally, selecting the 'Download' button will download a .txt file of the contents retrieved from the API.

Final Script



  1. Create a new Sitecore item based on the SPE PowerShell Script template and copy the final script above into the Script Body field.
  2. Replace the default "XXXXXXXXXXXXXXXXXXXXXXXXX" placeholder values in the $aiAppID and $apiKey variables with your own.  

Sitecore Package

  1. Download the Sitecore package and install from GitHub.
  2. Navigate to the PowerShell script located here:
    /sitecore/system/Modules/PowerShell/Script Library/Azure Application Insights Logs/Toolbox/Azure Application Insights Logs
  3. Replace the default "XXXXXXXXXXXXXXXXXXXXXXXXX" placeholder values in the $aiAppID and $apiKey variables with your own.  
The script will be available to run from the PowerShell Toolbox in the Start Menu.

Source Code

The full script can also be found on GitHub.
Feel free to grab a copy and modify it how you see fit.  

Thursday, July 11, 2019

Azure Search 1,000 Field Limit: Generating Values for AddIncludedField using PowerShell

If Azure Search is set up as your search provider, you're probably already aware of the limitations that come with it. One common issue you may discover (even well after your initial launch) is the limit on the number of fields Azure Search allows - a maximum of 1,000 fields.

In our case, after a major feature implementation and the introduction of a new site into our solution, the following log errors surfaced during the index rebuild process:

Exception: Sitecore.ContentSearch.Azure.Http.Exceptions.AzureSearchServiceRESTCallException Message: {"error":{"code":"","message":"The request is invalid. Details: definition : Invalid index: The index contains 1001 leaf fields (fields of a non-complex type). An index can have at most 1000 leaf fields.\r\n"}} 
The rebuild would get stuck and not budge.  This has been documented.

In our case, the <indexAllFields> property was set to true (which is the default value) causing the index field count to exceed the limit.

For the web and master index, there are two ways to work around this limitation within the Sitecore.ContentSearch.Azure.DefaultIndexConfiguration.config or overriding patch file:
  1. Set <indexAllFields> to false - then includethe fields which are necessary in the <include hint="list:AddIncludedField"> section.
  2.  Set <indexAllFields> to true and then exclude the fields which are unnecessary in the <exclude hint="list:AddExcludedField"> section. 

I like the first option.

We initially attempted to manually create all fields we believed were needed for our custom search services. This turned out to be rather tedious - and left a lot of room for error had we missed a field.

To quickly and easily identify all custom fields to include in the AddIncludedField section, I put together this super simple Sitecore PowerShell Extensions snippet:

Notice the path to the User Defined folder.  If you run this to include all custom fields with the query above as-is, you may run into the same 1,000 field limit error.  You can simply change the path and run this multiple times (or build a script out of it) to generate sections in bulk for templates that make sense for your specific solution.

The output can be simply copied and pasted into the AddIncludedField section of the Sitecore.ContentSearch.Azure.DefaultIndexConfiguration.config file:

The index should be able to rebuild successfully with all the custom fields present.
If you need to trim the index further, you should be able to determine your exclusions with a bit more granularity knowing that you haven't missed anything.

Happy Indexing! 🚀

Wednesday, June 12, 2019

Azure App Service Deployment Error: There is not enough space on the disk.

I recently came across an error during a deployment to one of our Content Delivery App Service instances - stopping the deployment process dead in its tracks. 

The error occurred when deploying to the CD Slot:

This occurred each time we attempted to deploy this step.

The error in full does indicate troubleshooting codes and links (oddly enough, the Microsoft link did not have any trace of the error code):
Failed to deploy web package to App Service. Error Code: ERROR_NOT_ENOUGH_DISK_SPACE More Information: Web Deploy detected insufficient space on disk. Learn more at: Error: The error code was 0x80070070.

I found it especially strange given that we saw no indication that we've hit any limit on storage space in Azure Portal.  Initially, I thought it may have something to do with storage on the build server, but was able to quickly rule out this theory by verifying that there was plenty of disk space remaining on that machine.

The error was also evident when I attempted to upload any file directly via FTP:

I began a look for some giant file(s) that may be preventing any additional files from being uploaded (since that's what made the most sense given the context of the error message itself).

By logging into the App Service via FTP, I was able to identify two IIS memory dumps located in the /LogFiles directory.  These both appear to have been taken the month prior - and simply never removed. 

After deleting both memory dump directories, I was able to restart the deployment step - which completed without errors. Direct FTP uploads were also restored.

What's up with that?

Well, your Azure App Services is tied to a particular pricing tier that dictates storage, memory, ACU, etc.  In our case, this particular App Services is configured to use the Standard standard tier - which has a 50GB limit.

By leaving the remnants of these IIS memory dumps on the App Service's storage, we must have surpassed that storage limit.

This brings up some interesting questions:

First, based on the configured pricing tier, is there a limit on how much Sitecore can store in App_Data/MediaCache or /temp folders before hitting that cap?

I assume the answer to that is yes - if your application is not setup to periodically clean stale files (which it should by default), it's possible to reach that storage limit and cause this error to surface.  In that case, the quick fix to get your deployment out would be to remove some or all temp files in the application.

Second, how can we monitor this storage limit of App Services in Azure Portal?

I'll have to circle back on this one as I don't quite have the answer to it.  It may even already exist, and I just haven't spotted it yet.   I'll update this post if I do figure that one out, but please let me know if you have the answer in the comments!

Monday, April 29, 2019

Sitecore Azure Kudu Tools PowerShell Module

I've managed to start several blog post drafts with the intention of sharing a few of my PowerShell scripts - but haven't got around to finishing/posting any of them.

This actually led to an epiphany: the scripts I wanted to share all had an underlying theme: obtaining files using the Kudu Rest API using PowerShell.

Huh? Kudu?

Aw, a baby Kudu!

If you don't already know, Kudu is the "engine behind git deployments" in Azure App Service - but can also be used as a built-in diagnostics tool within Azure.   Any time you have an Azure website, you automatically get a 'companion' Kudu (aka SCM) site accessible via the following URL format:  https://{ResourceName}  

For example, if your CM App Service name is

the corresponding Kudu site would be: 

If you've ever had to Rebuild the xDB index in Azure Search, Sitecore's documentation walks you through how to do so using the Kudu Debug console.


One of my favorite feature of Kudu is the Kudu REST API since any files you can access via FTP are also accessible via the Kudu REST API.   You can download files, upload new ones, etc.

Typically, all you need are:
  1. Subscription ID
  2. Resource Group Name
  3. Resource Name
In Azure Portal - you can copy these values from a resource in the overview panel:

Those values are the key to interact with the API using PowerShell's Invoke-RestMethod.
There are a couple prerequisites:
  1. Azure RM module installed and ConnectAccount has been executed.
  2. Valid Azure credentials (same ones used to log into Azure Portal) to invoke Login-AzureRmAccount (converted to Base64)

Sitecore Azure Kudu Tools

I'd never written a PowerShell Module, but I figured this would be a great segway to learning how. I got to reading -- and tinkering -- and refactoring.  

Before long I had written my first PowerShell Module: Sitecore Azure Kudu Tools.

Sitecore Azure Kudu Tools is a collection of functions (three at the time of this post) built to help you get information/files from Sitecore instances on hosted on Azure PaaS using the Kudu Rest API.

It's available on the PowerShell Gallery or check out the GitHub repository.


Allows you to remotely generate a Sitecore Support Package.  The function will download files defined for Sitecore Support Packages into a specified path, obfuscate sensitive data from ConnectionStrings.config, and compress the contents:

\App_Config\* Global.asax
\Logs\* license.xml
eventlog.xml sitecore.version.xml


While there's a built-in way to obtain Sitecore Support Packages in Sitecore's admin page, being able to remotely obtain this information is a nice alternative.  This is useful not only for providing the required information for Sitecore Support tickets - but also for your own diagnostics.


Invoke this function using the following syntax:


Alternatively, if you just run Get-SitecoreSupportPackage without any parameters, you'll be prompted to provide each required parameter.


Provides a way to verify that certificate thumbprints match across Sitecore Azure PaaS Resource Group.  The function will download ConnectionStrings.config and AppSettings.config files from all App Services in a given Resource Group, then display any certificate thumbprints discrepancies.


If you've ever had to replace thumbprint values across an Azure PaaS Sitecore topology, you know that it can be a bit of a pain identifying all the configs where the old thumbprint needs to be replaced.

Bram Stoop wrote a great post identifying all the places you'll need to modify those thumbprints.  If you're looking to semi-automate this process, you can utilize the Kudu REST API to get all the configurations, then identify any mismatched thumbprint values using PowerShell.


Invoke this function using the following syntax:



Allows you to a full copy of an App Service's website file contents.  This function will download all files from in a given ResourceName.

The following folders are excluded:
_DEV sitecore modules
App_Data sitecore_files
App_Browsers temp
sitecore upload


Sometimes I just want everything. If I need to determine discrepancies between environments for any reason, this helps.


Invoke this function using the following syntax:


What's Next?

Now that the module is established, I've created a few GitHub Issues which I hope to get through quickly.  I also plan to add more functions in the future and am 100% open to contributions. 

Is it perfect? Far from it! It's a work in progress. Thrilled to share anyway.

If you're interested in contributing, please check out the contribute section on the Github repo.



Friday, March 29, 2019

Sitecore Twitter Hashflags

One of my favorite mediums into the Sitecore community is Twitter.  It's a place where you can interact with other Sitecore enthusiasts, promote your blog content / events, and have meaningful discussions about our favorite CMS.   It reveals how tight-knit our community really is.  If you're not already part of it, it's never too late to join!  😎

If you are active on Twitter, you've probably seen them.  Those little images that are embedded after specific hashtags are used.  Those are 'hashflags' and they've been around for almost a decade.

According to Wikipedia:
In 2010, Twitter introduced "hashflags" during the 2010 World Cup in South Africa. They reintroduced the feature on June 10, 2014, in time for the 2014 World Cup in Brazil, and then again on April 10, 2015, with UK political party logos for the 2015 UK General Election.
Since the first hashflag in 2010, 1,300+ active hasflags are available for use (1,309 at the time of this post - an unofficial running list can be found here)

Given that none of the Twitter-provided hashflags have anything available for Sitecore-related hastags (#Sitecore for example), I figured there is certainly a way we can include.

And thus, the Sitecore Twitter Hashflag Google Chrome Extension was born!

The extension runs only on specified Twitter domains (,, and

A loop is configured to discover hashtags in a defined array of strings and replaces some HTML to include embedded images.  If you have the extension installed, it will inject any applicable hashtag to also include a hashflag.

The extension currently supports the following:
- #Sitecore
- #SitecoreMVP
- #SitecoreJSS
- #SCHackathon
- #WomenOfSitecore
- #SPE
- #Coveo
- #SitecoreSYM
- #SXA

The repository is open source and open to contributions here.

This project is just for fun with a hope to encourage the use of Sitecore hashtags.
It's okay to have fun!  😁


Friday, February 22, 2019

Redis Dead Redemption: Redis Cache Timeouts with Sitecore Azure PaaS

Our production CD environments (v9.0 Initial Release) began experiencing significant performance issues to the point where the application kept restarting our site would hang for several minutes at a time.  When the site finally came to, a few minutes later, it'd go right back down.

With the site having been stable for months, it was odd that this issue surfaced out of the blue.

Our logs revealed the following error (one of many):

What is Redis? 

In a nutshell, Azure Redis cache is the default, OOB session provider Sitecore 9.0+ for PaaS instances.
I think George Tucker's StackOverflow answer summed it up best:

Sitecore uses this session provider as a means of managing out of process (ie. distributed) session state to share contact data across browser sessions and devices. This is required to support base functionality in Sitecore XP (Analytics, XDB etc). Even if you are using a custom session provider for other purposes, you will likely still need the Sitecore sessions configured to get full value out of the solution.  
Redis is designed as a means for fast, distributed access to a key/value store. If you're digging into the redis instance directly, you're likely to see all of the keys of your current sessions (private and shared) with non-readable values (usually stored as binary vals). These values are usually managed and accessed via the Sitecore Session API abstractions. It's rare you would need to access Redis directly.

 Initial Troubleshooting

We attempted a few things in attempts to re-stabilize the environment.
  1. Standard procedures to restart applications: generally no effect
  2. Ran 'flushdb' command against Redis Console: errors cleared initially, but the issue resurfaced soon after.
  3. Reboot Redis: Site restores, goes down soon after
  4. Scaled up Redis: Site restores - crashes soon after with the same Redis errors
  5. Applied Support fix outlined in KB464570: Redis driver timeout issues to both CM and CD environments.
To no avail, we decided to take it up with the Sitecore Support team. 

Sitecore Support's Take

Based on the reported errors, Sitecore support identified the following
  • - The "in: 7923" parameter means that there is an amount of data in the Redis queue that sill need to be processed
  • - The "WORKER: (Busy=85,Free=32682,Min=150,Max=32767)" shows that there is some pressure on the Redis side (even if it is not visible as the CPU is not stressed)

You can read more into what your specific Redis errors may mean from this handy Microsoft blog bost documentation.

Support sanctioned our use of KB464570: Redis driver timeout issues and also recommended applying solutions outlined in a separate KB article: KB858026: Excessive load on ASP.NET Session State store.

Additional suggestions included:
- Scale up the Redis instance.  "You may need extra resources to process all the items  "in: 7923")"
- Increase the timeout until you could see the application running.

Among several solutions offered in KB858026: Excessive load on ASP.NET Session State store. (mostly configuration changes to the Web.config and Sitecore.Analytics.Tracking.config),  one included splitting the Sitecore.Sessions databases into dedicated instances - one for private and another for shared.

Splitting the two databases meant creating a new Redis instance in Azure and use different connections strings for the Shared and Private session definitions.

The documentation articles for adjusting the configuration can be found in two separate documents:


Since the site was stable for months before this began occurring, Support concluded that the most possible cause is that the amount of data in the Redis' queue slowly built up until the CDs could not keep up with the timeouts.
Splitting the sessions into Private and Shared should allow more control over which Redis instance needs more or less processing power and avoid obscure locks.  Also, increasing the timeout values to higher values allows the queue more time to process.

The Split

After creating a new Redis instance in Azure:

1) Create a new redis.sessions.shared entry in the ConnectionString.config under the existing redis.sessions entry.
2) Leave the original (Private) <sessionState> Redis provider as-is in the Web.config
3) Replace the existing redis.sessions connectionString parameter to redis.sessions.shared.

A Note on Timeout Values

Regarding the timeout parameters (connectionTimeoutInmillisecondsoperationTimeoutInMillisecondsretryTimeoutInMilliseconds) there is no exact value to set.  Like Sitecore caches, it must be tuned until your instances do not experience timeouts.

Sitecore's rule of thumb here is to:
- double the timeout until you the environment stabilizes
- set a high value (30 minutes) and then adjust it if it needs further tuning

You can find out what each timeout is designed for here: Redis Provider Settings 

After making these changes, the site has since appeared to have stabilized. Of course, we anticipate to further monitor the logs for Redis errors, but for now, it seems we're in the clear.  

Happy Redis-ing!