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: dist.nuget.org
curl: (6) Could not resolve host: download.microsoft.com
curl: (6) Could not resolve host: aka.ms
curl: (6) Could not resolve host: www.7-zip.org

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:
C:\ProgramData\Docker\config\daemon.json

And adding a new "dns" parameter (pointing to Google's public 8.8.8.8 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 AzureTools.zip 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





Installation

Manual

  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: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_NOT_ENOUGH_DISK_SPACE. 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}.scm.azurewebsites.net.  

For example, if your CM App Service name is
'mysitecoresite-xp2-small-prd1-cm',

the corresponding Kudu site would be:
https://mysitecoresite-xp2-small-prd1-cm.scm.azurewebsites.net/ 

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.

Kudu REST API

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.


Get-SitecoreSupportPackage

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
Web.config


Why?

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.

Usage

Invoke this function using the following syntax:


Output


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



Invoke-SitecoreThumbprintValidation

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.

Why?

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.

Usage

Invoke this function using the following syntax:


Output




Get-SitecoreFileBackup

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
xsl

Why?

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

Usage

Invoke this function using the following syntax:

Output




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.

via GIPHY

😊


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 (https://twitter.com, https://mobile.twitter.com, and https://tweetdeck.twitter.com).

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
- #SUGCON
- #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!  😁

Enjoy!

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:

Diagnosis

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!


Monday, February 18, 2019

Implementing Sitecore Experience Commerce™ 9.0.2 (300) Training Course Overview


Last week, I attended the Implementing Sitecore Experience Commerce™ 9.0.2 (Sitecore Commerce 300) training course with several of my fellow Rightpoint team members led by experienced Sitecore trainer Michael Mavrofrides (always highly recommended).  It was the first official on-site Sitecore training course I've taken in over 5 years and first training course I've taken for Sitecore's Commerce offering.

If you're planning to take the course this year, this quick overview may help clarify what to expect and how to prepare in order to get the most out of your training sessions.

Course Objectives

  1. Discuss the technical features Sitecore Experience Commerce (Shops, Pricing, Catalog, Promotions, Inventory, Fulfillment, Payments, Orders, Shopping Cart, Checkout, Entitlements, BizFX Merchandiser Tool).
  2. Build a storefront using SXA components
  3. Explain the benefits of SXA
  4. Understand plugin architecture and how to extend Sitecore Experience Commerce
  5. Pass a 'quiz' to obtain a Certificate of Training.  (This is not a certification for Commerce, but rather just an overview with ~32 questions covering material from the course)

Course Structure

The course offers 25 hours (4 days) of material which really ties together concepts covered in the Sitecore® Experience Commerce™ 9 100: Overview and Sitecore® Experience Commerce™ 9 200: Essentials eLearning courses.  The training is held onsite - in many cases -a Microsoft training center. 

The material is a combination of presentation slides and student labs. Student Labs consist of material covered during the slides and are completed on a VM provided by the trainer so you won't have to worry about installing anything locally.  Simply make sure you're able to access remote machines using Windows Remote Desktop Manager.

Getting the Most Out of Training

Complete the Prerequisite Courses

Definitely come with the minimum prerequisite courses.  It's important to come into class with a baseline understanding of what Sitecore Commerce has to offer.  If you have any questions from those lower level courses, this class gives you the opportunity to ask a certified Sitecore trainer for any clarification.

Have Exposure (If Possible)

One of our co-workers had a few weeks of real life Sitecore Commerce development exposure and he certainly benefited where the course was able to clarify certain aspects prior. If you have the opportunity to be exposed to commerce development  (specifically Commerce Plugin development and SXA integration), it's a great way to get ahead of the course material and discover things in-flight during training that you may have come across during development.

In any case, you'll still find the course material useful from a conceptual perspective.

Engage in Meaningful Discussion

One of the best ways to learn is to engage in meaningful discussions. Talking through architectural and development concepts that may not make sense right away in plain text will facilitate a better understanding of those concepts.

Our course was filled with Rightpoint developers and architects, so we had an extra advantage to openly discussing any specific questions regarding course material.  During the class, ask questions or clarification at any point to make an effort to understand the material fully. Even specific questions regarding specific scenarios not explicitly covered in the course are not off limits.  This is the time to ask!

Understand the Coding Exercises. 

The student labs have a technical side to them as the course is gear towards "advanced-level course for ASP.NET MVC web developers and solution architects with advanced C# skills". There's an expectation that you're comfortable working within various Windows tools including Visual Studio, IIS, machine certificates, system services, etc. 

Many of the labs require you to create a series of classes to build Commerce Plugin components. Luckily, the labs come with all the code snippets you need to complete each exercise. The downside there is because there's a whole lot of copying pasting, it may be difficult to understand what you're actually doing. 

Take the time to read all the notes within the student lab guide, as well as adding breakpoints/debugging through the code to build a proper understanding.  Ultimately, your Sitecore Commerce development skills will improve with real-world scenarios and repetition, but following the general code structure in the labs will help facilitate those basic building blocks.

Provide Feedback

There were some issues throughout the student labs - whether it was a lapse in steps or terminology confusion.  That's okay! The Sitecore training team is constantly trying to improve the course for a better experience for the next group.  Issues we ran into may no longer be problematic in future courses due to our feedback. 

Pass any feedback along to make sure future attendees and trainers can handle issues more swiftly.  After the quiz, you'll have the opportunity to provide an assessment of the course and trainer.  This feedback is imperative to improving the course for future students, so be specific and honest!

After the Course

After completing the quiz, you'll get a nice little certification and a code to take the Sitecore Commerce Certification exam (which expires 1 year after the course ends). 


Take the knowledge you learned from the courses and apply them to your Sitecore Commerce projects, and prepare to take the Certification exam by studying/reviewing all the material. If you have any questions after the course, you can always email your trainer.

Goooo Sitecore Commerce, Go!

Monday, February 4, 2019

Quick and Easy Azure PaaS PublishSettings Import to FileZilla with PowerShell

With the advancement of Sitecore on Azure Platform as a Service (PaaS), gone are the days where you remote into a physical or virtual machine. If you need to access the application files, you'll need to download a Publish Profile settings file from the Azure Portal. Just click the button.



The Publish Profile setting file simply an XML file (surprise, surprise) with connection information about the resource - which can be directly imported to Visual Studio to deploy files.   You can manually copy those values from the FTP host endpoint (publishUrl), username (userName), and password (userPWD) nodes into an FTP client and connect.
A standard Sitecore 9 Experience Platform comes packaged with at least 9 Application Services when installed on Azure - each with unique FTP endpoints and credentials.

Our team uses the FileZilla FTP client - in which you can create a set of accessible FTP sites and share them in a locked down repository where other developers who need access can get it without downloading the Publish Profile settings themselves.

As you can imagine, working through 9 unique Publish Profile settings is rather tedious when setting up these 'racks' in FileZilla - copying and pasting via the FileZilla GUI

via GIPHY

To streamline this process when setting up a new instance of Sitecore on PaaS - or onboarding an existing Sitecore PaaS, I've written a Windows PowerShell script that eliminates the need to copy and paste anything.



Simply download each App Service's FTP Publish Profile setting file to a folder on your local machine.


Run the script and select that same folder


The script processes each .PublishSettings file and generates an AzurePaaS-FileZillaSites.xml file in the same directory.  This file is compatible with FileZilla's import feature.


In FileZilla, go to File > Import

Select the script-generated AzurePaaS-FileZilla.xml file.

Click through the Import Settings (Site Manager Entries will already be selected)

You'll get a success message when the import is successful

The entries will be available in FileZilla and ready to connect!


The benefit of this approach allows you to quickly and easily create an XML file that can be shared amongst the team of developers who would need to access those files.

Once you've completed an import, use FileZilla's Site Manager to organize these entries into folders then export it again from FileZilla (this will encrypt the passwords using your FileZilla's master password).




Friday, January 11, 2019

Translating Text in Sitecore using Microsoft Cognitive Services and PowerShell


Microsoft Cognitive Services is an impressive set of powerful, easy to integrate APIs for developers. With AI at its core, Cognitive Services strives to solve business problems using Vision, Speech, Knowledge, Search, and Language service offerings.  Recently announced, it's now easier than ever to start using Cognitive Services with a simplified key mechanism.

Creating a Cognitive Service in Azure itself is dead simple. It take less than 5 minutes to spin up a Cognitive Service resource and you're ready to develop. The above video will help get you started.☝

So, what can we do with these services in Sitecore?

Cognitive Services Is Not That New

We've seen folks across the Sitecore community utilising this technology since its inception in 2016 - specifically the Computer Vision API. From bulk image alt tagging using Computer Vision and PowerShell and automatic image alt tag generation module, to a fully integrated Cognitive Services module from the infamous Mark Stiles.

These are really great adaptations of these APIs, but I wanted to explore these services myself.

Translator Text API

The Translator Text API is easy to integrate in your applications, websites, tools, and solutions. It allows you to add multi-language user experiences in more than 60 languages, and can be used on any hardware platform with any operating system for text-to-text language translation.
The Translator Text API is part of the Azure Cognitive Services API collection of machine learning and AI algorithms in the cloud, and is readily consumable in your development projects.
What is Translator Text API?

Being completely obsessed with PowerShell, I figured I'd give it a go.  For my demo, I want to allow content authors to right-click on a Sitecore item, select a Translate Text Fields PowerShell script, configure some option in a dialog and click Continue.



The script should create a new language version in the target language selected and translate all text fields selected.

Pricing

Before starting, it should be noted that the Free tier for translations is 2 million characters per month. 
Since we're keeping this integration simple, it's not likely we'll hit the limit.



Let's Script It

Building the dialog is pretty straightforward. Get the context item, grab the applicable languages and fields (Single-Line and Multi-Line only for simplicity and API restriction avoidance), and set the dialog options:

We'll need a function that we can call to process the item after obtaining the selections from the dialog.  We expect to call it like this:

Translate-Item -TargetItem $item -FromLang $selectedFromLanguage -ToLang $selectedToLanguage -FieldsList $fieldSelectionArray

The function should issue an authentication token from the Cognitive Service, generate a new language version for the item in the target language, and call another function to translate the original field value to the target language:

The Issue-CognitiveApiToken in the above function issues the authentication token we need to send with our request to the translation API.

We can send a request to the translation API with the issued token in a new function that will be responsible for processing the actual translation:

Putting It All Together

Now that we've got commands to interact with the Translation API, we can build out the contextual PowerShell script to provide some options for our content author.

Adding this script to one of the Context Menu (PowerShell Script Library) folders (eg. /sitecore/system/Modules/PowerShell/Script Library/SPE/Core/Platform/Content Editor/Context Menu) will allow the script to be executed contextually.


Final Result


I can see this being a good use-case for Dictionary items specifically as there are some restrictions for content length size that the API will reject.  However, this is simply a demo of what is possible here (definitely not production-ready 🀪).



Feel free to take and use any part of the script here and build something cool!