App settings in environment variables in Sitecore.

Creating back-end integrations is inevitably linked with having to authenticate against a remote endpoint. Be that a Rest API, FTP or an APM – secrets (credentials, api tokent, shared secrets) of some sort will be involved in the process.

Those credentials must be stored somewhere. At this point I hope no one even considers hardcoding those but even if you extract them to configuration – having them exposed in your repository may be a bad idea and is frowned upon by tools like SonarQube.

You would be encouraged to access those secrets by having them anchored against web.config appSettings section such as:

<appSettings>
  <add key="EmailReminder.FromAddress" value="[email protected]" />
  <add key="Foundation.RemoteApi.AccessKey" value="" />
  ...
</appSettings>

This is because you can easily and conveniently edit such settings in Azure portal. Arguably you could also do this using connection strings, but those are not full connection strings we’re dealing with…

You cannot keep them in a dev only patch file as this section is not patchable with standard Sitecore practices… So for a long time, we just kept empty placeholders this list in web.config and when you needed to work with a specific integration point you scrambled to find the credentials and struggled with them being wiped when the project was published.

This is handled elegantly in .Net Core OOTB as they can cascade from environment variables, but somehow despite decades of aggregated Sitecore experience in the team we just kept doing it.

Yesterday morning something in me broke… I’ve had enough! Decided that we need a proper reusable solution that would not be harder than sharing a file with the necessary secrets between developers.

I sat down with the intention of writing something that would just let me use environment variables. This way we still don’t have to store them in the repository, and they don’t get wiped when an app is republished (akin to how it works in Azure.

Let’s see what we’re dealing with…

So the xml had some AppSettings builder OOTB that maybe I could reuse/inherit in some capacity…

<appSettings configBuilders="SitecoreAppSettingsBuilder">
  <add key="EmailReminder.FromAddress" value="[email protected]" />
...
</appSettings>

SitecoreAppSettingsBuilder looked curiously like what I wanted to do…

  <configSections>
    <section name="sitecore" type="Sitecore.Configuration.RuleBasedConfigReader, Sitecore.Kernel" />
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging" />
    <section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
  </configSections>
  <configBuilders>
    <builders>
      <add name="SitecoreAppSettingsBuilder" mode="Strict" prefix="SITECORE_APPSETTINGS_" stripPrefix="true" type="Sitecore.Configuration.FlexibleEnvironmentConfigBuilder, Sitecore.Kernel" />
      <add name="SitecoreConnectionStringsBuilder" mode="Strict" prefix="SITECORE_CONNECTIONSTRINGS_" stripPrefix="true" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment, Version=1.0.0.0, Culture=neutral" />
    </builders>
  </configBuilders>

I started investigating the classes, which looked intriguing, something didn?t feel right. Then it struck me?Sitecore already provided all the configuration builders for the job… undocumented…

The least buggy, most hassle-free code is the one you never write

There is no code to write here, when dealing with app settings defined in the main web.config <appSettings> section (not patchable by the usual sitecore Sitecore-specific configs), such as:

<add key="Foundation.RemoteApi.AccessKey" value="" />

We can use environment variables with a prefix SITECORE_APPSETTINGS_. For instance, the setting above could be stored in the following environment variable:

SITECORE_APPSETTINGS_Foundation.RemoteApi.AccessKey

Handling Environment Variables in IIS

Since environment variables are fixed at application startup, you can?t use a newly modified variable immediately. Unfortunately, even recycling the application wasn?t enough in my case. I had restart IIS for them to take:

iisreset /stop
iisreset /start

Automating the Process

To streamline this, I created short PowerShell script that globally sets all required variables. Here are some key points about the script:

  • No repo storage: This script isn?t stored in the repository, but we can share it securely via direct messaging or other private channels.
  • Elevated privileges: If you run it without admin rights, it will prompt you for confirmation and relaunch itself with elevated privileges.
  • Environment-specific values: The script can easily be populated by keys we store in Azure app settings.
  • IIS restart: It handles the IIS restart automatically.

Checking App Settings in Sitecore

To verify the value of an appSetting in Sitecore, open Sitecore Desktop, launch PowerShell ISE, and run the following one-liner, replacing the variable name with the one you want to check:

[System.Web.Configuration.WebConfigurationManager]::AppSettings["Foundation.RemoteApi.AccessKey"]

PowerShell Script: Simplified and Ready

Below is the script I mentioned earlier:

# Check if the script is running as Administrator
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Host "The script is not running with administrative privileges. Relaunching as Administrator..."
    
    # Get the current script's full path
    $scriptPath = $MyInvocation.MyCommand.Path

    # Create a new PowerShell process as Administrator
    Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`"" -Verb RunAs

    # Exit the current non-admin script
    exit
}

# Code below runs with administrative privileges
Write-Host "Script is running with administrative privileges."

function Set-SitecoreAppSetting {
    [CmdletBinding()]
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string]$VariableName,
        
        [Parameter(Position=1, Mandatory=$true)]
        [string]$VariableValue
    )
    process {
        Write-Host "Setting variable `"SITECORE_APPSETTINGS_$VariableName`" to value `"$VariableValue`""
       [System.Environment]::SetEnvironmentVariable("SITECORE_APPSETTINGS_$VariableName", $VariableValue, [System.EnvironmentVariableTarget]::Machine)
    }
}

# store your variables below - to speed up onboarding your colleagues...

Set-SitecoreAppSetting "VariableName1" 'VariableValue1'
Set-SitecoreAppSetting "VariableName2" 'VariableValue2'

Conclusion

This approach eliminates the need for any custom code while leveraging Sitecore?s built-in capabilities. The PowerShell script provides a clean way to manage environment variables without hardcoding sensitive details, and it ensures a consistent setup across the team. I hope this solution simplifies your workflow as much as it has mine!

Posted in Uncategorized
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...
| Leave a Comment »

shoot_out_of_cannon_400_clr_13993In one of my previous posts I described how to create reports in Sitecore PowerShell Extensions (SPE for short) that allow you to leverage the joint power of Sitecore and PowerShell to deliver complete and elegant reports in little to no time. In this post I?ll tell you how to take this a step further and operationalize them into full blown Sitecore Desktop applications.

The secret sauce is in the actions you can place on the report, the additional parameters that I haven?t mentioned in the previous post, and the use of Sitecore rules engine with some rules that come with SPE.

For the purpose of this post I will limit the scripts to samples that are (mostly) in the vanilla SPE deployment.

Let?s begin with describing the actions and how you can configure them to appear in your reports.

What are report actions?

Actions are simply commands powered by scripts and with visibility dependent on certain conditions like the .Net class of the object that is displayed or perhaps other session settings.

Action Scripts

You define an action as a script located in an SPE script library and appears in the Actions panel. In the simplest scenario the action would appear when the script library name matches the .Net class name of the items displayed. In the above scenario the actions are placed under /Platform/Internal/List View/Ribbon/Item/ where Platform is the module and Item is a script library. Let?s take a look at the script here /Platform/Internal/List View/Ribbon/Item/Open Read the rest of this article »

PS_watchdog2

So I?ve finally found a moment (well a few days actually) to follow up on the previous article, and just about time as there are quite a few more tricks that PowerShell can help you with when assessing the quality of your Sitecore solution.

One thing that you need to keep in mind when reading the recommendations is that they are exactly that ? recommendations. While Sitecore strongly encourages you that you follow them ? I can see how most of those are perfectly fine to be ditched in some situations, you just need to be careful about picking those situations. By the general rule of thumb though, following vendor recommendations is a good thing and they are usually a good metrics of a well put together solution. Most of statistics provided in this post are hard to gather without a scripting solution like Sitecore PowerShell Console or Revolver.

Measurement is the first step that leads to control and eventually to improvement. If you can?t measure something, you can?t understand it. If you can?t understand it, you can?t control it. If you can?t control it, you can?t improve it

Dr. H. James Harrington

By no means this is the final list of assessments, those are simply the most straightforward translations of Sitecore recommendations into PowerShell reports. Most of those reports does not give you a simple Yes/No answer on whether your solution is in a good shape or not. But they give you the solution statistics that you can analyse further to improve. It?s worth mentioning that most of the scripts you will be able to find in the upcoming version of the PowerShell Console in a ready-to-reuse ?Solution Audit? library of scripts. Scripts in this post  are simplified (to make them easier to understand, apply and re-use) versions of the scripts found in that library.

ScriptLibrary

Ok so let?s start with what you came here for?. the recommendations!

Templates and _Standard Values

Image Fields ? Define the source field to show the point in the media library that is relevant to the item being created.

Which we can get an outlook of with this little script (run in context of /sitecore/templates/my site templates/):

Get-ChildItem -recurse | `
  Where-Object { $_.TemplateName -eq "Template Field" `
                 -and $_.Type -eq "Image" } | `
  Format-Table -auto ItemPath, Name, _Source

What it will show you is the list of all fields of type ?image? and will allow you to see if they have Source defined for them. Just because a source is not there , doesn?t necessarily mean it?s a bad thing. You just need to look at them critically and make sure you cannot narrow their scope to improve your author?s experience.

Another aspect of editing streamlining is having a human readable description on each field:

Use the Help option in the individual field definition items to provide extra information to users about fields. Also consider using the Title field of the definition item to present a different name for the field to the user.

To learn which field does or doesn’t meet the criteria you can execute the following script (run in context of /sitecore/templates/my site templates/):

get-childitem -recurse | `
  where-object { $_.TemplateName -eq "Template Field"} | `
  format-table ItemPath, `
    @{Name="Help Defined"; `
      Expression={$_."__Long description" -ne "" -or `
                  $_."__Short description" -ne "" -or `
                  $_."__Help link" -ne "" }}, `
    @{Name="Title Specified"; `
      Expression={$_.Title -ne "" }} `
    -auto

which will show you all fields in your solution with information whether they define short or long description as well as a human readable title.

Information Architecture (Content Structure)

Sitecore defines a number of recommendations on your content a few of which can benefit from measuring with Powershell. the following is especially important if you want your site to be usable in Content Editor:

Limit the number of items under any given node that share the same parent, to 100 items or less for performance and usability.

A script that will allow you to see if your site is violating the recommendation (or approaching its limit) could look as follows (run in context of /sitecore/content/my site/):

Get-ChildItem -recurse | `
  Select-Object `
    ItemPath, `
    @{Name="ChildrenCount"; Expression={$_.Children.Count;} } | `
  Where-Object { $_.ChildrenCount -gt 50 } | `
  Sort ChildrenCount -descending

The script will show you all pages with 50 or more children. If there is a recommendation that you should be orthodox about ? that?s definitely the one. Should your content structure violate it, your editors will be in a lot of pain because of the site being slow on the back-end!

Similarly on the user experience you can hurt yourself having too many versions defined for any particular page.

Limit the number of versions of any item to the fewest possible. Sitecore recommends keeping 10 or fewer versions on any item, but policy may dictate this to be a higher number.

You can measure the compliance to this recommendation with the following script (run in context of /sitecore/content/my site/):

Get-ChildItem -recurse | `
  Select-Object `
    ItemPath, `
    @{Name="Versions"; Expression={$_.Versions.Count;} } | `
  Where-Object { $_.Versions -gt 10 } | `
  Sort Versions -descending

The result of running the script will be a list of pages with more than 10 versions (sorted from the biggest to the smallest abusers).

The following recommendation deals more with the convenience for your authors, and suggests that you only list the relevant nodes in your tree selectors:

Use the special syntax to restrict the results on Treelists, DropTrees, and TreelistEx to make sure users can only select the appropriate items, or Sitecore query in the other selection fields.

To learn about your solution compliance in this regard you can run the following script (in context of /sitecore/templates/my site templates/):

get-childitem -recurse | `
  where-object { $_.TemplateName -eq "Template Field" } |  `
  where-object { $_.Type -match "Drop" -or 
                 $_.Type -match "Tree" -or 
                 $_.Type -match "list"  } |  `
  format-table 
    @{Name="Template"; 
      Expression={$_.Parent.Parent.Paths.Path 
                    -replace "/Sitecore/templates/", ""}}, 
    Name, Type, _Source -auto

As a result you will see a list of fields with their types and the queries that they will use to populate their available select options. Examine the list carefully to see if you can limit the choices further.

Security (Users and Roles)

Security recommendations are usually tricky ones as you can always find a situation where they won?t meet your scenario but overall from my experience the following two recommendations are definitely worth adhering to:

Break inheritance rather than explicitly deny access rights ? It is a recommended practice to break inheritance in cases where the access right should be denied instead of explicitly denying it for a security account. If you deny an access right explicitly to a security account, the only way to override this denial of access is to do it directly on a user account. This creates an overhead in security management when you would like a user to inherit this role and some other role that should allow the same right access.

The following script (run in context of /sitecore/content/my site/) will show you all items where restrictions have been applied in a deny fashion:

Get-ChildItem -recurse | `
  Where-Object { $_.__Security -match "-item"  -or $_.__Security -match "-field" } |  `
  Format-Table -auto `
    @{Name="Item restricting right"; Expression={$_.ItemPath}}, `
    __Security

The following recommendation is also definitely worth complying to:

Apply security to roles rather than users ? We recommend that you configure security rights for a role security account rather than a user account. Even if there is only one user in the system with this unique access level, it is still better to have permissions configured for a role account. It is much easier to maintain a security system in which all the security configuration is set on role security accounts.

Which you can investigate with the following script (run in context of /sitecore/content/my site/) that will show you all items where rights have been assigned on a user rather than role basis:

Get-ChildItem -recurse | `
  Where-Object { $_.__Security -match "au\|" } |  `
  Format-Table -auto `
    @{Name="Item assigning rights to users"; Expression={$_.ItemPath}}, `
    @{Name="Security setting"; Expression={$_.__Security}}

Presentation

And last but no least ? presentation:

Leverage the presentation component parameters. You could use the parameters to allow users to configure/modify the behavior of the component, for example, the number of items shown in a list, the CSS classes to use, the URL for a feed it is showing, and so on.

? and then again ?

Make sure to create a template for any parameters in the presentation component, and set the Parameters Template Property.

Basically what it means is ? use rendering parameters. Which you can get metrics of by running (in context of /sitecore/layout/sublayouts/):

Get-ChildItem -recurse | `
  where-object { `
    $_.TemplateName -eq "Sublayout" -and  `
    $_."Parameters Template" -eq "" 
  } | `
  Select-Object Name

Now agreed ? not all components necessarily require rendering parameters, but if you?re seeing that all of your presentation parameters are driven by item pointed to from data source or if you find that you have a large number of similar components ? maybe you should think about leveraging the rendering parameters more?

Summary

As said before, by no means this exhausts metrics that you can get from your content using PowerShell, the ones listed are the most obvious and simple to gather. If you have any metrics I?ve missed and you created or if you have other metrics you would be interested to have but you have trouble writing the script for ? by all means let me know! I?d love to include them in the ?Solution Audit? library, so we can all enjoy more responsive Sitecore solutions that delight our clients!

Posted in Uncategorized
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...
| 78 Comments »

PS_detectiveRecently I?ve been asked to audit a site for one of our clients. Overall for a fairly seasoned Sitecore developer it?s rather obvious what to look for in a site and get a feel for whether an a solution is thoroughly thought through or just put together using brute-force development. You can usually tell if the implementation is sloppy or excellent, but how do you quantify that feeling to give the objective view to the person reading your report? Looking at the Sitecore Developer Network I?ve found the following set of recommendations. This is a great help with codifying how a proper Sitecore implementation should look like, what should we pay attention to and most importantly it?s a great reference when you?re trying to prove that your feeling is something more than just nitpicking but rather an industry standard that the developers should adhere to. I recommend strongly that you look at it and think how closely your practices match those that Sitecore recommends.

There is a small problem though. Not all of them are easy to asses, at least not without some clever tools in your toolbox. for example what do I do with a statement like:

Use TreelistEx instead of Treelist when showing very big trees ? like the Home node and its descendants ? or have lots of Treelist fields in one single item. TreelistEx only computes the tree when you click Edit whereas a Treelist will compute it every time it is rendered.

It might be fine in a small site to verify in a few data templates that it?s not violated, but  In my case I was dealing with a multisite platform that can potentially host tens or even hundreds of sites? Going manually over the hundreds of fields in nearly 300 data templates, bah even finding them ? would not be fun or easy thing to do. But hey? we have PowerShell why should I look there if I can whip up a one liner for it? Let?s try it then.

Read the rest of this article »

Posted in Best Practices, C#, CMS UX, PowerShell, Sitecore, Software Development, Solution, Uncategorized
1 Star2 Stars3 Stars4 Stars5 Stars (3 votes, average: 5.00 out of 5)
Loading...
| 58 Comments »

All of the PowerShell blog posts so far were about using the console. Being the developer however, you probably think ? well that’s good for admins, but what?s in it for me? How can I benefit from it in my code? Well you can. With the latest update you can run the PowerShell environment in your application and take advantage of its scripting power, by getting the results out of it and pulling them into your app.

PowerShellPlug

So How do I tap into the PowerShell goodness?

Read the rest of this article »

PowerShell driven Sitecore scheduled tasks

So now that you can easily create the menus and ribbons executing PowerShell scripts, it might be a good time to do some more administrative tasks? let?s start with scheduled tasks. I?m not going to go deep into the task scheduling, you can find an excellent post by John West on his blog regarding task scheduling. Currently the PowerShell module supports one of the ways described in the post ? the section describing how to configure them is called ?Scheduled Tasks? in the blog.

The module comes with an out-of-the-box PowerShell script command as you can see

PowerShellScheduledTaskCommand

You don?t need to create any additional commands, instead you only need to create a script and a schedule for it and the existing command will handle all of them. In my example I wanted to trim all recycle bin items every night.

Let?s get cracking?

Read the rest of this article »

Posted in Uncategorized
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...
| 39 Comments »

Context PowerShell scripts for Sitecore

In the he latest update of PowerShell Console for Sitecore, I?ve started experimenting with further integration ? context scripts. What is that and what can it do for you?

You can safely assume PowerShell is not something your regular users will aspire to learn, but it does not mean they cannot harness its power if you enable them to.

If you look closely at the latest Microsoft solutions you may notice that a lot of what GUI does is running some scripting behind the scenes. This is true for a long time with the SQL Server Management studio where pretty much for any action you can generate a script that will let you automate a common task.

SqlManagementScripting

Similarly but the other way around, with the PowerShell Console for Sitecore, you can attach scripts to the context menu in your item tree.

ContextScripts

Read the rest of this article »

Posted in Uncategorized
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...
| 255 Comments »