Sitecore PowerShell Reports / by Derek Hunziker

Earlier this year, I shared a collection of handy PowerShell scripts for the Sitecore PowerShell Extensions Module. These scripts have served me well on my last few projects, however, I have since discovered another useful feature of the module that I had previously overlooked: it's ability to run reports.

Once you've got the module installed, you can begin running reports right away. I think you will find that many of the out-of-the-box reports are quite useful for both Content Authors and Developers alike. To run a report, all you need to do is load up the Sitecore Desktop and navigate to Reporting Tools > PowerShell Reports as shown below.


From a Developer's perspective, a report is fundamentally the same as any other script that you can find within the PowerShell Integrated Scripting Environment (ISE). This means that you can modify them to your liking, create new ones, and even save them under your very own custom script library. Pretty cool, right?

To get started, I recommend using one of the out-of-the-box reports as starting point. Once you have it open in the PowerShell ISE, take note of the following two commands:

  1. Read-Variable - Prompts the user to select a root item 
  2. Show-ListView - Displays the results in a sortable, filterable, and exportable listing

Together, these two commands can be used in a wide variety of use cases. However, you are certainly not limited to only these two. To view the full listing of Sitecore commands, you can run the report located at: Reporting Tools > PowerShell Reports > Configuration Audit > Find all Sitecore PowerShell Commands. Indeed, it would seem there's a report for everything these days.

Example Report: Rendering Audit

The following is an example report that compares your Sitecore renderings against a set of known issues and outputs a list of offenders. If your requirements differ from mine, all you need to do is comment out the conditional statements that don't apply to you and you should be all set. I hope you find it useful.

$item = gi master:\sitecore\layout\renderings
$result = Read-Variable -Parameters `
    @{ Name = "item"; Title="Rendering branch to analyze"; Tooltip="Branch you want to analyze."; Root="/sitecore/layout/renderings"} `
    -Description "This report will analyze the selected branch and output a list of renderings that contain one or more issues." `
    -Title "Choose Rendering Branch" -Width 500 -Height 280 `
    -OkButtonName "Proceed" -CancelButtonName "Abort" 

if($result -ne "ok")

function IsItemInvalid($item, $printOnly) {
    $invalidFlag = $false
    $msg = ""
    # Folder template does not contain rendering insert options, please use Rendering Folder template instead.
    if ($item.TemplateName -eq "Folder") {
        $msg += "Please use Rendering Folder. "
        $invalidFlag = $true
    # View rendering with no Path defined
    if ($item.TemplateName -eq "View rendering" -and $item.Path -eq "") {
        $msg += "Path not set. "
        $invalidFlag = $true
    # View rendering with a Path that does not exist on disk
    if ($item.TemplateName -eq "View rendering" -and $item.Path -ne "" -and -not (Test-Path ([System.Web.Hosting.HostingEnvironment]::MapPath($item.Path)))) {
        $msg += "File path does not exist on disk. "
        $invalidFlag = $true
    # Most renderings should utilize caching
    if ($item.Cacheable -ne "1") {
        $msg +="Caching not configured. "
        $invalidFlag = $true
    # If the rendering utilizes a datasource, you'll usually want to vary by data
    if ($item["Datasource Location"] -ne "" -and $item.VaryByData -ne 1) {
        $msg += "Consider varying cache by Data. "
        $invalidFlag = $true
    # If datasource location is set, but template is not, author can choose any item as datasource, which may cause issues
    if ($item["Datasource Location"] -ne "" -and $item["Datasource Template"] -eq "") {
        $msg += "Datasource Template not set. "
        $invalidFlag = $true
     # If datasource template is set, but location is not, author can insert or select datasource items anywhere in the tree
    if ($item["Datasource Template"] -ne "" -and $item["Datasource Location"] -eq "") {
        $msg += "Datasource Location not set. "
        $invalidFlag = $true
    # Authors will see the item name/display name, please use spaces
    if ($item.Name -cnotmatch "\s" -and $item.Name -cmatch "^(.*?[A-Z]){2,}" -and $item.DisplayName -cnotmatch "\s") {
        $msg += "Use spaces in name or display name. "
        $invalidFlag = $true
    # Thumbnails help authors identify what your rendering looks like
    if ($item.__Thumbnail -eq "") {
        $msg += "Please set rendering thumbnail. "
        $invalidFlag = $true
    if ($printOnly) {
    else {

$items = get-childitem $item.ProviderPath -recurse | `
  where-object { $_.TemplateName -ne "Rendering Folder" } | `
  select-object @{ Name="Invalid"; Expression={ IsItemInvalid($_) } } | `
  group-object Invalid;

$isValid = $items | where-object {$_.Name -ne "True" } | Select-object Count;
$isNotValid = $items | where-object {$_.Name -ne "False" } | Select-object Count;
$title = "Found $($isValid.Count + $isNotValid.Count) renderings. $($isValid.Count) of those are valid, while $($isNotValid.Count) are not."
Write-host -f Yellow $title

get-childitem $item.ProviderPath -recurse | `
    where-object { $_.TemplateName -ne "Rendering Folder" } | `
    where-object { IsItemInvalid($_) } | `
        Show-ListView -Property Name, `
            @{Name="Path"; Expression={$_.ItemPath}}, `
            @{Name="Issue(s)"; Expression={ IsItemInvalid $_ $true }} `
            -Title "Found $($isValid.Count + $isNotValid.Count) renderings." `
            -InfoTitle "Found $($isValid.Count + $isNotValid.Count) renderings." `
            -InfoDescription "$($isValid.Count) renderings are valid while $($isNotValid.Count) are not. Double click on a rendering to open it."