How to find all Sitecore RichText fields contain scripts inside

One of the customers I was working for recently asked us “Can you find for me all RichText fields that contain scripts and styles tags inside?”. Let’s be honest – in the thousands of items no one could ever done it manually – but with PowerShell you can do that fairly easily.

Here is the script that searches for all fields of “RichText” and then within the usage of indexes tries to find items with these fields containing prohibited values.

$fieldsList = @()
$templatesPaths = @(
    "master:\templates\Branches",
    "master:\templates\Feature",
    "master:\templates\Foundation",
    "master:\templates\Project",
    "master:\templates\User Defined"
    )


ForEach($templatePath in $templatesPaths)
{
    $fieldsList += Get-ChildItem $templatePath -Recurse | Where-Object {
        $_.TemplateID -eq "{455A3E98-A627-4B40-8035-E683A0331AC7}" -and $_.Fields['Type'].Value -eq "Rich Text" -and $_.TemplateID -ne "{0437FEE2-44C9-46A6-ABE9-28858D9FEE8C}" -and $_.TemplateID -ne "{85ADBF5B-E836-4932-A333-FE0F9FA1ED1E}" -and $_.FullPath -notLike "*/System/*" -and $_.FullPath -notLike "*/Experience Accelerator/*" -and $_.FullPath -notLike '*/JSS Experience Accelerator/*' -and $_.FullPath -notLike '*$name*' -and $_.TemplateID -ne "{E269FBB5-3750-427A-9149-7AA950B49301}" -and $_.TemplateID -ne "{A46706F7-EAF8-4575-9860-A85B6F17C5EB}" -and $_.TemplateID -ne "{239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B}" -and $_.Name -ne "__Standard Values"
    }
}

$reportProps = @{
    Title = "Report of RichText fields"
    InfoTitle = "Report of RichText fields containing script and styles inside"
    InfoDescription = "Total entries found: $($itemList.length)"
    PageSize = 25
}

$report = New-Object System.Collections.Generic.List[PSObject]

ForEach ($field in $fieldsList)
{
    Write-Host "Operations on field: "+ $field.FullPath
    $foundPaths = New-Object System.Collections.Generic.List[String]
    $foundIDs = New-Object System.Collections.Generic.List[String]
	
	$foundItems = Find-Item -Index sitecore_master_index -Criteria @{Filter = "Contains"; Field = $field.Name; Value = "script"}, @{Filter = "Contains"; Field = $field.Name; Value = "style"}, @{Filter = "Equals"; Field = "_latestversion"; value = "1"}|Initialize-Item
	ForEach($foundItem in $foundItems)
	{
	    if($foundItem.Fields[$field.Name].Value -like "*<script*" -or $foundItem.Fields[$field.Name].Value -like "*<style*")
	    {
	        $foundPaths.Add($foundItem.FullPath)
	        $foundIDs.Add($foundItem.ID.ToString())
	    }
	}
	#$foundItems| ForEach-Object -Process { $foundPaths.Add($_.FullPath) }
	#$foundItems| ForEach-Object -Process { $foundIDs.Add($_.ID.ToString()) }
	
	$newObject = New-Object PSObject @{__Icon = $field.__Icon; DisplayName = $field.DisplayName; FullPath = $field.FullPath; ID = $field.ID; IDs = ($foundIDs -join "|"); Paths = ($foundPaths -join "|")}
    $report.Add($newObject)
}


$report | Show-ListView @reportProps -Property `
    @{ Label = "Field Name"; Expression = { $_.DisplayName } },
    @{ Label = "Field Path"; Expression = { $_.FullPath} },
    @{ Label = "Field Id"; Expression = { $_.ID } },
    @{ Label = "Items use that field"; Expression = {$_.IDs} },
    @{ Label = "Paths of items using that field"; Expression = { $_.Paths } }
Close-Window

How to find all unused Sitecore Templates?

Recently one of the customers had a need to identify all of the templates that are not in use. We could go through all of the templates manually and verify all the links but with PowerShell we can do that much faster. Here is a script that will generate a report (that you can later download as Excel).

In this report, you will see all the templates and references – then with the help of Excel filtering you can filter out the rows without any references to get the list of unused templates.

$itemList = @()
$allPaths = @(    
    "master:\templates\Feature",
    "master:\templates\Foundation",
    "master:\templates\Project"
    )

ForEach($path in $allPaths)
{
    $itemList += Get-ChildItem $path -Recurse | Where-Object {
        $_.TemplateID -ne "{0437FEE2-44C9-46A6-ABE9-28858D9FEE8C}" -and $_.TemplateID -ne "{85ADBF5B-E836-4932-A333-FE0F9FA1ED1E}" -and $_.FullPath -notLike "*/System/*" -and $_.FullPath -notLike "*/Experience Accelerator/*" -and $_.FullPath -notLike '*/JSS Experience Accelerator/*' -and $_.FullPath -notLike '*$name*' -and $_.TemplateID -ne "{E269FBB5-3750-427A-9149-7AA950B49301}" -and $_.TemplateID -ne "{455A3E98-A627-4B40-8035-E683A0331AC7}" -and $_.TemplateID -ne "{A46706F7-EAF8-4575-9860-A85B6F17C5EB}" -and $_.TemplateID -ne "{239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B}" -and $_.Name -ne "__Standard Values"
    }
}

$reportProps = @{
    Title = "Templates references"
    InfoTitle = "This report shows all references of the templates"
    InfoDescription = "Total entries found: $($itemList.length)"
    PageSize = 25
}

$report = New-Object System.Collections.Generic.List[PSObject]

ForEach ($item in $itemList)
{
    Write-Host "Referrers for "+ $item.FullPath
    $referrers = Get-ItemReferrer -Item $item
    $referrersPaths = New-Object System.Collections.Generic.List[String]
    $referrers| ForEach-Object -Process { $referrersPaths.Add($_.FullPath) }
    
    $newObject = New-Object PSObject @{__Icon = $item.__Icon; DisplayName = $item.DisplayName; FullPath = $item.FullPath; ID = $item.ID; Status = $status; Referrers = ($referrersPaths -join "|")}
    $report.Add($newObject)
}


$report | Show-ListView @reportProps -Property `
    @{ Label = "Item Name"; Expression = { $_.DisplayName } },
    @{ Label = "Path"; Expression = { $_.FullPath} },
    @{ Label = "Id"; Expression = { $_.ID } }
    @{ Label = "Referrers"; Expression = { $_.Referrers } }
Close-Window

From the list of all paths we exclude things like:

  • folders
  • standard values
  • SXA templates
  • system templates
  • and few more

How to get the latest logs from Azure with Kudu

Before I will tell you how I want to describe to you why someone may need to use Kudu to get logs from Azure.

Of course, the best way to work with Sitecore logs (when it is installed as PaaS) is the Application Insights tool. But when it has to be disabled because of many different reasons we are forced to use good old files with logs.

An issue with log files is the fact that when a file is in use we cannot just download it from the server with FTP client because it is locked by IIS process. To access the latest data we must use Kudu tool – but it is not the most efficient way to find and open log file – especially when you have thousands of log files and Kudu does not allow us to sort the files by date to get that one you need.

How to find in Kudu lately updated files?

Let’s start with the opening of PowerShell tool in Kudu

Then by clicking or with command enter the directory with logs files.

cd "D:\home\site\wwwroot\App_Data\logs"

As a result, you will see the list of files with pagination – it means that in case of having thousands of files – to find the file is a nightmare. Thanks to PowerShell console, we can find the name of a file very quickly.

Run the following command to get files modified during last hour:

Get-ChildItem | Where { $_.LastWriteTime -gt (Get-Date).AddHours(-1) }

(you can run two commands at once, just use a semicolon between two of them)

As a result, you will see in a PS console a list of files names:

Now, to get the file you have to use Kudu’s URL (copy it from the browser) – get only a domain, then add the following path to it, with name of your file at the end:

/api/vfs/site/wwwroot/App_Data/logs/nameOfYourFile

In total you should receive something like this:

https://domainWithSCMinIT/api/vfs/site/wwwroot/App_Data/logs/nameOfYourFile.txt

Open it in the browser to get the latest data from the currently used log file.

PowerShell – Stage 2

In this part of PowerShell topic I will show you how to create IIS website and unzip Sitecore into the new site directory.

Set site name

Before we will do a real job we have to define name of our new site. We can ask user in console to set the value. This code will prompt for name:

As result we will have name saved in variable $nameProvidedByUser.

Stop IIS

Because we have to add new ApplicationPool, create new IIS Site, sometimes also override some values in confiugration – it is better to stop our local instance of IIS before we will start.

We can do this with script:

After that definition we have to just call our function with command “IISStop”

Do some real work – define/copy/run

Ok, for now we have defined name and stopped IIS instance. We are ready to do some real work.

Run following command and at the end you will have ready to work IIS site and copied Sitecore files inside web root.

We have here code for:

  • unpacking ZIP files
  • changing the structure of unpacked files
  • creation of IIS AppPool
  • creation of IIS Site
  • creation of settings for bindings


But what exactly this command will do? Here you have explanation.

Inside this block of code we use some functions which were prepared before.

Add host to Windows file

If we want to define new site in our environment we also should add new definition in windows hosts file. We can do this with following script:

Start IIS

Because we have in plan to stop our IIS we also should have a script to start it again.

We can do this with following function:

Select version of Sitecore

Probably you will have more than one version of Sitecore in your files system – it means that would be nice to have an option to select which version of Sitecore should be copied into our web root. We can provide that feature with code:

What’s next?

In next part of PowerShell fun I am going to refactor code and set some settings like:

  • permissions
  • database connection strings

If you want to check how current version works you can checkout (and later also participate) code from my public repository on GitHub : PowerShell-automation

PowerShell – stage 1

I have decided to prepare some PowerShell scripts to automatize my work with Sitecore. In this and next articles with PowerShell in the name, you will find some resolved issues and some useful scripts as well.

The NAME

As you can noticed in the title – I wrote PowerShell not Powershell or powershell or anything else. You should also remember about correct name.

I do not know if you noticed how people very often write Sitecore in the wrong way. I mean examples like “SiteCore” – looks strange right?

That is why we should care about details.

Prepare your system to run PowerShell scripts

After some fun with inline PowerShell scripts you probably will decide to create your first file with PowerShell script. Then probably you will have following error:

File XXX cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.

It means that you do not have enough permissions to run PowerShell scripts. You have to change that, for instance with following command (remember to open PowerShell Terminal in Administrator mode):

Set-ExecutionPolicy RemoteSigned

More about options you can find here: https://msdn.microsoft.com/powershell/reference/5.1/Microsoft.PowerShell.Core/about/about_Execution_Policies

Tools

To write/manage your PowerShell scripts you can use many tools. I have chosen Visual Studio Code. It’s simple, it’s for free and when you install PowerShell Extension it will have IntelliSense.