Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 224 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Sitecore PowerShell Extensions

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Disclaimer

Since every environment is different, all code should not be run in a production environment without your team or organization thoroughly testing first. We recommend the use of a test lab environment often referred to as a development/staging instance of Sitecore.

The disclaimer is provided because someone somewhere will inevitably not follow this recommendation and if they do hose their Sitecore environment, they have no one to blame but themselves.

All data and information provided in this book are for informational purposes only. Adam Najmanowicz, Michael West, and the SPE Team make no representations as to accuracy, completeness, currentness, suitability, or validity of any information in this book and will not be liable for any errors, omissions, or delays in this information or any losses, injuries, or damages arising from its display or use. All information found in this book is provided "as is" with no express or implied warranties.

Control Panel

Administration

Note: Examples included in the following modules

  • System Maintenance

Analytics

Database

Globalization

Preferences

Reports

Note: Examples included in the following modules

  • System Maintenance

Security

Common

Interfaces

SPE includes several built-in interfaces for managing and executing scripts, as well as provides tools for modifying content.

Here we'll discuss the Console, ISE, and other dialogs made available through SPE.

The Sitecore PowerShell Console is a command line interface that many power users find great for quickly running commands.
The Sitecore PowerShell ISE is a scripting interface for running commands and authoring scripts.

Releases

Thank you for taking the time to check out the latest and greatest changes for SPE. Send a tweet sharing how much you love the module on Twitter.

The following links provide a way to report issues and get the latest release.

  • Book issue tracker

  • Module issue tracker

See the for a compatibility matrix.

Introduction

About the Module

The (SPE) module is a Sitecore development accelerator that can drastically increase your productivity and curtail the amount of time it takes to deliver a Sitecore solution.

The module provides a command line (CLI) and a scripting environment (ISE) for automating tasks. SPE works with the Sitecore process, capable of making native calls to the Sitecore API and manipulating files. Running commands and writing scripts follow the standard and well-known Windows PowerShell syntax. Windows PowerShell is a common tool used in IT for desktop and server management, so we decided to stick with that as a framework to build upon.

Interface Configuration

Colors

The Console, ISE, and Result dialog all provide a way a way to view output data. The $host variable provides access to configuring the colors for this output data.

Example: The following configures colors for the background and forground text in multiple streams.

Modules

Sitecore PowerShell Extensions provides an organization structure composed of modules, libraries, and scripts. Modules make up the highest level and can be grouped together by module folders.

Some benefits to using modules:

  • The contained within each module can be enabled or disabled globally. For this to take full affect the integration should be rebuilt in the ISE.

  • Organization of custom scripts is a cinch.

Functions

The Functions integration allows for scripts to be discoverable through autocomplete while authoring scripts. Functions can be "disabled" by disabling the containing module.

  1. Begin by adding a script library called "Functions" to a module. This can be created by the new module wizard.

  2. Add a script to the "Functions" script library with a name that represents the purpose.

  3. Use the command Import-Function

Authoring Tasks

The Sitecore task scheduler is capable of running PowerShell scripts when using the task command PowerShellScriptCommand. The Task Management module includes a few shortcuts to managing tasks.

The module provides the ability to create, edit, and run scheduled tasks.

References

ISE Plugins

Custom ribbon commands for use in the ISE.

You can include custom ribbon commands in the ISE to aid in improving the script authoring experience.

Add a custom plugin

For this example, we wish to have a plugin that analyzes the script and reports on any errors.

Create a new script stored under the following structure:

Workflows

The Workflows integration allows for scripts to run like workflow commands. Rules can be used to control visiblity and enablement. The script is only executed when the command is triggered.

  1. Begin by adding a new item to a workflow command of template type /Modules/PowerShell Console/PowerShell Script Workflow Action. We've added an insert option to help with this.

  2. Edit the Type string field to your custom type or to the built in type Spe.Integrations.Workflows.ScriptAction, Spe.

Manage Templates

Examples for managing item templates.

Manage Templates

Change Template

Module releases
Appendix
  • Custom Scheduled Task by Mike Reynolds

  • Scheduled Task Menu
    Edit Scheduled Task
    $Host.UI.RawUI.BackgroundColor = ($bckgrnd = 'DarkRed')
    $Host.UI.RawUI.ForegroundColor = 'Cyan'
    $Host.PrivateData.WarningForegroundColor = 'Magenta'
    $Host.PrivateData.WarningBackgroundColor = "Green"
    $Host.PrivateData.VerboseForegroundColor = 'Green'
    $Host.PrivateData.VerboseBackgroundColor = "Red"
    Write-Host " Write-Host "
    Write-Verbose " Write-Verbose " -Verbose
    Write-Warning " Write-Warning "
    Show-Result -Text -Width 500 -Height 300
    Host output using Show-Result
    Sitecore Stack Exchange

    The following examples are best kept on SSE since it provides more context about the problem being solved.

    • Question Find all items based on a template found anywhere in the inheritance chain.

    # Sample Item
    $sourceTemplate = Get-Item -Path "master:\{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    # Sample Content
    $targetTemplate = Get-Item -Path "master:\{93A8866B-972F-4FBF-8FD9-D6004B18C0AF}"
    
    # Use Get-ItemReferrer to find all items referencing the template, rather than scanning the content tree.
    $sourceTemplate | Get-ItemReferrer | 
        Where-Object { $PSItem.TemplateId -eq $sourceTemplate.ID -and $PSItem.Paths.IsContentItem } |
        ForEach-Object {
            Set-ItemTemplate -Item $PSItem -TemplateItem $targetTemplate
        }

    Edit the Script body with the appropriate script. I like to save my workflow scripts in a library called Workflows.

  • Configure the Enable rules on the workflow action item to specify when to execute. Leave the rule alone if you wish for it to execute any time the command is activated.

  • Edit the script in your Workflows library to perform the appropriate actions. The script can run in the background and show dialogs.

  • Change the icon of the workflow action item to match the script purpose.

  • Celebrate your success with the team!

  • Example: The following requests input from the user then writes to the workflow history.

    See how Adam integrated workflow actions if you are really curious to know more.

    References

    • Fixing problematic content or Workflow state

    $item = $SitecoreContextItem
    $comment = Show-Input -Prompt "Enter a comment:"
    if($comment) {
        New-ItemWorkflowEvent -Item $item -Text $comment
    }
    Close-Window

    The book provides documentation about how to use the module based on the latest released version. While some of the screenshots and materials may be slightly out-of-date, you will inevitably find details referring to something that doesn't exist on your installed version. Feel free to submit a pull request for corrections here.

    Support for Sitecore 7 has discontinued with SPE 5.0. Check the appendix for version compatibility.

    Development Team

    • Adam Najmanowicz | @adamnaj

    • Michael West | @michaelwest101

    Bundled Tools

    The following are some helpful modules distributed with SPE.

    • Core

      • Platform

        • PowerShell Background Session Manager

        • Recreate site from sitemap

      • X-UnitTests - examples at how to use to test your scripts

    • Extensions

      • - reports based on the Sitecore Rules Engine.

        • - similar to the Luke tool

    • Maintenance

      • Index On Demand

      • Media Library Maintenance

      • System Maintenance

    • Reporting

      • - variety of reports to help audit the Sitecore solution.

    • Samples

      • Automatically show quick info section

      • Enforce user password expiration

      • Example Event Handlers

    • Tools

      • Authoring Instrumentation

      • Copy Renderings

      • Data Management

    • Training

    Endorsements

    There is nothing you can not do with PowerShell Console, because you're inside the Sitecore application. You can call the Sitecore API. - Alistair Deneys - Sitecore Symposium 2012

    Recommended by John West to use as a tool for maximizing Sitecore developer productivity.

    Get a job done with a one liner! Just provisioned a new language for the whole content tree with a one-liner. Whaaaat? Have to include it as a default install for all sandboxes now. - Alex Shyba's comment on Marketplace

    Thank you for the GitBook. Invaluable Reference. - Nick Wesselman's tweet

    The Sitecore powershell tools are absurdly good and helpful. I know they make a lot of people nervous, but they are incredibly well managed. Everybody should learn to sling some shell in Sitecore, you'll never look back. - Christopher Campbell tweet

    I literally couldn't work without SPE - I can't remember the last implementation I did that didn't have it installed lol @michaellwest & @adamnaj better not ever retire it 😄 - Richard Seal

    Help and Support

    See the Troubleshooting section for some common fixes.

    Questions, comments, and feature requests should be submitted on GitHub. You may also check out the SPE Slack channel for more interactive support. Not on Slack yet? Contact us on Twitter and we'll send you an invite.

    Disclaimer: With great power comes great responsibility – this tool can do a lot of good but also bring harm to a lot of content in a very short time – backup your system before running a script that modifies your content and never run any untested scripts in a production environment! We will not be held responsible for any use of it. Test your scripts on your development server first! Test on an exact copy of production before running scripts on production content.

    Sitecore PowerShell Extensions
    Sitecore PowerShell Extensions

    More reasons can be found in Adam's post.

    The Platform module is one you should avoid changing.

    Create a custom module

    Getting started with your own module is a short process and something you should do for all of your custom scripts.

    1. Navigate to the Script Library item and Insert -> PowerShell Script Module.

      New Module
    2. Enter the name for the new module and click OK.

    3. Right click the new module and Scripts -> Create libraries for integration points.

      Integration Points
    4. Select the appropriate integration points for your module.

    5. Select the module and enable for use.

    6. Open the ISE, switch to the Settings tab, and rebuild integrations.

    integration points
    to discover the available functions.
    Module Creation

    Note: It's best practice to create function scripts that follow the Verb-Noun pattern as outlined by Microsoft.

    Shared Functions Library
    Autocomplete in ISE

    Here's a short video on authoring custom functions.

    Creating Functions

    Click for a demo

    The path structure needs to follow [MODULE]/Internal/ISE Plugins/[PLUGIN_NAME]. Here we have X-Demo/Internal/ISE Plugins/Analyze Script.

    Use the following sample to fill in the script body.

    Now you can run the command from the ribbon and see the results in the ISE.

    Example results
    ISE Plugins
    Analyze Script
    if([string]::IsNullOrWhiteSpace($scriptText)){
        Show-Alert "Script is empty - nothing to format."
        exit
    }
    
    Import-Module -Name PSScriptAnalyzer
    Invoke-ScriptAnalyzer -ScriptDefinition $scriptText

    Data Sources

    Scripted Data Sources provide a way to use a PowerShell script to perform complex queries.

    Here are some good reasons to use this feature:

    • Delivering complex functionality based on multiple criteria.

    • Your field may need to provide different set of items to choose from based on:

      • user name or role (in simplest case this can be done using right management, but maybe not always possible in a more elaborate scenario)

      • current day or month?

      • In a multisite/multimarket scenario you may want to show different items for each site

        based on engagement analytics parameters of the page

        based on where in the tree an item exist (some of it can be done with use of a “query:”)

      • anything you might want to build the code data source for…

    Something that would be beyond the reach of a regular Sitecore query and potentially something that you would really need to deliver code source for. But maybe you’re not in a position to deploy that on your environment?

    Field Data Source

    Field Data Source provides a great opportunity for a script.

    Below are field types you may wish to use a script:

    • Checklist

    • Droplist

    • Grouped Droplink

    • Grouped Droplist

    Rendering Data Source Roots

    //TODO

    Rendering Data Source Items

    //TODO

    References

    • PowerShell Scripted Data Sources and

    • Sitecore Spark on using scripted datasources

    Page Editor

    Notification

    The Notification integration reveals to the user a notification above the content. The Sitecore rules engine may be used to control the enabled state; simply configure the Enable rule on the script. The script is executed every time the page loads.

    A Notification for the current date

    Example: The following adds an information notification to the page for Sitecore 8 and a warning for Sitecore 7.

    $title = "Thank you for using SPE!"
    $text = "Today is $([datetime]::Now.ToLongDateString())"
    $icon = @{$true="Office/32x32/information.png";$false="Applications/16x16/warning.png"}[$SitecoreVersion.Major -gt 7]
    
    $notification = New-Object -TypeName Sitecore.Pipelines.GetPageEditorNotifications.PageEditorNotification -ArgumentList $text, "Info"
    
    $notification.Icon = $icon
    $pipelineArgs.Notifications.Add($notification)

    Note: Examples included in the following modules

    • License Expiration

    Experience Button

    The Experience Button integration adds a button to the Page Editor. Rules can be used to control visiblity and enablement. The script is only executed when the button is clicked.

    1. Begin by adding a new script to the Experience Button library. The name of the script will appear in the tooltip.

    2. Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.

    3. Change the icon of the item to match the script purpose.

    4. Configure any Enable

    Example: The following adds a command which will display a dialog asking a question, then send an email with the response.

    Pipelines

    Use the following in your scripts to get access to the arguments passed to the processor.

     $pipelineArgs = Get-Variable -Name pipelineArgs -ValueOnly

    Configure any Enable rules to ensure your script only runs when necessary.

    Logging In

    Note: Examples included in the following modules

    • Enforce user password expiration

    Logged In

    Note: Examples included in the following modules

    • Automatically show quick info section

    Logout

    Note: Examples included in the following modules

    • Unlock user items on logout

    Help

    There are multiple methods of accessing help documentation in SPE to provide you with information on the commands available to you.

    Viewing all available commands

    A report is available which will show you all available SPE commands:

    Accessing the report

    When executed, this report provides a paged view of the SPE commands.

    Paged results of commands

    Viewing command help

    Console

    To display the available help for a command in the Console, simply use the Get-Help command:

    For full documentation, including examples, use the -Full parameter:

    ISE

    Through the Integrated Scripting Environment (ISE), SPE provides a method of acccessing help for available commands. To view the help for a command, simply highlight the command and press Ctrl + Enter.

    After doing this, a dialog will appear with the relevant help information:

    Documenting functions

    When writing scripts, you are able to include formatted comments that will be used to provide help text for functions. If formatted correctly, this help text will be available through the methods described above.

    Example: A simple function with documentation:

    Once the script containing this function has been invoked, the help text will be available:

    For further information on comment-based help, refer to the .

    Online appendix

    Online help is additionaly available for all SPE commands in this documentation, with detailed explanations of commands and their parameters, along with useful examples. These can be found in the .

    Event Handlers

    The Event Handler integration provides a way to execute scripts when defined events are fired.

    Steps required to activate this integration include the following:

    1. Enable the Spe.Events.config or apply your own patch with the required events enabled.

    2. Add a new integration point library to your new or existing module.

    3. Add a new script to the appropriate event library.

    4. Configure an Enable Rule if needed.

    5. Profit!

    Enable Configuration

    While SPE comes with an example configuration, which is disabled by default, it contains several events that may not meet your requirements.

    An event configuration patch may look like the following:

    Add Event Script

    To mimic the event item:added you should create nested script libraries such as Event Handlers -> Item -> Added followed by a script.

    Installation

    Review prerequisites and details on how to get setup with SPE.

    Prerequisites

    Take a quick look at the to see which version of SPE you should be installing that is compatible with your Sitecore environment. Generally SPE has pretty good backwards compatibility but may require a new version to support the latest Sitecore CMS release.

    • Windows Management Framework 5.1 (PowerShell) is generally available for most Windows environments.

    ConvertFrom-CliXml

    Imports a CliXml string with data that represents Microsoft .NET objects and creates the objects within PowerShell.

    Syntax

    ConvertFrom-CliXml [-InputObject] <String>

    Item Links

    Examples for managing item referrers maintained by the Link Database.

    Relink Item

    Example: The following changes the image linked on an item to a new image. Originally posted .

    Task Management

    • Scheduled Task Manager

    Getting Started - includes the Kitchen Sink Demo for Read-Variable.

  • License Expiration

  • Random desktop background

  • Training Modules

  • Unlock user items on logout

  • Bulk Data Generator - useful for items and users

  • Bulk Item Restorer - restore items from recycle bin

  • Bulk Template Changer - can't think of a better description than this

  • Data Importer - create or update items from a Csv

  • Find and Replace - use Content Search to change text

  • Elevated Unlock - provides options to unlock items using delegated administration

  • Package Generator - a simple method to package up items

  • Publishing Status Gutter

  • Security Management

    • Logged in Session Manager

    • Transfer item security

  • Pester
    Authorable Reports
    Index Viewer
    Content Reports
    Integration Point Libraries
    Module Activation

    Multilist

  • Name Lookup Value List

  • Droplink

  • Begin by adding a new script library called Data Sources followed by adding a script. You can call it something like Get-GlobalOption.

  • Add the path to your script in the Source field on the data template. The source should be prefixed with script: followed by the path.

  • Enjoy the results.

  • part 1
    part 2
    article
    Droplink query
    or
    Show
    rules as needed.
    An Experience Button for sending emails
    Message Input
    Email Response
    $pipelineArgs.Username
    $pipelineArgs.Password
    $pipelineArgs.Success
    $pipelineArgs.StartUrl
    $pipelineArgs.Username
    $pipelineArgs.StartUrl
    official PowerShell documentation
    Command Appendix
    Highlight the command and press Ctrl + Enter
    A help dialog for Get-Rendering
    Item Added Event Handler

    PowerShell Execution Policy set to RemoteSigned (probably optional)

    The release of SPE 6.0 introduced name changes to some files which are now reflected throughout the documentation. Review issue #1109 to see the full scope of what changed. Any place where the name Cognifide or Cognifide.PowerShell was used is now replaced with Spe.

    Docker

    Working with Docker is going to be the preferred method of installation.

    You can find two flavors of the images:

    • Community Built

      • Ex: docker pull sitecorepowershell/sitecore-powershell-extensions:6.4-1809

    • Sitecore Built

      • Ex: docker pull scr.sitecore.com/sxp/modules/sitecore-spe-assets:6.4-1809

    With this approach, you essentially add a new layer during your image build to include the files from the asset image. Here are some samples of what you can add to your existing setup. Check out Sitecore's samples for additional guidance.

    docker-compose.yml

    Dockerfile (mssql-init)

    Dockerfile (cm)

    Installation Wizard

    The SPE module installs like any other for Sitecore. This approach is appropriate for installations not within a containerized environment.

    Download the module from the GitHub releases page and install through the Installation Wizard.

    • For Sitecore 10.1 and newer along with Identity Server you should enable the provided configuration Spe.IdentityServer.config.

    • For Sitecore 10.1 and newer you can leverage the IAR packages. There is still the need for dacpac deployments because SPE includes a security user and role.

      • An additional patch is required for 10.1 to include the location /sitecore modules/items/. See Gist here.

    Upgrade

    We've tried to make upgrading SPE as seamless as possible. The following should provide you with some basic information on what to expect when upgrading.

    From 6.x

    You should be able to install directly over the previous installation of 6.0+.

    • For Sitecore 10.1 and newer along with Identity Server you should enable the provided configuration Spe.IdentityServer.config.

    • For Sitecore 10.1 and newer you can leverage the IAR packages. There is still the need for dacpac deployments because SPE includes a security user and role.

      • An additional patch is required for 10.1 to include the location /sitecore modules/items/. See Gist here.

    Using packages with the Items as Resources (IAR) files will require additional steps to remove database records that correlate with the contents of the *.dat files. Refer to the Sitecore documentation when upgrading for the process to cleanup the databases. This post may be helpful if you wish to take a more precise approach.

    From 5.x and older

    These versions used a different name for the assemblies and configs. You may find it easier to delete all files originally distributed with SPE before installing a newer version. Here are a few steps to consider:

    • Delete all files in the bin and App_Config/Include directories prefixed with Cognifide.

    • Delete /sitecore modules/Shell/PowerShell

    • Delete /sitecore modules/PowerShell

    Reference the original SPE package (if available) to identify if any other files were included.

    Sitecore items in the content tree will potentially shuffle around into their new location. Be sure to backup your custom scripts first.

    Troubleshooting

    See the troubleshooting section here

    appendix
    Remove Item Link

    Example: The following removes an item link followed by removing the item. Originally posted here.

    $item = Get-Item -Path "master:\media library\images\koala"
    $itemNew = Get-Item -Path "master:\media library\images\penguins"
    $links = Get-ItemReferrer -Item $item -ItemLink
    foreach($link in $links) {
        $linkedItem = Get-Item -Path master:\ -ID $link.SourceItemID 
        $itemField = $linkedItem.Fields[$link.SourceFieldID]
        $field = [Sitecore.Data.Fields.FieldTypeManager]::GetField($itemField)
        
        $linkedItem.Editing.BeginEdit()
        $field.Relink($link, $itemNew)
        $linkedItem.Editing.EndEdit() | Out-Null
    }
    here
    # The script must return an item. This is useful for populating a Droplink.
    Get-ChildItem -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    script:/sitecore/system/Modules/PowerShell/Script Library/X-Demo/Data Sources/Get-GlobalOption
    $item = Get-Item -Path .
    $response = Show-Input -Prompt "What's the message for $($item.Name)?"
    if($response) {
        $mailSettings = @{
            To = @("Michael West < [email protected] >")
            From = "Console < [email protected] >"
            BodyAsHtml = $true
            SmtpServer = "localhost"
        }
    
        $subject = "Message sent regarding item $($item.Name) from $($SitecoreAuthority)"
        $response += "<br/>$($item.ItemPath)"
        Send-MailMessage @mailSettings -Subject $subject -Body $response
    }
    
    Close-Window
    Get-Help Get-Rendering
    Get-Help Get-Rendering -Full
    <#
        .SYNOPSIS 
        A short synopsis of this function.
        .DESCRIPTION
        A much more detailed description of this function, which outputs a value.
        .PARAMETER Value
        The value that will be output 
        .EXAMPLE
        PS> Output-Value "My value"
        My value
    #>
    Function Output-String
    {
        param(
            [string]$value
        )
    
        Write-Host $value
    } 
    Get-Help Output-String
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <events>
          <event name="item:added">
            <handler type="Spe.Integrations.Tasks.ScriptedItemEventHandler, Spe" method="OnEvent" />
          </event>
        </events>
      </sitecore>
    </configuration>
    services:
      mssql-init:
        image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-mssql-init:${VERSION:-latest}
        build:
          context: ./docker/build/mssql-init
          args:
            BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-mssql-init:${SITECORE_VERSION}
            SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION}
      cm:
        image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest}
        build:
          context: ./docker/build/cm
          args:
            BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION}
            SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION}
    # escape=`
    
    ARG BASE_IMAGE
    ARG SPE_IMAGE
    
    FROM ${SPE_IMAGE} as spe
    FROM ${BASE_IMAGE}
    
    COPY --from=spe C:\module\db C:\resources\spe
    # escape=`
    
    ARG BASE_IMAGE
    ARG SPE_IMAGE
    
    FROM ${SPE_IMAGE} as spe
    FROM ${BASE_IMAGE}
    
    SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
    
    WORKDIR /inetpub/wwwroot
    
    COPY --from=spe \module\cm\content .\
    # Crafted by Dylan
    
    function Remove-ItemLink {
        param([Item]$item)
        
        $linkDb = [Sitecore.Globals]::LinkDatabase
    
        $links = Get-ItemReferrer -Item $item -ItemLink
    
        foreach($link in $links) {
            $linkedItem = Get-Item -Path master:\ -ID $link.SourceItemID 
            $itemField = $linkedItem.Fields[$link.SourceFieldID]
            $field = [Sitecore.Data.Fields.FieldTypeManager]::GetField($itemField)
    
            $linkedItem.Editing.BeginEdit()
            $field.RemoveLink($link)
            $linkedItem.Editing.EndEdit()
        }
    }
    
    # Example usage: delete items along with their references that have passed a certain date defined by a 'date' field
    $today = Get-Date
    $todayIsoDate = [Sitecore.DateUtil]::ToIsoDate($today)
    $query = "/sitecore/system/Modules/Mysite/Service Schedules/*[@date < '$($todayIsoDate)']"
    $itemsToDelete = Get-Item -Path master: -Query $query
    
    foreach($item in $itemsToDelete) {
        Write-Host "Cleaning up $($itemsToDelete.Paths.Path)"
        Remove-ItemLink -Item $item
        Remove-Item -Path $item.Paths.Path
    }
    Detailed Description

    The ConvertFrom-CliXml command imports a CliXml string with data that represents Microsoft .NET Framework objects and creates the objects in PowerShell.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -InputObject <String>

    String containing the Xml with serialized objects.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • System.String

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • object

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    • ConvertTo-CliXml

    • ConvertTo-Xml

    • ConvertFrom-Xml

    • Export-CliXml

    • Import-CliXml

    Item Languages

    The section on working with items provided a variety of examples in retrieving items based on their language. In this section will show how to manage items and their languages.

    Add Language Version

    Example: The following example queries all of the content items and adds a new language version of "en-ca", while overwriting any that exist.

    Example: The following example adds a language version from English to US and Polish while leaving the Title field blank. If a version already exists nothing happens.

    Example: The following example adds a language version from English to Polish of Template Name Sample Item. If the version exists a new version is created for that language. Finally the results are displayed as a table showing only the Name, Language, and Version.

    Example: The following example adds a language version in Polish to the Home item and all its children. If the version exists nothing happens. No fields were harmed in the making of this version.

    Remove Language Version

    Example: The following example queries all of the content items and removes the language version of "fr-CA".

    New Item with Forced Language Version

    Example: The following example creates a new item with language versions only matching the specified languages; all other language version are removed.

    Parameters and Configuration

    Supported parameters:

    • -Recurse Translates item and its children

    • -IfExist Accepts one of 3 pretty self explanatory actions: Skip, Append or OverwriteLatest

    On top of the ignored fields in the -IgnoredFields the following fields are ignored as configured within the Spe.config file:

    References

    Tasks

    The task scheduler is a great way to run scripts in a periodic fashion. You may find the need to automatically archive log files into a compressed file. Perhaps send an email with a generated report based on stale site content.

    Video Tutorial

    Scheduled Task Editor

    Click for a demo

    Scheduled Task Command

    To help make the setup simple, we've provided a Task Command.

    The command shown above is simply a type exposed as a public method in the Spe assembly. There exists an update method which accepts one or more items and executes the associated script.

    Beneath Schedules you can create as many tasks as Sitecore will allow. Configure the Command and Items fields like that shown below.

    The Items field contains the path to a script in the Script Library.

    Below are some of the scripts found out-of-the-box with SPE.

    Module
    Script

    Create and Manage Tasks

    We've added a context menu item to provide you with a shortcut to the Task Scheduler Editor.

    Create a new scheduled task:

    Run or edit the scheduled task:

    The scheduled task is capable of running 1-to-many scripts. Choose all that apply for the selected task. Each script runs within a shared session, making it possible to share results between scripts.

    Note: Make use of the Enable Rule to take advantage of the rules engine.

    The task schedule has an intuitive dialog for working with and changing the frequency.

    Note: Examples included are in the following modules

    • License Expiration

    • Media Library Maintenance

    • System Maintenance

    See how Adam added .

    Web API

    The Web API integration point exposes scripts through a url. This can be especially helpful when a script needs to be executed on the server but without knowledge of the script contents.

    The url will look something like the following: https://remotesitecore/-/script/v2/master/homeanddescendants?user=sitecore\admin&password=b

    Here's the url broken down:

    • API Version - Specifies which service is being requested.

      • v2 - This is the service that executes scripts stored in the integration point library.

    • Database - Specifies which database contains the script.

      • master - This database requires the credentials to be provided.

    • Script - Specifies the name of the script contained in the database. The SPE module containing the script needs to be enabled otherwise you'll receive a 404 error.

      • homeanddescendants - Replace this name with whatever your script is called in the Web API library.

    • Query String Parameters (deprecated) - Specifies the additional bits of data for use by the web service.

      • user and password - Authenticates the request and in most cases will be needed. If the script is published to the web database the credentials are not required. You should use the Basic header instead of the query string.

      • All of the query string parameters added to the variable scriptArguments

    Headers:

    Use the Basic header to provide authentication information. Here is an example of how to build that for a script.

    Note: Examples included in the following modules

    • Getting Started

    Security

    The integration point is disabled by default and can be enabled through configuration as described . See Restfulv2. Be sure to enable the SPE script module in the content tree.

    References

    • Watch Adam present this and much more on Sitecore! Experienced .

    Packaging

    Ever wanted to package up items and files without opening the Sitecore Package Designer each time? There are a number of commands available for generating packages.

    Package Creation

    Example: The following example demonstrates how to generate a package.

    $package = New-Package "Package-of-Stuff"
    $package.Sources.Clear()
    
    $package.Metadata.Author = "Michael West"
    $package.Metadata.Publisher = "Team Awesome"
    $package.Metadata.Version = "1.0"
    $package.Metadata.Readme = @"
    Set of instructions for the user.
    "@
    
    # Items using New-ItemSource and New-ExplicitItemSource
    $source = Get-Item -Path "master:\templates\Feature\Forms" | 
        New-ItemSource -Name 'Feature Forms Items' -InstallMode Overwrite
    $package.Sources.Add($source)
    
    # Files using New-FileSource and New-ExplicitFileSource
    $source = Get-Item -Path "$AppPath\App_Config\Include\Feature\Forms\Company.Feature.Forms.config" | 
        New-ExplicitFileSource -Name "Feature Forms Files"
    $package.Sources.Add($source)
    
    Export-Package -Project $package -Path "$($package.Name)-$($package.Metadata.Version).xml"
    Export-Package -Project $package -Path "$($package.Name)-$($package.Metadata.Version).zip" -Zip
    Download-File "$SitecorePackageFolder\$($package.Name)-$($package.Metadata.Version).zip"

    Post Step

    Example: The following adds a Post Step and custom attributes.

    Example: The following adds a Post Step included with SPE to delete a file. The SPE Post Step code reads xml data stored in the comment section of the package.

    Example: The following adds a Post Step Script included with SPE to change icons. The SPE Post Step code executes a script included with the package as stored in the attributes section.

    ConvertTo-CliXml

    Exports Microsoft .NET objects froms PowerShell to a CliXml string.

    Syntax

    ConvertTo-CliXml [-InputObject] <PSObject>

    Detailed Description

    The ConvertTo-CliXml command exports Microsoft .NET Framework objects from PowerShell to a CliXml string.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -InputObject <PSObject>

    Specifies the object to be converted. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe objects to ConvertTo-CliXml.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • object

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • System.String

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • ConvertFrom-Xml

    • ConvertTo-Xml

    Troubleshooting

    General

    We generally see issues occurring due to an incompatible version of Windows PowerShell. Be sure to install Windows PowerShell version 3 or newer.

    Installation

    Elevated Session Hanging

    There is an additional configuration file added to support Identity Server. If you are installing Sitecore 9.1 or later you will want to enable the configuration file Spe.IdentityServer.config.

    You can see the Sitecore Stack Exchange answer describing the contents of the configuration.

    Hanging Installation Wizard

    Some users have reported an where the package installation in Sitecore hangs while installing SPE. One possible fix is to disable the Sitecore Analytics feature; this of course assumes you do not plan on using it for your instance.

    Article: Martin Miles encountered the issue and proposed a fix .

    Hack: Run this script on Sitecore 8.0.

    Exception Messages

    ISE throws exception when /sitecore/content/home is missing

    • - Missing Home item (fixed in 3.2)

    Modules

    Integration Point is not working

    Be sure the module is enabled and the integrations are rebuilt from within the ISE. The following are some of the integration issues you may experience:

    • Content Editor Gutter - Entries not listed.

    • Content Editor Ribbon - Buttons not visible or working.

    • Control Panel - Entries not listed.

    • Functions - Import-Function name parameter not populating with functions or can't be found after running the command.

    Remoting

    • 404 error in browser console can be caused by missing SPE files, a custom pipeline, or perhaps a rewrite rule.

    • "The request failed with an empty response." could be caused when TLS is offloaded to a load balancer and traffic to the endpoint is no longer over HTTPS. Fixed by issue #.

    • "The underlying connection was closed: An unexpected error occurred on a send." could be caused in Azure PaaS when requests are made using TLS 1.1 or lower. Setting the SecurityProtocol may help. Thanks to Jayesh Sheth for pointing to a resolution.

    Training

    Comprehensive guide to learning SPE from beginner to advanced.

    The world renowned Sitecore PowerShell Extensions module has so much to offer, but sometimes those new to the module may find it difficult to know where to start. This training guide provides you with everything you need to use and be productive with SPE.

    Don't worry, you will be able to use it without having to write any code.

    Learning Path

    This guide provides a progressive roadmap from beginner to advanced SPE user. Follow this path to build your skills systematically:

    Console

    The Console is a command line interface (CLI) designed for efficiency, providing a streamlined tool for working with Windows PowerShell and Sitecore.

    The default security configuration for SPE requires the Console to be in an before allowing the execution of commands. The following figure shows the Console when the User Account Controls (UAC) are disabled. While this is a common configuration for developers, we highly encourage you to ensure UAC is enabled in higher environments.

    Shortcuts

    Below are the shortcuts available in the console.

    Item Renderings

    In this section we'll show how to manage item renderings.

    List renderings

    Example: The following demonstrates the use of Get-LayoutDevice and Get-Rendering to find all renderings on a page associated with the FinalLayout.

    Integration Points

    The SPE Modules support a wide variety of predefined script libraries to help with exposing scripts to the Sitecore interface.

    The following list outlines the available libraries for Integration Points that may be added to modules. These may also be generated automatically when creating or updating modules.

    Be certain to enable the module when you need to use it.

    Toolbox

    The PowerShell Toolbox is quick way to access frequently used scripts.

    Navigate to Sitecore -> PowerShell Toolbox and after selecting you should see the configured scripts:

    Note: Examples included in the following modules

    • Authorable Reports

    • Logged in Session Manager

    Field Types

    Examples for managing complex field types such as MultilistField and NameValueListField.

    Edit MultilistField

    Example: The following demonstrates how to set a field to a known list of Ids. The Id is already converted to a GUID string.

    Example: The following replaces an instance of an Id with an alternate Id. The Id is already converted to a GUID string.

    Example: The following adds new Ids to an existing list. Makes use of the Sitecore.Text.ListString class.

    Get-Archive

    Returns Sitecore database archives.

    Syntax

    Get-Archive [[-Database] <Database>] [[-Name] <String>]

    Get-UserAgent

    Returns the current user's browser user agent.

    Syntax

    Detailed Description

    Close-Window

    Closes the runner job window after the script completes.

    Syntax

    Close-Window

    PS master:\> #Convert original item to xml
    PS master:\> $myCliXmlItem = Get-Item -Path master:\content\home | ConvertTo-CliXml 
    PS master:\> #print the CliXml
    PS master:\> $myCliXmlItem
    PS master:\> #print the Item converted back from CliXml
    PS master:\> $myCliXmlItem | ConvertFrom-CliXml
    Get-ChildItem "master:\content" -Recurse |
        Add-ItemLanguage -Language "en-us" -TargetLanguage "en-ca" -IfExist OverwriteLatest
    $languageParameters = @{
        Path = "master:\content\home"
        Language = "en"
        TargetLanguage = @("pl-pl","en-us")
        IfExist = "Skip"
        IgnoredFields = @("Title")
    }
    Add-ItemLanguage @languageParameters
    https://github.com/SitecorePowerShell/Console/issues/218
    -TargetLanguage accepts a list of languages that should be created
  • -DoNotCopyFields creates a new version but does not copy field values from original language

  • -IgnoredFields list of fields that should not be copied over from original item this can contain e.g. __Security if you don't want the new version to have the same restrictions as the original version.

  • Issue 184
    Remove All Content items in French
    . Use this PowerShell hashtable inside of your scripts. Check out the function
    Invoke-ApiScript
    for an example of how these parameters can be put to good use.
    here
    here
    $package = New-Package "Package-of-Stuff"
    $package.Sources.Clear()
    
    $package.Metadata.Author = "Michael West"
    $package.Metadata.Publisher = "Team Awesome"
    $package.Metadata.Version = "1.0"
    $package.Metadata.Readme = @"
    Set of instructions for the user.
    "@
    $package.Metadata.PostStep = "Some.Library.Class,Some.Library"
    $package.Metadata.Attributes = "scriptId={9b9a3906-1979-11e7-8c9d-177c30471cec}|width=50|height=200"
    
    Export-Package -Project $package -Path "$($package.Name)-$($package.Metadata.Version).xml"
    Import-Function -Name New-PackagePostStep
    
    $package = New-Package "Package-of-Stuff"
    $package.Sources.Clear()
    
    $package.Metadata.Author = "Michael West"
    $package.Metadata.Publisher = "Team Awesome"
    $package.Metadata.Version = "1.0"
    $package.Metadata.Readme = @"
    Set of instructions for the user.
    "@
    $newPackageFiles = @([PSCustomObject]@{"FileName"="/bin/Company.Feature.Unused.dll"})
    $package.Metadata.PostStep = "Spe.Package.Install.PackagePostStep, Spe.Package"
    $package.Metadata.Comment = New-PackagePostStep -PackageFiles $newPackageFiles

    Export-CliXml

  • Import-CliXml

  • Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/
    ConvertFrom-CliXml

    Web API - Scripts not existing or can't be found.

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    here
    issue
    here
    378
    1005
    Update rendering parameters

    Example: The following demonstrates the use of Get-Rendering and Set-Rendering for updating values on templates.

    Find pages using rendering

    Example: The following demonstrates how to report on pages referencing the specified rendering.

    Find renderings marked cacheable

    Example: The following demonstrates how to report on which renderings are globally set to "Cacheable".

    Find renderings with personalization

    Example: The following demonstrates how to find renderings with a conditions node set on the item.

    Disable cacheable setting on renderings

    Example: The following demonstrates how to disable global caching on all renderings.

    Move renderings between placeholders

    Example: The following moves renderings from one placeholder to another. See this article for more details.

    Remove datasource from rendering

    Example: The following removes a datasource from a rendering on the FinalLayout.

    Replace compatible rendering

    Further Reading

    • Parse raw layout xml and count components

    Example: The following appends an ID to a set of items in all languages. It verifies that the field Keywords exists.

    Example: The following example gets all of the items of a MultilistField and append a specific ID, ensuring that it's delimited with the | character.

    Example: The following example extracts the items from a 'keywords' field, comma separates the values, and then outputs to a report.

    Edit NameValueListField

    Example: The following example gets all of the name/value pairs of a NameValueListField and appends a new pair.

    # Hardcoded list of Ids.
    $item.Editing.BeginEdit()
    $item["Allowed Controls"] = "{guid1}|{guid2}|{guid3}"
    $item.Editing.EndEdit()
    # Array of Ids.
    $array = [System.Collections.ArrayList]@()
    $array.Add({guid1}) > $null
    $array.Add({guid2}) > $null
    $ids = [System.String]::Join("|", $array)
    $item.Editing.BeginEdit()
    $item["Allowed Controls"] = $ids
    $item.Editing.EndEdit()
    Detailed Description

    The Get-Archive command returns Sitecore archives in context of the specified database.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Name <String>

    Name of the archive to retrieve.

    Aliases

    Required?

    false

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <Database>

    Database for which the archives should be retrieved.

    Aliases

    Required?

    false

    Position?

    2

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Database

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Archiving.Archive

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    Returns current user's browser user agent. Works only if Console is running outside of job. (e.g. in ISE - script needs to be run from the dropdown under the "Execute" button)

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • System.String

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    Detailed Description

    Ensures the runner process window is closed after the script finishes execution. This is commonly used when the runner should close after a report runs while in the Desktop mode.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    Get-ChildItem "master:\content\home" -Language "en" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" } |
        Add-ItemLanguage -TargetLanguage "pl-pl" -IfExist Append |
        Format-Table Name, Language, Version -AutoSize
    Add-ItemLanguage -Path "master:\content\home" -TargetLanguage "pl-pl" -IfExist Skip -DoNotCopyFields -Recurse
    Get-ChildItem "master:\content" -Recurse |
        Remove-ItemLanguage -Language "fr-CA"
    $itemPath = "master:\content\home\sample item\Sample Item 3"
    New-Item -Path $itemPath -ItemType "Sample/Sample Item" -Language "en-CA"
    
    Name          Children Language Version Id                                     TemplateName
    ----          -------- -------- ------- --                                     ------------
    Sample Item 3 False    en-CA    1       {C9517583-3AF9-4AFB-B247-BB0A09F55D94} Sample Item
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <translation>
            <ignoredFields>
              <field>__Archive date</field>
              <field>__Archive Version date</field>
              <field>__Lock</field>
              <field>__Owner</field>
              <field>__Page Level Test Set Definition</field>
              <field>__Reminder date</field>
              <field>__Reminder recipients</field>
              <field>__Reminder text</field>
              <!--field>__Security</field-->
            </ignoredFields>
          </translation>
      </sitecore>
    </configuration>
    $username = "admin"
    $password = "b"
    
    $pair = "$($username):$($password)"
    
    $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
    
    $basicAuthValue = "Basic $encodedCreds"
    
    $headers = @{
        Authorization = $basicAuthValue
    }
    
    Invoke-RestMethod -Headers $headers -Uri "https://spe.dev.local/-/script/v2/master/TrainingWebApi?offset=3&limit=2&fields=(Name,ItemPath,Id)"
    $package = New-Package "Package-of-Stuff"
    $package.Sources.Clear()
    
    $package.Metadata.Author = "Michael West"
    $package.Metadata.Publisher = "Team Awesome"
    $package.Metadata.Version = "1.0"
    $package.Metadata.Readme = @"
    Set of instructions for the user.
    "@
    $package.Metadata.PostStep = "Spe.Integrations.Install.ScriptPostStep, Spe"
    $package.Metadata.Attributes = "scriptId={737CD0CC-12F7-4528-8FBD-E0FDEFC41325}"
    Write-Log "Processing changes to ensure backwards compatibility."
    $oldVersion = New-Object System.Version(10,0)
    if($PSVersionTable["SitecoreVersion"] -lt $oldVersion) {
        $iseButton = Get-Item -Path "core:{bfc79034-857c-4432-a5c2-2d93af784384}"
        $iseButton.Editing.BeginEdit()
        $iseButton.Fields["{D25B56D4-23B6-4462-BE25-B6A6D7F38E13}"].Value = "powershell/32x32/ise8.png"
        $iseButton.Editing.EndEdit() > $null
    
        $reportButton = Get-Item -Path "core:{74744022-353c-43f1-b8e4-5bc569ca9348}"
        $reportButton.Editing.BeginEdit()
        $reportButton.Fields["{D25B56D4-23B6-4462-BE25-B6A6D7F38E13}"].Value = "Office/32x32/chart_donut.png"
        $reportButton.Editing.EndEdit() > $null
        Write-Log "Changes complete."
    } else {
        Write-Host "No changes required."
    }
    Close-Window
    PS master:\> #Convert original item to xml
    PS master:\> $myCliXmlItem = Get-Item -Path master:\content\home | ConvertTo-CliXml 
    PS master:\> #print the CliXml
    PS master:\> $myCliXmlItem
    PS master:\> #print the Item converted back from CliXml
    PS master:\> $myCliXmlItem | ConvertFrom-CliXml
    $paths = @("C:\inetpub\wwwroot\Console\Website\App_Config\Include\*")
    $patterns = @("Sitecore.Analytics*.config", "Sitecore.ExperienceAnalytics*.config")
    
    $paths | Get-ChildItem -Include $patterns -Recurse | Rename-Item -NewName { $PSItem.Name + ".disabled" }
    $defaultLayout = Get-LayoutDevice -Default
    $rootItem = Get-Item -Path "master:" -ID "{961563FC-3445-4558-BF3A-06DF06BA6298}"
    Get-Rendering -Item $rootItem -Device $defaultLayout -FinalLayout
    $rendering = Get-Item -Path "master:\sitecore\layout\Sublayouts\Sample Sublayout"
    
    $items = Get-ChildItem -Path "master:\sitecore\templates\Sample Item" -Recurse 
    foreach($item in $items) {
        $renderingInstance = Get-Rendering -Item $_ -Rendering $rendering 
        if ($renderingInstance) { 
            Set-Rendering -Item $_ -Instance $renderingInstance -Parameter @{ 
                "Lorem" = "Ipsum" 
            } 
            Write-Host "Updated $($_.Paths.FullPath)" 
        } 
    }
    Get-Item "master:\layout\Renderings\Feature\Experience Accelerator\Page Content\Page Content" | 
        Get-ItemReferrer | Where-Object { $_.ContentPath.StartsWith("/Demo/usa/Home") } | Show-ListView
    Get-ChildItem -Path "master:\layout\Renderings" -Recurse | 
        Where-Object { $_.Cacheable -eq "1" } | 
        Select-Object -Property Name, Cacheable, ClearOnIndexUpdate, VaryBy* | 
        Sort-Object -Property Name | Show-ListView
    $query = "fast:/sitecore/content//*[@__renderings='%<conditions%' or @#__Final Renderings#='%<conditions%']"
    $items = Get-Item -Path "master:" -Query $query
    $VerbosePreference = "Continue"
    Get-ChildItem -Path "master:\layout\Renderings" -Recurse | 
        Where-Object { $_.Cacheable -eq "1" } | 
        ForEach-Object { Write-Verbose "Disabled global caching on $($_.Name)"; $_.Cacheable = "0" }
    
    # VERBOSE: Disabled global caching on Navigation
    $placeholderMappings = @(
     @("/old-placeholder","/new-placeholder"),
     @("/another-old-placeholder","/new-placeholder")
    )
    $rootItem = Get-Item -Path master:/sitecore/content/Home
    $defaultLayout = Get-LayoutDevice "Default"
    # Toggle for whether to update Shared or Final Layout
    $useFinalLayout = $True
    # If set to true, the script will only list the renderings that need fixing, rather than fixing them.
    $reportOnly = $False
    foreach ( $item in Get-ChildItem -Item $rootItem -Recurse )
    {
        # Only interested in items that have a layout
        if (Get-Layout $item)
        {
            foreach( $mapping in $placeholderMappings )
            {
                # Get renderings in this item that have renderings in the placeholder we want to update 
                $renderings =  Get-Rendering -Item $item -Placeholder ($mapping[0] + '/*') -Device $defaultLayout -FinalLayout:$useFinalLayout
    
                foreach ( $rendering in $renderings )
                {
                    # Only update the rendering if we're not in "Report Only" mode
                    if (!$reportOnly)
                    {
                       # Update the placeholder in the rendering and set it back in the item
                       $rendering.Placeholder = $rendering.Placeholder -replace $mapping[0], $mapping[1]
                       Set-Rendering -Item $item -Instance $rendering -FinalLayout:$useFinalLayout
                    }
                    Write-Host "$($item.FullPath) - Rendering $($rendering.UniqueID) - Placeholder: $($mapping[0]) --> $($mapping[1])"
                }
            }
        }
    }
    Get-Rendering -Item $item -PlaceHolder "main" | 
      Foreach-Object { Set-Rendering -Item $item -Instance $_ -DataSource $null -FinalLayout }
    $rendering = Get-Item master:\layout\path\to\your\rendering
    $renderingPageContainer = Get-Rendering -Item $item "{F39BAC93-1EEC-446B-A4A1-AB7F7C1B6267}" -Device $defaultLayout
    $renderingPageContainer.ItemID = $rendering.ID
    Set-Rendering -Item $item -Instance $renderingPageContainer
    [Sitecore.Data.Fields.MultilistField]$field = $item.Fields["Allowed Controls"]
    $item.Editing.BeginEdit()
    $field.Replace("{493B3A83-0FA7-4484-8FC9-4680991CF742}","{493B3A83-0FA7-4484-8FC9-4680991CF743}")
    $item.Editing.EndEdit()
    [Sitecore.Text.ListString]$ids = $item.Fields["Rendering"].Value
    $ids.AddAt(0,"{guid1}") > $null
    $ids.Add("{guid2}") > $null
    $ids.Add("{guid3}") > $null
    
    $item.Editing.BeginEdit()
    $item.Fields["Rendering"].Value = $ids.ToString()
    $item.Editing.EndEdit() > $null
    $items = Get-ChildItem -Path "master:\sitecore\content\home" -Recurse -Language *
    foreach($item in $items) {
        if ($item.Keywords -and $item.Keywords.Length -gt 0) {
            $item.Keywords = $item.Keywords + "|{guid}"
        } else {
            $item.Keywords = "{guid}"
        }
    }
    $items = Get-ChildItem -Path "master:\sitecore\content\home" -Recurse -Language *
    foreach($item in $items) {
        $item.Keywords = (@() + $item.Keywords.GetItems().ID + "{6D1EACDD-0DE7-4F3D-B55A-2CAE8EBFF3D0}" | Select-Object -Unique) -join "|"
    }
    function Get-KeywordsAsString($item) {
        [Sitecore.Data.Fields.MultilistField] $field = $item.Fields["Keywords"]
        $items = $field.GetItems()
        $strArray = $items | Foreach { $_.DisplayName }
        $strArray -join ', '
    }
    Get-ChildItem -Path 'master:\content\home\path-to-item' `
      | Show-ListView -Property Name, Language, Version, ID, TemplateName, ItemPath, `
            @{ Label = "KeywordsAsString"; Expression = { Get-KeywordsAsString($_) } }
    $item = Get-Item -Path "master:" -ID "{371EEE15-B6F3-423A-BB25-0B5CED860EEA}"
    
    $nameValues = [System.Web.HttpUtility]::ParseQueryString($item.UrlMapping)
    
    # Here you can add or remove name/value pairs
    $nameValues["^/ab[cde]/$"] = "/somewhere/fun?lang=en"
    
    foreach($key in $nameValues.AllKeys) {
        $nameValues[$key] = [Uri]::EscapeDataString($nameValues[$key])
    }
    
    $item.UrlMapping = [Sitecore.StringUtil]::NameValuesToString($nameValues,"&")
    PS master:\> Get-Archive -Database "master"
    
    Name                                        Items
    ----                                        -----
    archive                                         0
    recyclebin                                   1950
    PS master:\> Get-UserAgent
    
    Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
    PS master:\> Close-Window
    Beginner - Get Started
    1. Get up and running - Start with Getting Started

    2. Watch the basics - View our video series

    3. Learn PowerShell syntax - Study Language Basics

    4. Master commands - Read Commands and Pipelines

    5. Understand providers - Learn

    6. Practice with examples - Try

    7. Avoid mistakes - Review

    Intermediate - Build Skills

    1. Retrieve Sitecore items - Learn to query and navigate → Retrieving Items

    2. Modify content - Edit, create, and delete → Editing Items, Creating Items

    3. Move and copy items - Reorganize content → Moving and Copying Items

    4. Use interactive dialogs - Build user interfaces → Interactive Dialogs

    5. Explore integration points - Extend Sitecore UI →

    Advanced - Master SPE

    1. Create custom reports - Build powerful analysis tools → Authoring Reports

    2. Build reusable libraries - Organize your scripts → Libraries and Scripts

    3. Automate with tasks - Schedule automated jobs → Authoring Tasks

    4. Use remoting - Control Sitecore from external scripts → Remoting

    5. Package your work - Deploy scripts as packages →

    6. Plan your next steps - Review

    Critical - Secure Your Installation

    BEFORE deploying to any environment, you MUST review security:

    • Security Hardening Guide - Overview of security concepts

    • Security Checklist - Step-by-step hardening

    • - Configure access control

    • NEVER install SPE on Content Delivery (CD) servers

    • NEVER deploy SPE on internet-facing instances

    Resources & Support

    Official Documentation

    • This book - Comprehensive reference for all SPE features

    • Command Reference - Complete list of SPE cmdlets

    • Code Snippets - Ready-to-use examples

    Video Tutorials

    • SPE Video Series - Beginner walkthroughs

    • Blogs and Videos Collection - Community content

    Hands-On Practice

    • Console - Interactive PowerShell terminal in Sitecore

    • ISE (Integrated Scripting Environment) - Full-featured script editor with IntelliSense

    Get Help

    • Built-in help: Use Get-Help <command-name> in the Console

    • Troubleshooting: Troubleshooting Guide

    • Community: Join the #module-spe channel on Sitecore Slack

    • GitHub: Report issues or request features at

    Happy scripting!

    Shortcut

    Usage

    Enter

    Submits line for execution.

    Tab

    Autocomplete commands. Press tab again to cycle through commands.

    Shift+Tab

    Reverse cycle through Autocomplete commands.

    Shift+Enter

    Inserts new line. Works when the backtick is used.

    ArrowUp/Ctrl+P

    Show previous command from history

    ArrowDown/Ctrl+N

    Show next command from history

    Delete/backspace

    Note: The font family, font size, and other settings can be configured through the ISE.

    Elevated Session State
    PowerShell Console
  • Context Menu - Visibility can be control using rules made available from within the Interactive field section.

  • Gutters - Requires the library to be synced (see below).

  • Insert Item - Visibility can be control using rules made available from within the Interactive field section.

  • Ribbon - Requires the library to be . Visibility can be control using rules made available from within the Interactive field section.

  • Warning - Appears as a warning message beneath the ribbon in the Content Editor.

  • Control Panel - Requires the library to be synced (see below).

  • Data Sources - Not a formal integration point library, but a good place to add scripts used for Data Source Scripts. Read more about how they work here and here. The Source field simply references the script like script:/sitecore/system/Modules/PowerShell/Script Library/[MODULE NAME]/Data Sources/[SCRIPT NAME].

  • Event Handlers - Requires a patch file to enable the desired events. Read more about it here.

  • Functions - Exposes scripts to the command Import-Function.

  • Internal

    • ISE Plugins - Appears as a button in the ISE Settings tab.

    • List View - Represents the ribbon buttons such as for Actions and Exports.

  • Page Editor (Experience Editor)

    • Notification - Appears as a notification message beneath the ribbon in the Experience Editor.

  • Pipelines

    • LoggedIn

    • LoggingIn

    • Logout

  • Reports - Appears as a shortcut under Sitecore -> Reporting Tools -> PowerShell Reports.

  • Toolbox - Appears as a shortcut under Sitecore -> Toolbox. Visibility can be control using rules made available from within the Interactive field section.

  • Tasks - Not a formal integration point library, but a good place to add scripts used for Scheduled Tasks. SPE includes a PowerShellScriptCommand found under /sitecore/system/Tasks/Commands/PowerShellScriptCommand which is used to run scripts from within scheduled tasks.

  • Web API - Exposes scripts than can be consumed through SPE Remoting. The script can be executed by requesting a specific url.

  • Workflows - Not a formal integration point library, but a good place to add scripts used for Workflow Action Scripts. Read more about how they work here.

  • Other Integrations

    • Remoting - Interact with SPE through the provided web services as described here. A Windows PowerShell module is made available to encapsulate the web service calls into PowerShell commands.

    Syncing Integrations

    Some integrations need to be synced with the Core database through the ISE. See the Settings section of the Scripting documents for instructions.

    Content Editor

    Package Generator

  • Task Management

  • Platform

  • Available Tools

    Index Viewer

    This tool provides similar functionality to the Index Viewer module. Search and rebuild the index on-demand.

    Index Viewer

    Logged in Session Manager

    View the list of user sessions and "kick" them out as needed.

    Logged in Session Manager

    Rules based report

    Generate a report using the Sitecore Rules Engine.

    Rules based report

    PowerShell Background Session Manager

    View the list of SPE sessions and "kill" them as needed.

    PowerShell Background Session Manager

    Create Anti-Package

    This tool provides similar functionality to the Sitecore Rocks module.

    Create Anti-Package

    Re-create Site from Sitemap

    Simple tool for generating a site tree using an existing sitemap.

    Re-create Site from Sitemap

    Task Manager

    View and manage the configured scheduled tasks.

    Task Manager

    Create Tools for the Toolbox

    To create your own Toolbox item take the following steps: 1. Create the Toolbox folder under an SPE module. Use the context menu to simplify the process.

    • Right click the module name and choose Scripts -> Create libraries for integration points.

      Module Libraries
    • Select the Toolbox item and click Proceed.

      Module Toolbox Library
      1. Create a PowerShell Script under the Toolbox item.

    • Right click the Toolbox library and choose PowerShell Script.

      1. Open and edit the PowerShell Script using the ISE.

      2. Run the Rebuild All command in the ISE by navigating to the Settings

    Toolbox

    System Maintenance

    Archive Sitecore logs, Clean up deleted items older than 30 days

    User Session Management

    Remove idle user sessions

    powershell driven Sitecore scheduled tasks
    PowerShell Script Command
    PowerShell Script Task
    Insert Option for Task
    Run or Edit Task Schedule
    Dialog to Select Task Scripts
    Dialog to Edit Task Schedule

    Contributor Guide

    Support for Sitecore 7 has discontinued with SPE 5.0.

    The following guide should provide you with enough information to setup a development environment configured to contribute to SPE. We'll begin with a single installation of Sitecore 8+.

    The solution requires Visual Studio 2015 or later.

    This guide assumes a source root location of "C:\Source" and a site root location of "C:\inetput\wwwroot". These are not prerequisites of the project, and you can use whatever folder locations suit you.

    Single Instance for Sitecore 8 & 9

    1. Meet the prerequisites found

    2. Install Sitecore 8+ to a folder of your choice, for example C:\inetpub\wwwroot\SitecoreSPE_8

    3. Clone the repo to your local development environment

    Any changes you make going foward just require a build of the solution. Remember that when pulling down updates to the source, you should execute a Unicorn sync to ensure your items are up to date.

    Multiple Instances

    The SPE deployment process supports multiple sites and multiple versions of Sitecore. The following steps carry on from above to add further support for another Sitecore site, such as 8.x or 9.x.

    1. Complete the steps for a Single Instance.

    2. Install Sitecore 8.x/9.x to a folder of your choice, for example C:\inetpub\wwwroot\SitecoreSPE_91

    3. Edit the sites definition in deploy.user.json to add your new Sitecore web root folder. Set the version property to 9.0

    SPE can be deployed to as many Sitecore sites as you like. Each time you first deploy to a new installation, make sure you use Unicorn to sync the latest state of items into Sitecore.

    Optional: PowerShell Remoting support

    To add the SPE PowerShell Remoting Module scripts into your machine's PowerShell Module path, execute the .\Setup_Module.ps1 script from the source folder. This will add the \Modules folder from source into your PSModulePath environment variable. Once this is done, you can use Import-Module SPE on your development machine to run the remoting scripts.

    Optional: Junction Support

    As part of the SPE deployment process, all of the relevant binary, configuration and sitecore module files are copied over from the projects within the solution. This means that any changes to static files such as JS / CSS files require a full build for these to be deployed to the site. As the build triggers an application pool recycle of your site, this can be a little slow for quick changes.

    For more rapid development, you can enable junction deployment on your sites. When this is enabled, rather than copying over the static files, will be setup for various folders so that the folders within the Sitecore installation are directly linked to the source folder. Any changes made in the solution are seen instantly, because the solution and the site are referencing the exact same files.

    To enable a junction deployment for a site, add junction property to the site definition and set it to true:

    Note that with junction deployments, a solution build is still required if you want to deploy any code or .config changes.

    It is not currently supported for a junction deployment site to be changed back into a non-junction deployment site. If you wish to do this, you should manually delete the following folders from your Sitecore installation before updating the junction property back to false: sitecore modules\PowerShell and sitecore modules\Shell\PowerShell

    Invoke-JavaScript

    Syntax

    Detailed Description

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Script <String>

    Aliases

    -OnScriptEnd <SwitchParameter>

    Aliases

    Get-Cache

    Retrieves a Sitecore cache.

    Syntax

    Get-Cache [[-Name] <String>]

    Detailed Description

    The Get-Cache command retrieves a Sitecore cache.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Name <String>

    Name of the cache to retrieve. Supports wildcards.

    Aliases

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Caching.Cache

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    Common Pitfalls

    Avoid these common mistakes when learning SPE.

    Avoid these common mistakes when starting with SPE. Learning from others' errors will save you time and frustration.

    Forgetting Item Editing Context

    Items in Sitecore cannot be modified directly. You must use the editing context.

    Scripting

    The Integrated Scripting Environment (ISE) is a great way to group together commands and save for later use. This tool helps you write scripts in Powerful Ways!

    The default security configuration for SPE requires the ISE to be in an before executing scripts. The following figure shows the ISE when the User Account Controls (UAC) are disabled. While this is a common configuration for developers, we highly encourage you to ensure UAC is enabled in higher environments.

    Let's have a quick walk through of each ribbon tab available.

    Home Tab

    Get-Database

    Retrieves a Sitecore Database.

    Syntax

    Get-Database [[-Name] <String>] [-Item <Item>]

    Invoke-JavaScript [-Script] <String> [-OnScriptEnd <SwitchParameter>] [<CommonParameters>]

    Remove one character from right/left to the cursor

    ArrowLeft/Ctrl+B

    Move cursor to the left

    ArrowRight/Ctrl+F

    Move cursor to the right

    Ctrl+ArrowLeft

    Move cursor to previous word

    Ctrl+ArrowRight

    Move cursor to next word

    Ctrl+A/Home

    Move cursor to the beginning of the line

    Ctrl+E/End

    Move cursor to the end of the line

    Ctrl+K/Alt+D

    Remove the text after the cursor

    Ctrl+H

    Remove character before the cursor

    Ctrl+D/Delete

    Remove character selected by the cursor

    Ctrl+C/Escape

    Remove all text in the line

    Ctrl+U

    Remove the text before the cursor

    Ctrl+V/Shift+Insert

    Insert text from the clipboard

    Ctrl+Alt+Shift +

    Increase the font size

    Ctrl+Alt+Shift -

    Decrease the font size

    PageUp

    Scroll console up

    PageDown

    Scroll console down

    Ctrl+R

    Reverse search history

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Providers
    Your First Scripts
    Common Pitfalls
    Integration Points
    Packaging
    Next Steps
    Security Policies
    GitHub
    synced (see below)
    Copy
    C:\Source\Console\deploy.user.json.sample
    to
    C:\Source\Console\deploy.user.json
    . This will be a file just for your local environment and will be ignored by git.
  • Edit the sites definition in deploy.user.json to target your Sitecore web root folder, making sure you use double-slashes for paths like in the existing file. For this site, make sure the version property is 8. Remove any other sites in the file that do not apply.

    The deploy.user.json file supports deploying SPE to multiple Sitecore installations. For now, we are just deploying to a single instance, but later on in the tutorial we will cover multiple instances.

  • Copy C:\Source\Console\UserConfiguration\App_Config\Include\z.Spe.Development.User.config.sample to a file of the same name, without the .sample suffix. This file can be edited to add any SPE-specific configuration that you want in your sites, but don't wish to commit back into the repo.

    You may notice there is a %%sourceFolder%% value in this configuration file. This is a special string that gets replaced as part of the SPE deployment with your source folder location. You don't need to update this manually.

  • Open the solution in Visual Studio.

  • Compile the solution. Whenever you compile the solution, SPE will be automatically deployed to the site web root paths you have set in deploy.user.json

  • Login to Sitecore

  • Navigate to /Unicorn.aspx. Use Unicorn to sync all projects into Sitecore.

    SPE uses Unicorn for serializing Sitecore items to the source folder, and for syncing items from disk into Sitecore. For more information on Unicorn, see https://github.com/kamsar/Unicorn

  • SPE is now installed in Sitecore and you're ready for developing!

  • ,
    9.1
    or
    9.2
    depending on the major/minor version.
  • Follow steps 7 onward from the Single Instance guide above to deploy to your Sitecore 8.x/9.x installation and sync the SPE items into Sitecore.

  • here
    junction points

    Required?

    false

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/
    The Problem
    • ❌ Wrong: $item["Title"] = "New Title" (changes won't save!)

    • ✅ Correct:

    Why It Matters

    Without BeginEdit() and EndEdit(), changes are made to the in-memory object but never persisted to the database.

    Best Practice Pattern

    Always use try-catch to handle errors properly:

    Read more: Editing Items

    Using Recursion on Large Trees

    Using -Recurse carelessly can cause performance problems or even crash your session.

    The Problem

    Why It's Problematic

    • On large content trees, this can take minutes or hours

    • May consume excessive memory

    • Can cause session timeouts

    • Locks up the browser

    Better Approaches

    Option 1: Limit the Scope

    Option 2: Use Content Search

    Option 3: Limit Depth

    Read more: Find-Item | Best Practices

    Ignoring Security

    SPE is powerful, which makes security critical.

    Common Security Mistakes

    • ❌ NEVER run scripts from unknown sources

    • ❌ NEVER deploy SPE without reviewing security settings

    • ❌ NEVER install SPE on CD (Content Delivery) servers

    • ✅ Always review and understand scripts before running

    • ✅ Use role-based access control

    • ✅ Test in development first

    Review the Security Hardening Guide and complete the Security Checklist before deploying to any non-development environment.

    Confusing PowerShell Comparison Operators

    PowerShell uses different operators than most programming languages. See Language Basics for the complete comparison operator reference.

    Examples

    Learn more: Language Basics - Comparisons

    Forgetting About Language Versions

    Items in Sitecore can have multiple language versions, which affects querying and editing.

    The Problem

    Working with Languages

    Read more: Item Languages

    Suppressing Output Incorrectly

    Different methods of suppressing output have very different performance characteristics.

    The Problem

    Performance Comparison

    Next Steps

    Now that you know what to avoid:

    1. Review your scripts: Look for these pitfalls in existing code

    2. Practice safely: Test in development before production

    3. Learn best practices: Read Best Practices

    4. Secure your installation: Complete the Security Checklist

    Everyone makes mistakes when learning. The key is learning from them and building better habits!

    Detailed Description

    The Get-Database command retrieves one or more Sitecore Database objects based on name or item passed to it.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Name <String>

    Name of the database to be returned.

    Aliases

    Required?

    false

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    -Item <Item>

    Database returned will be taken from the item passed to the command.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

      System.String

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Database

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    EXAMPLE 2

    EXAMPLE 3

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    cd "C:\Source\Console"  // Your local source folder, with a new folder for the solution
    git init
    git remote add origin https://github.com/SitecorePowerShell/Console.git
    git fetch origin
    git checkout -b master --track origin/master
    { 
        "sites": [
            {
                "path": "C:\\inetput\\wwwroot\\SitecoreSPE_8\\Website",
                "version": 8,
                "junction": true
            }
        ]
    }
    PS master:\> Get-Cache -Name master*
    
    Name                                     Enabled       Count       Size   Max Size Default  Scavengable
                                                                                       Priority
    ----                                     -------       -----       ----   -------- -------- -----------
    master[blobIDs]                          True              0          0     512000   Normal       False
    master[blobIDs]                          True              0          0     512000   Normal       False
    master[blobIDs]                          True              0          0     512000   Normal       False
    master[itempaths]                        True            292     108228   10485760   Normal       False
    master[standardValues]                   True             57      38610     512000   Normal       False
    master[paths]                            True            108      13608     512000   Normal       False
    master[items]                            True           1010    5080300   10485760   Normal       False
    master[data]                             True           3427    7420654   20971520   Normal       False
    $item.Editing.BeginEdit()
    $item["Title"] = "New Title"
    $item.Editing.EndEdit()
    foreach($item in $items) {
        $item.Editing.BeginEdit()
        try {
            # Make your changes
            $item["Title"] = "New Title"
            $item["Text"] = "New content"
    
            # Commit changes
            $item.Editing.EndEdit()
        }
        catch {
            # Roll back on error
            $item.Editing.CancelEdit()
            Write-Error "Failed to update $($item.ItemPath): $_"
        }
    }
    # DANGEROUS on large content trees!
    Get-ChildItem -Path "master:\content" -Recurse
    # Recurse only within a specific subtree
    Get-ChildItem -Path "master:\content\home\articles" -Recurse
    # Much faster for large queries
    $parameters = @{
        Index = "sitecore_master_index"
        Criteria = @{Filter = "DescendantOf"; Value = "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"}
    }
    
    $items = Find-Item @parameters | Initialize-Item
    $items = Get-ChildItem -Path "master:\content" -Depth 2
    # WRONG - Using C# operators
    if($count == 0) { }          # Syntax error!
    
    # RIGHT - Using PowerShell operators
    if($count -eq 0) { }         # Correct
    
    # WRONG - Case-sensitive by default assumption
    if($name -eq "MICHAEL") { }  # Will match "michael"!
    
    # RIGHT - Explicit case-sensitive check
    if($name -ceq "MICHAEL") { } # Only matches exact case
    # This gets the item in the DEFAULT language (usually en)
    $item = Get-Item -Path "master:\content\home"
    $item["Title"]  # Returns English title
    # Get specific language version
    $item = Get-Item -Path "master:\content\home" -Language "de-DE"
    
    # Get all language versions
    $item = Get-Item -Path "master:\content\home"
    $allVersions = Get-ItemField -Item $item -IncludeStandardFields -Name "*" -ReturnType Field
    
    # Edit specific language
    $item = Get-Item -Path "master:\content\home" -Language "de-DE"
    $item.Editing.BeginEdit()
    $item["Title"] = "Deutscher Titel"
    $item.Editing.EndEdit()
    # SLOW - Out-Null is a cmdlet, adds pipeline overhead
    $builder.Append("Text") | Out-Null
    
    # FAST - Redirect to $null
    $builder.Append("Text") > $null
    # Slow (don't use for simple suppression)
    $list.Add($item) | Out-Null
    
    # Fast (use this instead)
    $list.Add($item) > $null
    PS master:\> Get-Database
    Name                 Languages                      Protected  Read Only
    ----                 ---------                      ---------  ---------
    core                 {da, pl-PL, ja-JP, en...}      False      False
    master               {en, de-DE, es-ES, pt-BR...}   False      False
    web                  {es-ES, de-DE, pt-BR, pl-PL... False      False
    filesystem           {en, en-US}                    False      True
    PS master:\> Get-Database -Name "master"
    
    Name                 Languages                      Protected  Read Only
    ----                 ---------                      ---------  ---------
    master               {en, de-DE, es-ES, pt-BR...}   False      False
    PS master:\> Get-Item . | Get-Database
    
    Name                 Languages                      Protected  Read Only
    ----                 ---------                      ---------  ---------
    master               {en, de-DE, es-ES, pt-BR...}   False      False
    tab and selecting the icon to rebuild. Be certain to enable the module before running the rebuild command.
    ISE Settings Tab
  • Verify the new toolbox item appears in the Toolbox.

    Toolbox
  • Libary Script
    ISE Edit

    Write:

    • New - Creates a new script or module.

    • Open - Opens an existing script for the library.

    • Save - Saves the current script to the library.

    • Save As - Saves a copy of the current script to the library.

    • Reload - Opens the original copy of the current script without saving any modifications.

  • Script Execution:

    • Execute - Runs the current script as a background job or in the HttpContext.

    • Selection - Runs the selected text of the current script.

    • Debug - Runs the current script with the debugging mode enabled. A temporary file is generated on the file system to support the use of breakpoints.

    • Abort - Stops the execution of an executing script.

  • Context:

    • Context - Specifies the current item in the script. Helpful if you write a script dependent on a specific path, or the current directory is denoted as a . (dot) or _$pwd (_present working directory). An MRU and tree view are provided for choosing a path.

    • Session - Specifies the session to use when executing the script. Reused sessions live in the HttpSession. Options include the session created for the ISE instance, One-Time session, or the Persistent Session ID configured on the script.

  • UI Context:

    • Language - Specifies the context language to use when executing the script.

    • User - Specifies the context user to impersonate when executing the script. This can be used to emulate UserSwitcher code.

  • Settings Tab

    ISE Settings Tab
    • Preferences:

      • Settings - This is where you configure the Console and ISE font family, font size, and other useful things.

    • Integration:

      • Rebuild All - This is where you rebuild the integration points for Control Panel, Gutters, and Ribbons. Without running this you will not see those integrations appear (or disappear).

    Plugins Tab

    The plugins feature is a great way to add custom behaviors while in the ISE. Any plugin added can make use of the Enable or Show rules to control how it appears in the ribbon.

    ISE Plugins Tab
    • Platform: Custom scripts added to the ISE Plugins integration point script library will appear here.

    The Open dialog provides both a search and tree view of the scripts stored in the script libraries.

    Open Script Dialog

    Shortcuts

    Below are the shortcuts available in the ISE.

    Shortcut

    Usage

    TAB

    Indent

    Ctrl

    Bypass cached variable value when pressed.

    Ctrl-Space

    Autocomplete commands. Use the up or down direction keys to cycle through options.

    Ctrl-Enter

    Displays the command help window.

    Ctrl-Z

    Undo the previous change.

    Ctrl-Alt-Shift +

    Increase the font size

    For more commands built into the script editor see here

    Elevated Session State
    PowerShell ISE

    Community

    See some of the community contributed modules built for SPE.

    There are some really amazing contributions and add-ons to SPE from the community.

    Unicorn

    SPE + Unicorn

    A well known and widely adopted module Unicorn has published some SPE commands. These commands are available (and optional) after installing Unicorn. Below are some samples ripped off from Kam Figy's blog posts here and here.

    Configurations

    Example: The following lists configurations by name.

    Syncing

    Example: The following syncs configurations just like you would through the Unicorn Control Panel or the PowerShell API.

    Partial Syncing

    Reserializing

    Partial Reserializing

    Converting to Raw Yaml

    Converting from Raw Yaml

    Deserialization

    Packaging

    SPE Modules

    The following are Sitecore modules that enhance the SPE experience.

    • :

    • :

    • :

    Working with Items

    The Sitecore PowerShell Extensions (SPE) module provides powerful cmdlets for managing Sitecore content items. This section covers everything you need to know about working with items programmatically.

    Quick Start

    The core item management cmdlets mirror standard PowerShell conventions:

    Cmdlet
    Purpose
    Example

    Documentation Topics

    Fundamentals

    Before working with items, understand these foundational concepts:

    • - PowerShell providers and navigating Sitecore databases

    • - Built-in variables available in SPE scripts

    Core Item Operations

    Learn how to perform essential item operations:

    • - Find items by path, ID, query, or URI

    • - Update properties, work with field types, and manage versions

    • - Create new items and delete existing ones

    • - Transfer and duplicate items

    Specialized Operations

    Handle specific aspects of item management:

    • - Add, remove, and manage language versions

    • - Work with presentation details and renderings

    • - Manage item permissions and access control

    Advanced Topics

    Optimize your scripts and follow best practices:

    • - Performance optimization, bulk operations, and coding patterns

    Common Patterns

    Pattern: Find and Update Items

    Pattern: Bulk Create Items

    Pattern: Copy Content Between Databases

    Pattern: Audit and Report

    Dynamic Parameters

    SPE extends standard PowerShell cmdlets with dynamic parameters specific to Sitecore. These parameters appear based on context:

    • Language - Specify language versions (-Language "en-US" or -Language *)

    • Version - Specify item versions (-Version 2 or -Version *)

    • Database - Target specific databases when using IDs

    See the page for detailed parameter documentation.

    Path Formats

    SPE supports multiple path formats for flexibility:

    Note: The /sitecore portion is optional when using provider paths.

    Working with Field Types

    SPE provides intelligent handling of Sitecore field types through automated PowerShell properties:

    See for comprehensive field type examples.

    Performance Considerations

    When working with large datasets, consider these performance tips:

    • Use fast: queries instead of Get-ChildItem -Recurse when possible

    • Leverage BulkUpdateContext for multiple updates

    • Use SecurityDisabler judiciously for read operations

    See for detailed performance guidance.

    See Also

    • - Securing SPE and managing users/roles

    • - Core cmdlet reference

    • - Security cmdlet reference

    • - Automate item operations remotely

    Getting Help

    Getting Started

    This guide helps you quickly secure your Sitecore PowerShell Extensions installation with essential security configurations.

    Critical Security Warnings

    Never install SPE in internet-facing environments!

    • DO NOT install on Content Delivery (CD) instances

    • DO NOT deploy on servers facing the Internet

    • DO NOT expose SPE endpoints to untrusted networks

    SPE is a powerful development and administration tool intended for Content Management (CM) servers in protected internal networks only.

    Quick Security Checklist

    Before deploying SPE to any environment beyond your local development machine, complete these essential steps:

    ✓ Environment Assessment

    ✓ Web Services Security

    By default, all SPE web services are disabled except those required for the Sitecore UI. Keep them disabled unless you have a specific need.

    ✓ User Access Control

    ✓ Application Pool Security

    ✓ Content Editor Security

    Initial Configuration Steps

    Step 1: Review Default Settings

    The default security configuration is found in:

    • App_Config\Include\Spe\Spe.config

    Do not modify this file directly. Instead, create configuration patch files.

    Step 2: Create Your Security Patch

    Create a new configuration file: App_Config\Include\Spe\Custom\Spe.Custom.config

    Example: Basic production security configuration:

    Step 3: Configure IIS Authentication

    Protect the SPE services directory at the IIS level.

    Edit sitecore modules\PowerShell\Services\web.config:

    This denies anonymous access to all SPE web services.

    Step 4: Test Your Configuration

    1. Log in as a non-administrator user

    2. Verify you cannot access the PowerShell Console

    3. Verify you cannot access the PowerShell ISE

    4. Log in as an administrator

    Environment-Specific Recommendations

    Development Environment

    For local development machines, you may use relaxed settings:

    Never use elevationAction="Allow" in non-development environments!

    QA/Staging Environment

    Use the same strict security as production, but you may extend session timeouts slightly for testing convenience:

    Production Environment

    Use the strictest settings:

    For Azure AD/SSO environments, use:

    Identity Server Configuration (Sitecore 9.1+)

    If using Sitecore 9.1 or later with Identity Server, enable this configuration file:

    File: App_Config\Include\Spe\Spe.IdentityServer.config

    This prevents infinite loops in the SPE Console when using OWIN cookie authentication.

    Next Steps

    After completing the initial setup:

    1. Review the to understand the security model

    2. Configure for your environment

    3. If you need external access, carefully review security

    4. Learn about

    Common Mistakes to Avoid

    ❌ Don't install on CD servers - SPE is for CM only ❌ Don't expose to the internet - Keep SPE behind firewalls ❌ Don't use Allow elevation in production - Always require password or confirmation ❌ Don't enable unnecessary web services - Only enable what you specifically need ❌ Don't grant broad access - Limit to administrators only ❌ Don't skip session elevation - UAC is critical for production environments

    Getting Help

    If you need assistance with SPE security:

    • Review the detailed documentation

    • Check the

    • Visit the

    • Join #module-spe on Sitecore Community Slack

    Get-ItemClone

    Returns all the clones for the specified item.

    Syntax

    Get-ItemClone [-Item] <Item>

    Get-ItemClone [-Path] <String>

    Get-ItemClone -Id <String> [-Database <String>]

    Detailed Description

    The Get-ItemClone command returns all the clones for the specified item.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    The item to be analysed for clones presence.

    Aliases

    -Path <String>

    Path to the item to be analysed for clones presence.

    Aliases

    -Id <String>

    Id of the item to be analysed for clones presence.

    Aliases

    -Database <String>

    Database containing the item to be processed - if item is being provided through Id.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    Get-SitecoreJob

    Returns list of the current sitecore jobs

    Syntax

    Get-SitecoreJob

    Detailed Description

    The Get-SitecoreJob command returns the list of the currently running jobs of Sitecore.

    © 2010-2019 Implemented by Vangasewinkel Benjamin using the Adam Najmanowicz, Michael West Sitecore PowerShell Extensions. All rights reserved.

    Parameters

    None

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Jobs.Job

    Notes

    Help Author: Vangansewinkel Benjamin

    Examples

    EXAMPLE 1

    EXAMPLE 2

    EXAMPLE 3

    Related Topics

    Variables

    There are several variables available out of the box for use in running commands and scripts. Many of the variables prefixed with Sitecore derive from the Sitecore.config settings. Run the command Get-Variable to see the complete list available in the currently running session.

    Variable

    Example

    AppPath

    C:\Inetpub\wwwroot\Console\Website\

    HostSettings

    ... FontSize : 12 FontFamily : Wingdings ...

    me

    sitecore\admin

    Note: Any new variables created are stored within the current session; when the session ends the variables are removed. Be careful not to overwrite the built-in variables.

    Providers

    Understanding PowerShell providers and the Sitecore provider.

    The provider architecture in PowerShell enables a developer to make a command like Get-Item interact with the filesystem files and folders, and then interact with the Sitecore CMS items. This is one of the most powerful concepts in PowerShell!

    What is a Provider?

    A provider is an adapter that makes a data store look like a drive. Think of it like this:

    • File system provider

    Your First Scripts

    Hands-on examples to get you started with practical Sitecore automation.

    Now that you understand the basics, let's put it all together with practical Sitecore automation tasks. These examples demonstrate real-world scenarios you'll encounter when working with SPE.

    Example 1: Find Items Ready for Review

    Goal: Find all items under /sitecore/content/home that are in a specific workflow state.

    What just happened?

    Moving and Copying Items

    This page covers how to move and copy Sitecore items using SPE, including transfers within databases and between databases.

    Moving Items

    Use Move-Item to transfer items from one location to another. The item retains its ID and all version history.

    Reports

    The reports which come out of the box provide a wide variety of information regarding your Sitecore installation.

    We've built quite a few reports, many similar to the (ASR) module.

    Running a Report

    The custom reports can be found by navigating to Sitecore -> Reporting Tools -> PowerShell Reports.

    As an example, let's run the Unused media items report.

    Remoting

    There are a number of use cases where you need to remotely run scripts within SPE. Here we will try to cover a few of those use cases.

    Remoting Automation Service

    We have provided a handy way of executing scripts via web service using the Remoting Automation Service.

    Get-ItemCloneNotification

    Syntax

    Detailed Description

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Import-Function

    Imports a function script from the script library's "Functions" folder.

    Syntax

    Import-Function [-Name] <String> [-Library <String>] [-Module <String>]

    Users and Roles

    Managing users and roles is a big topic and this section won't cover everything. We aim to show you different problems that have come up and how we solved them.

    Example: The following command returns the security commands available.

    Users

    Managing users should be a pretty straight forward task. While the User Manager provided by Sitecore is handy, you'll likely find yourself wanting to make bulk changes. The following examples should give you a few ideas about how to manage user accounts.

    PWD

    master:\

    PSScript

    $PSScript.Appearance.Icon # Returns the icon of the executing script

    ScriptSession

    ... ID : e9fedd64-cad0-4c43-b950-9cd361b151fd ...

    SitecoreAuthority

    https://console

    SitecoreContextItem

    $SitecoreContextItem.Language.Name # Returns the language name

    SitecoreDataFolder

    C:\Inetpub\wwwroot\Console\Data

    SitecoreDebugFolder

    C:\Inetpub\wwwroot\Console\Data\debug

    SitecoreIndexFolder

    C:\Inetpub\wwwroot\Console\Data\indexes

    SitecoreLayoutFolder

    C:\Inetpub\wwwroot\Console\Website\layouts

    SitecoreLogFolder

    C:\Inetpub\wwwroot\Console\Data\logs

    SitecoreMediaFolder

    C:\Inetpub\wwwroot\Console\Website\upload

    SitecorePackageFolder

    C:\Inetpub\wwwroot\Console\Data\packages

    SitecoreScriptRoot

    master:\system\Modules\PowerShell\Script Library\Task Management\Toolbox

    SitecoreCommandPath

    master:\system\Modules\PowerShell\Script Library\Task Management\Toolbox\Task Manager

    SitecoreSerializationFolder

    C:\Inetpub\wwwroot\Console\Data\serialization

    SitecoreTempFolder

    C:\Inetpub\wwwroot\Console\Website\temp

    SitecoreVersion

    8.2.160729

    Ctrl-Alt-Shift -

    Decrease the font size

    Ctrl-E

    Executes the script

    Alt-E

    Executes the selected text in the script

    Ctrl-D

    Debugs the script

    Ctrl-Shift-E

    Aborts the running script

    Ctrl-F

    Search for keywords in the script

    #1346

    Query - Execute Sitecore queries (query: or fast:)

  • ID - Work with items by GUID

  • Uri - Use ItemUri for complete item identification

  • Batch operations and provide progress feedback

    Get-Item

    Retrieve a single item

    Get-Item -Path "master:\content\home"

    Get-ChildItem

    Retrieve children and descendants

    Get-ChildItem -Path "master:\content" -Recurse

    New-Item

    Create a new item

    New-Item -Path "master:\content\home" -Name "Page" -ItemType "Sample/Sample Item"

    Set-ItemProperty

    Update item properties

    Set-ItemProperty -Path "master:\content\home" -Name "Title" -Value "Welcome"

    Copy-Item

    Duplicate an item

    Copy-Item -Path "master:\content\home\source" -Destination "master:\content\home\target"

    Move-Item

    Transfer an item

    Move-Item -Path "master:\content\home\old" -Destination "master:\content\home\new"

    Remove-Item

    Delete or recycle an item

    Remove-Item -Path "master:\content\home\demo" -Permanently

    Providers
    Variables
    Retrieving Items
    Editing Items
    Creating and Removing Items
    Moving and Copying Items
    Item Languages
    Item Renderings
    Item Security
    Best Practices
    Retrieving Items
    Editing Items
    Best Practices
    Security
    Appendix - Common
    Appendix - Security
    Remoting

    Review the Session Elevation documentation

    Verify Session Elevation prompts appear when expected
  • Test that scripts execute successfully after elevation

  • Complete the Security Checklist before deployment

    Web Services
    Security Policies
    Session Elevation
    Web Services
    User and Role Management
    Security Hardening
    Security Checklist
    GitHub repository

    Get-Item

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    New-ItemClone
    ConvertFrom-ItemClone
    https://github.com/SitecorePowerShell/Console/
    https://github.com/SitecorePowerShell/Console/issues/218
    https://github.com/SitecorePowerShell/Console/
    https://www.youtube.com/watch?v=N3xgZcU9FqQ&list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b&index=9
    Example 3

    Retrieved the home item using the Sitecore provider → Learn more

  • Queried all child items recursively

  • Filtered by workflow field value → Learn more

  • Displayed results as a report → Learn more

  • Example 2: Bulk Update Item Fields

    Goal: Update a field value on multiple items.

    Key concepts demonstrated:

    • Filtering by template → Templates

    • Proper item editing workflow → Editing Items

    • Using PowerShell loops and variables

    Always use BeginEdit() and EndEdit() when modifying items. Changes won't persist without this pattern.

    Example 3: Interactive User Input

    Goal: Create a script that prompts the user for input and processes items based on their choices.

    Interactive concepts:

    • Using Read-Variable for user input

    • Parameter validation

    • Conditional logic based on user choices

    • See Interactive Dialogs for more

    Try It Yourself

    Ready to experiment? Follow these steps:

    Step 1: Open the ISE

    In Sitecore, go to Desktop → Development Tools → PowerShell ISE

    Step 2: Run Your First Command

    Try these commands in the script editor:

    Step 3: Execute the Script

    Click the Execute button (or press Ctrl+E)

    Step 4: Explore the Results

    • Examine the object properties returned

    • Try modifying the filters

    • Experiment with different paths

    The ISE provides IntelliSense, syntax highlighting, and debugging capabilities. It's the best place to learn and develop SPE scripts. See Scripting for more details.

    Practice Exercises

    Test your knowledge with these exercises:

    Exercise 1: Find Empty Items

    Write a script that finds all items under /sitecore/content that have an empty Title field.

    Solution

    Exercise 2: Count Items by Template

    Write a script that counts how many items exist for each template under /sitecore/content/home.

    Solution

    Exercise 3: Export Item Data

    Export all items under a specific path to a CSV file with their Name, Path, Template, and Last Updated date.

    Solution

    Common Patterns

    Here are some frequently used patterns you'll encounter:

    Pattern: Safe Item Editing

    Pattern: Check if Item Exists

    Pattern: Process Items with Progress

    Next Steps

    Congratulations! You've completed your first SPE scripts. Now:

    1. Avoid common mistakes: Review Common Pitfalls

    2. Build on this knowledge: Explore Working with Items

    3. Create custom reports: Learn Authoring Reports

    4. Share your scripts: Build a Script Library

    The best way to learn is by doing. Try modifying these examples for your own use cases!

    Parameters

    -NotificationType <NotificationType>

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Language <String[]>

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Item <Item>

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Examples

    EXAMPLE 1

    The following gets the cloned Item and returns the available notifications.

    EXAMPLE 2

    The following gets the cloned Item based on the specified type of notification.

    Detailed Description

    The Import-Function command imports a function script from the script library's "Functions" folder.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Name <String>

    Name of the script in the "Functions" library or one of its sub-libraries.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Library <String>

    Name of the library withing the "Functions" library. Provide this name to disambiguate a script from other scripts of the same name that might exist in multiple sub-librarties of the Functions library.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Module <String>

    Name of the module "Functions" are going to be taken from. Provide this name to disambiguate a script from other scripts of the same name that might exist in multiple Modules.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • System.Object

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    The following imports a Resolve-Error function that you may later use to get a deeper understanding of a problem with script should one occur by xecuting the "Resolve-Error" command that was imported as a result of the execution of the following line

    Related Topics

    • Invoke-Script

    • https://github.com/SitecorePowerShell/Console/

    Query users and update properties

    Example: The following generates a batch of test users in the default domain with the out-of-the-box user profile template. The users are then queried filtering on the name.

    In case you forgot to set the user profile for accounts, we have a solution for that.

    Example: The following queries a user and sets the profile template. Note that changing the profile template requires the user to be authenticated.

    Example: The following queries all the user accounts for the default provider and filters those over the age of 18. The age property is custom on the Profile. Finally, export to CSV.

    Roles

    Example: The following queries roles using the specified identity.

    Example: The following finds all roles and exports to a report.

    Example: The following adds a user to a role.

    Example: The following removes a user from a role.

    See Also

    • Working with Items - Item Security - Managing item-level security and ACLs

    • Appendix - Security Commands - Full security cmdlet reference

    References

    • Using Get-User command to query over 200k users

    • Explore Sitecore Users Properties

    # Find all items of a specific template and update a field
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" } |
        ForEach-Object {
            $_.Title = "Updated Title"
        }
    # Create multiple items from a data source
    $data = Import-Csv "C:\data\pages.csv"
    foreach($row in $data) {
        New-Item -Path "master:\content\home" -Name $row.Name -ItemType "Sample/Sample Item"
    }
    # Copy an item tree from master to web
    $sourceItem = Get-Item -Path "master:\content\home\campaign"
    Copy-Item -Path $sourceItem.ProviderPath -Destination "web:\content\home" -Recurse
    # Generate a report of items modified in the last 7 days
    $startDate = (Get-Date).AddDays(-7)
    Get-ChildItem -Path "master:\content" -Recurse |
        Where-Object { $_.__Updated -gt $startDate } |
        Select-Object Name, ItemPath, __Updated, "__Updated by" |
        Show-ListView -Property Name, ItemPath, __Updated, "__Updated by"
    # Provider path format (recommended)
    Get-Item -Path "master:\content\home"
    
    # Sitecore path format (also works)
    Get-Item -Path "master:/sitecore/content/home"
    
    # Mixed separators (both work)
    Get-Item -Path "master:\content/home"
    Get-Item -Path "master:/content\home"
    $item = Get-Item -Path "master:\content\home"
    
    # DateTime fields return System.DateTime objects
    $item.__Created                              # Returns DateTime
    $item.__Created = [DateTime]::Now           # Assign DateTime
    
    # Image fields accept item references
    $item.Image = Get-Item "master:\media library\logo"
    
    # Link fields accept item references
    $item.Link = Get-Item "master:\content\home\page"
    
    # Multilist fields accept arrays of items
    $item.RelatedPages = Get-ChildItem "master:\content\home"
    # List all item-related commands
    Get-Command -Noun Item*
    
    # Get help for a specific command
    Get-Help Get-Item -Full
    Get-Help Get-ChildItem -Examples
    
    # Find commands by capability
    Get-Command -Noun Item* | Where-Object { $_.Parameters.Keys -contains "Language" }
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <!-- Session Elevation (UAC) -->
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
              <token name="ItemSave">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
    
          <!-- Ensure web services remain disabled -->
          <services>
            <remoting enabled="false" />
            <restfulv1 enabled="false" />
            <restfulv2 enabled="false" />
            <fileDownload enabled="false" />
            <fileUpload enabled="false" />
            <mediaDownload enabled="false" />
            <mediaUpload enabled="false" />
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </configuration>
    <token name="Console">
      <patch:attribute name="expiration">01:00:00</patch:attribute>
      <patch:attribute name="elevationAction">Allow</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="expiration">00:15:00</patch:attribute>
      <patch:attribute name="elevationAction">Password</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="expiration">00:05:00</patch:attribute>
      <patch:attribute name="elevationAction">Password</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="elevationAction">Confirm</patch:attribute>
    </token>
    PS master:\> Get-ItemClone -Path master:\content\home
    PS master:\> Get-SitecoreJob
    
    Category     : PowerShell
    Handle       : b62d9129-298a-4630-bb37-d725e5ce3bbf;DCI5CG6011F3Y-sc81u3contact
    IsDone       : True
    Name         : PowerShell-ca2a0179-78c5-02a4-5970-17e4909752b0-{347EBAF8-6BE2-4ABC-91D0-36B36FCF414B}
    Options      : Sitecore.Jobs.JobOptions
    Status       : Sitecore.Jobs.JobStatus
    WaitHandle   : System.Threading.ManualResetEvent
    QueueTime    : 11/13/2017 1:03:18 PM
    MessageQueue : Sitecore.Jobs.AsyncUI.MessageQueue
    
    Category     : Indexing
    Handle       : dca83fc7-def7-4564-ac44-987e79ffc3cd;DCI5CG6011F3Y-sc81u3contact
    IsDone       : True
    Name         : Index_Update_IndexName=sitecore_analytics_index
    Options      : Sitecore.Jobs.JobOptions
    Status       : Sitecore.Jobs.JobStatus
    WaitHandle   : System.Threading.ManualResetEvent
    QueueTime    : 11/13/2017 1:03:29 PM
    MessageQueue : Sitecore.Jobs.AsyncUI.MessageQueue
    
    Category     : PowerShell
    Handle       : de0a1dce-45f7-44fb-81b5-02b402c1f614;DCI5CG6011F3Y-sc81u3contact
    IsDone       : False
    Name         : PowerShell-ca2a0179-78c5-02a4-5970-17e4909752b0-{47666A58-890B-4D13-8F15-3348643750E4}
    Options      : Sitecore.Jobs.JobOptions
    Status       : Sitecore.Jobs.JobStatus
    WaitHandle   : System.Threading.ManualResetEvent
    QueueTime    : 11/13/2017 1:03:29 PM
    MessageQueue : Sitecore.Jobs.AsyncUI.MessageQueue
    PS master:\> $jobs = Get-SitecoreJob
    PS master:\> $jobs[0].Status
    
    Category     : PowerShell
    Handle       : c9215f66-ce60-49e5-9620-bf1ec51b6ef4;DCI5CG6011F3Y-sc81u3contact
    IsDone       : False
    Name         : PowerShell-ca2a0179-78c5-02a4-5970-17e4909752b0-{DF4895A6-3EBB-4A2A-9756-3A0EF4B96396}
    Options      : Sitecore.Jobs.JobOptions
    Status       : Sitecore.Jobs.JobStatus
    WaitHandle   : System.Threading.ManualResetEvent
    QueueTime    : 11/13/2017 1:05:54 PM
    MessageQueue : Sitecore.Jobs.AsyncUI.MessageQueue
    PS master:\> Get-SitecoreJob | Show-ListView -Property "Category", "IsDone", "Name", "QueueTime", `
        @{Label="Status Expiry"; Expression={$_.Status.Expiry} },
        @{Label="Status Failed"; Expression={$_.Status.Failed} },
        @{Label="Status State"; Expression={$_.Status.State} },
        @{Label="Status Processed"; Expression={$_.Status.Processed} },
        @{Label="Status Total"; Expression={$_.Status.Total} },
        @{Label="Status Message"; Expression={$_.Status.Messages} }
    Get-ChildItem -Path "master:\content" -Recurse |
        Where-Object {
            [string]::IsNullOrEmpty($_.Fields["Title"].Value)
        } |
        Show-ListView -Property Name, ItemPath, TemplateName
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    
    $templateCounts = $items | Group-Object TemplateName |
        Select-Object Name, Count |
        Sort-Object Count -Descending
    
    $templateCounts | Show-ListView
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    
    $export = $items | Select-Object Name,
        @{Name="Path";Expression={$_.ItemPath}},
        @{Name="Template";Expression={$_.TemplateName}},
        @{Name="Updated";Expression={$_."__Updated"}}
    
    $export | Export-Csv -Path "$($SitecoreDataFolder)\items-export.csv" -NoTypeInformation
    Write-Host "Exported $($items.Count) items"
    # Navigate to the home item
    $homeItem = Get-Item -Path "master:\content\home"
    
    # Get all descendants
    $items = Get-ChildItem -Path $homeItem.ProviderPath -Recurse
    
    # Filter items in "Draft" workflow state
    $draftItems = $items | Where-Object {
        $_.Fields["__Workflow state"] -ne $null -and
        $_."__Workflow state" -match "{190B1C84-F1BE-47ED-AA41-F42193D9C8FC}"
    }
    
    # Display results in an interactive list
    $draftItems | Show-ListView -Property Name, ItemPath, "__Updated", "__Updated by"
    # Get items to update
    $items = Get-ChildItem -Path "master:\content\home\articles" -Recurse |
        Where-Object { $_.TemplateName -eq "Article" }
    
    # Update each item
    foreach($item in $items) {
        # Begin editing
        $item.Editing.BeginEdit()
    
        # Update field
        $item["Category"] = "Updated"
    
        # Save changes
        $item.Editing.EndEdit()
    }
    
    Write-Host "Updated $($items.Count) items" -ForegroundColor Green
    # Prompt user for input
    $rootPath = Get-Item -Path "master:\content\home"
    $publishItems = $true
    $props = @{
        Parameters = @(
            @{Name="rootPath"; Title="Root Path"; Tooltip="Select the starting location"},
            @{Name="templateName"; Title="Template Name";
            Source="DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template";
            editor="groupeddroplist"; }
        )
        Title = "Bulk Item Processor"
        Description = "Select items to process"
        Width = 500
        Height = 300
    }
    
    $result = Read-Variable @props
    
    if($result -ne "ok") {
        Exit
    }
    
    # Process items based on user input
    $items = Get-ChildItem -Path $rootPath.ProviderPath -Recurse |
        Where-Object { $_.TemplateName -eq $templateName }
    
    Write-Host "Found $($items.Count) items"
    # Get your home item
    Get-Item -Path "master:\content\home"
    
    # List its children
    Get-ChildItem -Path "master:\content\home"
    
    # Find items by name
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.Name -like "*Sample*" }
    foreach($item in $items) {
        $item.Editing.BeginEdit()
        try {
            $item["FieldName"] = "Value"
            $item.Editing.EndEdit() | Out-Null
        }
        catch {
            $item.Editing.CancelEdit()
            Write-Error "Failed to update $($item.ItemPath): $_"
        }
    }
    $itemPath = "master:\content\home\test"
    if(Test-Path $itemPath) {
        $item = Get-Item $itemPath
        # Process item
    }
    else {
        Write-Host "Item not found" -ForegroundColor Yellow
    }
    $items = Get-ChildItem -Path "master:\content" -Recurse
    $total = $items.Count
    $current = 0
    
    foreach($item in $items) {
        $current++
        Write-Progress -Activity "Processing Items" `
                       -Status "$current of $total" `
                       -PercentComplete (($current / $total) * 100)
    
        # Process item here
    }
    Get-ItemCloneNotification [-Item] <Item> [-NotificationType <Notification | ChildCreatedNotification | FieldChangedNotification | FirstVersionAddedNotification | ItemMovedChildCreatedNotification | ItemMovedChildRemovedNotification | ItemMovedNotification | ItemTreeMovedNotification | ItemVersionNotification | OriginalItemChangedTemplateNotification | VersionAddedNotification>] [-Language <String[]>]
    Get-ItemCloneNotification [-Path] <String> [-NotificationType <Notification | ChildCreatedNotification | FieldChangedNotification | FirstVersionAddedNotification | ItemMovedChildCreatedNotification | ItemMovedChildRemovedNotification | ItemMovedNotification | ItemTreeMovedNotification | ItemVersionNotification | OriginalItemChangedTemplateNotification | VersionAddedNotification>] [-Language <String[]>]
    Get-ItemCloneNotification -Id <String> [-Database <String>] [-NotificationType <Notification | ChildCreatedNotification | FieldChangedNotification | FirstVersionAddedNotification | ItemMovedChildCreatedNotification | ItemMovedChildRemovedNotification | ItemMovedNotification | ItemTreeMovedNotification | ItemVersionNotification | OriginalItemChangedTemplateNotification | VersionAddedNotification>] [-Language <String[]>]
    $clonedItem = Get-Item -Path "master:" -ID "{9F158637-52C2-4005-8329-21527685CB71}"
    Get-ItemCloneNotification -Item $clonedItem
    $clonedItem = Get-Item -Path "master:" -ID "{9F158637-52C2-4005-8329-21527685CB71}"
    $clonedItem | Get-ItemCloneNotification -NotificationType ItemMovedChildRemovedNotification
    PS master:\> Import-Function -Name Resolve-Error
    Get-Command -Noun Role*,User,ItemAcl* | Select-Object -Property Name | Sort-Object -Property Name
    foreach($num in 0..10) {
        $key = -join ((65..90) + (97..122) | Get-Random -Count 7 | % {[char]$_})  
        New-User -Identity "TestUser$($key)" -Enabled -Password "b" -ProfileItemId "{AE4C4969-5B7E-4B4E-9042-B2D8701CE214}" | Out-Null
    }
    
    Get-User -Filter "sitecore\TestUser*"
    Get-User -Id "michael" -Authenticated | 
        Set-User -ProfileItemId "{AE4C4969-5B7E-4B4E-9042-B2D8701CE214}"
    $users = Get-User -Filter * | Where-Object { $_.Profile.GetCustomProperty("age") -gt 18 } 
    
    $property = @(
        "Name",
        @{Name="Age";Expression={ $PSItem.Profile.GetCustomProperty("age") }}
    )
    $users | Select-Object -Property $property | 
      Export-CSV -Path "$($SitecoreDataFolder)\export\users-over-eighteen.csv" -NoTypeInformation
    # Identity can be "[domain]\[name]", "Creator-Owner", and "\Everyone"
    Get-Role -Identity "default\Everyone"
    Get-Role -Filter * | Show-ListView -Property Name, Domain
    $user = Get-User -Identity "sitecore\author"
    $role = Get-Role -Identity "sitecore\Sitecore Client Authoring"
    Add-RoleMember -Identity $role -Members $user
    $user = Get-User -Identity "sitecore\author"
    $role = Get-Role -Identity "sitecore\Sitecore Client Authoring"
    Remove-RoleMember -Identity $role -Members $user
    :
  • Westco Image Optimizer : Michael West

  • SPE Image Importer
    Himadri Chakrabarti
    Multi-Item Publish
    Richard Seal
    Publish Status
    Morten Engel
    Example Syncing
    Converting To Yaml
    Converting from Yaml
    Deserialization
    Westco Pull Up Fields
    Michael West
    : Makes
    C:\
    look like a navigable drive
  • Registry provider: Makes HKLM:\ look like a navigable drive

  • Sitecore provider: Makes master:\ look like a navigable drive

  • This means you can use the same commands (Get-Item, Get-ChildItem, etc.) to work with files, registry keys, and Sitecore items!

    Available Providers

    The SPE module implements a new provider that bridges the Windows PowerShell platform with the Sitecore API. The following table demonstrates the use of Get-Item for a variety of providers.

    Name
    Drives
    Example

    Alias

    Alias

    Get-Item -Path alias:\dir

    Sitecore

    core, master, web

    Get-Item -Path master:\

    Environment

    Env

    Get-Item -Path env:\HOMEPATH

    FileSystem

    C, D, F, H

    Get-Item -Path c:\Windows

    The Sitecore Provider

    The most important provider for SPE is named Sitecore. This provider gives you access to Sitecore databases.

    Default Provider

    The default provider used by the PowerShell Console and ISE is Sitecore with the drive set to the master database.

    Database Drives

    The Sitecore provider exposes these databases as drives:

    Path Format

    Sitecore provider paths follow this format:

    Examples:

    Notice that the Sitecore provider supports backslashes (\) and forward slashes (/) like the Sitecore UI.

    • ✅ Correct: master:\content\home

    • ✅ Correct: master:/content/home

    • ❌ Wrong: /sitecore/content/home

    Switching Between Providers

    Example: The following demonstrates switching between providers using the function cd, an alias for Set-Location, while in the Console.

    You may have noticed that the C drive is the only path in which a backslash was used before changing drives. Leaving off the backslash will result in the path changing to C:\windows\system32\inetsrv. This similar behavior can be experienced while in the Windows PowerShell Console, where the path is changed to C:\Windows\System32.

    Working with the Sitecore Provider

    Getting Items

    Creating Items

    Removing Items

    Testing if Item Exists

    Provider-Specific Features

    While all providers support basic operations like Get-Item and Get-ChildItem, some have special features:

    Sitecore Provider Features

    File System Provider Features

    Why Providers Matter

    Understanding providers is crucial because:

    1. Same commands work everywhere - Learn Get-Item once, use it for files, registry, and Sitecore

    2. Path-based navigation - Everything has a path you can navigate

    3. Consistent patterns - If it works on files, it probably works on Sitecore items

    4. Powerful automation - Combine providers to move data between systems

    Example: Cross-Provider Automation

    Common Provider Operations

    Operation
    File System
    Sitecore

    Get item

    Get-Item C:\file.txt

    Get-Item master:\content\home

    List children

    Get-ChildItem C:\

    Get-ChildItem master:\content

    Create

    New-Item C:\file.txt

    New-Item master:\content\home\item

    Remove

    Remove-Item C:\file.txt

    Learn More

    This introduction covers the basics of the provider architecture and how to use paths in SPE.

    For comprehensive details about working with the Sitecore provider (item fields, languages, versions, wildcards, performance optimization, and advanced techniques), see the complete guide: Working with Items - Providers

    Next Steps

    Now that you understand providers:

    1. Practice with examples: Your First Scripts

    2. Avoid common mistakes: Common Pitfalls

    3. Deep dive into items: Working with Items

    4. Read comprehensive provider docs: Providers

    Basic Move Operations

    Example: Move an item to a new parent.

    If the destination item exists, the moved item becomes a child of the destination. If the destination doesn't exist, the source item is renamed during the move.

    Example: Move and rename in one operation.

    Moving via Pipeline

    Example: Get an item and move it using the pipeline.

    Moving with Children

    By default, Move-Item moves the item and all its descendants.

    Example: Move an entire content tree.

    Copying Items

    Use Copy-Item to duplicate items. By default, the copy receives a new ID.

    Basic Copy Operations

    Example: Copy an item to a new location and change display name.

    The item name in the destination path determines the new item's name. Lowercase names in the destination result in lowercase item names.

    Example: Copy and return the new item.

    Recursive Copying

    Example: Copy an entire tree maintaining structure.

    Copying Between Databases

    Copy items between databases (e.g., from master to web) using transfer options.

    Example: Transfer item with same ID to another database.

    Using -TransferOptions 0 maintains the same ID. This is useful for publishing workflows but can cause conflicts if the item already exists in the target database.

    Transfer Options

    The -TransferOptions parameter controls how items are copied between databases:

    Value
    Behavior

    0

    Keep original ID

    1

    Create new ID (default behavior)

    2

    Allow default values

    4

    Allow standard values

    Example: Copy with new ID (default behavior).

    Bulk Operations

    Pattern: Move Multiple Items

    Pattern: Copy Items Based on Criteria

    Pattern: Reorganize Content Structure

    Pattern: Copy with Progress Reporting

    Maintaining Structure

    Pattern: Copy Tree Maintaining Hierarchy

    Dynamic Parameters

    Parameter
    Command
    Description
    Example

    DestinationItem

    Move-Item, Copy-Item

    Parent item to receive moved/copied item

    -DestinationItem $parent

    FailSilently

    Move-Item, Copy-Item

    Suppress unauthorized access errors

    -FailSilently

    TransferOptions

    Copy-Item

    Controls ID handling (0=keep, 1=new)

    Performance Considerations

    • Batch operations - Group multiple moves/copies together

    • Use BulkUpdateContext - When copying many items with field updates

    • Progress reporting - Provide feedback for long-running operations

    • Avoid unnecessary recursion - Only use -Recurse when needed

    • Test first - Use -WhatIf parameter if available, or test in development

    Common Pitfalls

    Pitfall: Moving to Non-Existent Path

    Pitfall: Copying Without PassThru

    See Also

    • Retrieving Items - Find items to move or copy

    • Creating and Removing Items - Item lifecycle management

    • Best Practices - Performance optimization

    • Appendix - Common Commands - Full cmdlet reference

    References

    • Working with Sitecore Items in PowerShell Extensions

    Unused Media Items

    Once the report completes, the results appear in a report window.

    Unused Media Items Output

    Reports in SPE like ASR

    While SPE contains many reports, they don't match identical to ASR reports. We've done our best to build those that seem most relevant or likely to be used. If you find a report in ASR that you would like to exist in SPE please submit a request.

    SPE Report

    ASR Report

    Active Aliases

    Aliases

    Audit

    Broken Links2

    Broken Links

    Broken Links in publishable items

    Item History

    Check the reports in SPE under these sections to see the full list.

    • 1 Configuration Audit report

    • 2 Content Audit report

    • 3 Media Audit report

    • 4 Solution Audit report

    • 5 Toolbox

    Note: Examples included are in the following modules

    • Content Reports

    Reports Security

    You may wish to expose the reports to users such as Content Authors. Here are the steps required to grant access to users in the sitecore\Sitecore Client Authoring role.

    Here is what users may see in the event they do not have the appropriate access.

    Reports without Access
    1. Navigate to the item /sitecore/content/Documents and settings/All users/Start menu/Right/Reporting Tools/PowerShell Reports

    2. Grant access to sitecore\Sitecore Client Authoring

      Report Viewer Access
    3. Verify the reports are now visible to the Authoring users.

    Note: In verson 6.4 the default access changed from sitecore\Sitecore Client Maintaining to a lower privileged account sitecore\Sitecore Client Authoring.

    Advanced System Report
    Reports
    Remoting Module Setup

    The setup of the module only requires a few steps: 1. In the Sitecore instance install the Sitecore module package. 2. On the local desktop or server install the SPE Remoting module.

    • After downloading you may need to unblock the file by right-clicking the zip and unblocking.

    • Ensure that you have run Set-ExecutionPolicy RemoteSigned in order for the SPE Remoting module will run. This typically requires elevated privileges.

      1. Enable the remoting service through a configuration patch. See the Security page for more details.

      2. Grant the remoting service user account through a configuration patch and granting acess to the appropriate role. See the page for more details.

    SPE Remoting Module

    Click for a demo

    The remoting services use a combination of a SOAP service (ASMX) and HttpHandler (ASHX). Remoting features are disabled by default and should be configured as needed as can be seen in the security section here. The SOAP service may require additional Windows authentication using the -Credential parameter which is common when logged into a Windows Active Directory domain.

    Windows Authenticated Requests

    If you have configured the web services to run under Windows Authentication mode in IIS then you'll need to use the Credential parameter for the commands.

    You'll definitely know you need it when you receive an error like the following:

    Example: The following connects Windows PowerShell ISE to a remote Sitecore instance using Windows credentials and executes the provided script.

    Example: The following connects to several remote instances of Sitecore and returns the server name.

    File and Media Service

    We have provided a service for downloading all files and media items from the server. This disabled by default and can be enabled using a patch file. See the Security page for more details about the services available and how to configure.

    Example: The following downloads a single file from the Package directory.

    Example: The following downloads a single media item from the library.

    Script Sessions and Web API Tutorial

    SPE Web API

    Click for a demo

    Advanced Script Sessions

    Inevitably you will need to have long running processes triggered remotely. In order to support this functionality without encountering a timeout using Invoke-RemoteScript you can use the following list of commands.

    • Get-ScriptSession - Returns details about script sessions.

    • Receive-ScriptSession - Returns the results of a completed script session.

    • Remove-ScriptSession - Removes the script session from memory.

    • Start-ScriptSession - Executes a new script session.

    • Stop-ScriptSession - Terminates an existing script session.

    • Wait-ScriptSession - Waits for all the script sessions to complete before continuing.

    These commands are not only used for remoting, we just thought it made sense to talk about them here.

    Example: The following remotely runs the id of a ScriptSession and polls the server until completed.

    Example: The following remotely runs a script and checks for any output errors. The LastErrors parameter is available for ScriptSession objects.

    Example: The following redirects messages from Write-Verbose to the remote session. The data returned will be both System.String and Deserialized.System.Management.Automation.VerboseRecord so be sure to filter it out when needed. More information about the redirection 4>&1 can be read here.

    Example: The following improves upon the previous example.

    Troubleshooting

    If you receive the following error when trying to run a script (note the namespace is Microsoft.PowerShell.Commands instead of Spe or similar):

    then add the following line as the first line within the Invoke-RemoteScript block: Set-Location -Path "master:"

    Example:

    This issue occurs due to the fact that the remoting session defaults to the FileSystem provider. Changing the location activates the custom provider included with SPE. As part of the custom provider there are additional parameters added to commands native to PowerShell.

    References

    • Michael's follow up post on Remoting

    • Adam's initial post on Remoting

    Content Editor

    Visual components made available to users in the Content Editor.

    Context Menu

    The Context Menu integration reveals a list of options to the user in the context menu under a special node called Scripts. The Sitecore rules engine may be used to control visibility and enabled state. The script is only executed when the option is clicked.

    1. Begin by adding a new script to the Context Menu library. The name of the script will appear in the context menu.

    2. Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.

    3. Change the icon of the item to match the script purpose.

    4. Configure any Enable or Show rules as needed.

    Note: Examples included in the following modules

    • Authoring Instrumentation

    • Copy Renderings

    • Index On Demand

    • Media Library Maintenance

    See how Adam added .

    Gutter

    The Gutter integration reveals a visual notification to the user in the far left gutter. The Sitecore rules engine may be used to control enabled state.

    1. Begin by adding a new script to the Gutters library.

    2. Edit the script to create a new instance of Sitecore.Shell.Applications.ContentEditor.Gutters.GutterIconDescriptor if the right conditions are met.

      • Set the Icon, Tooltip, and Click properties.

    Note: Examples included in the following modules

    • Publishing Status Gutter

    Insert Item

    The Insert Item integration reveals a list of options to the user in the context menu under the node called Insert. The Sitecore rules engine may be used to control visibility and enabled state. The script is only executed when the option is clicked.

    1. Begin by adding a new script to the Insert Item library. The name of the script will appear in the context menu.

    2. Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.

    3. Change the icon of the item to match the script purpose.

    4. Configure any Show

    Note: Examples included in the following modules

    • Task Management

    • Platform

    Ribbon

    The Ribbon integration reveals commands to the user in the ribbon. The Sitecore rules engine may be used to control visibility and enabled state. The script is only executed when the option is clicked.

    1. Begin by adding a new child script library to the Ribbon library; we'll refer to this library as the Tab library. Choose a name that matches an existing tab to be used, such as Home or Developer, or a new name to create a new tab.

    2. Add a child script library to the Tab library; we'll call this the Chunk library. Choose a name such as Edit or Tools.

    3. Add a new script to the Chunk script library; we'll refer to this library as the Command

    Example: The following script gets the selected Context Menu item and displays an alert using the item name.

    Button Size:

    There is a way to generate small buttons and combo buttons. You simply need to prefix the script name and SPE will generate accordingly.

    • Small$[SCRIPT_NAME]

    • Combo$[SCRIPT_NAME]

    • SmallCombo$[SCRIPT_NAME]

    See the birth of by Adam.

    Check out an example of the in the wild by Toby.

    Contextual Ribbon

    Similar to the Ribbon integration, this provides a way to show buttons when certain contextual conditions are met. Most common is with media items. The steps are the same as with the standard Ribbon, but the structure is slightly changed.

    In the following example, we have a ribbon button that appears whenever the selected item in the Content Editor is a media item. Take note of the "Optimize" button.

    The ribbon structure would look like the following:

    Warning

    The Warning integration reveals a notification to the user above content. The Sitecore rules engine can be used to control visibility and enabled state. The scripts are only executed when the rule is met and the command is clicked.

    1. Begin by adding a new script library to the Warning library.

    2. Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.

    3. The warning notification title, text and icon should be configured in the script.

    Note: Examples included in the following modules

    • License Expiration - disabled by default

    Alan provided a nice example on setting up the warning with commands.

    Libraries and Scripts

    Modules may contain PowerShell Script Library items and PowerShell Script items. The following section outlines some of the basic concepts you need to know for the following chapters.

    PowerShell Script Library

    The library items represent a collection of scripts, and may be structured with one or more levels of libraries.

    Naming Convention

    You'll find that with the Integration Points some libraries should be created with specific names (i.e. Content Editor, Control Panel).

    As a best practice we recommend that the Functions library consist of reusable scripts containing PowerShell functions (i.e. Do-Something) while other libraries contain the solution specific scripts (i.e. MakeScriptingGreatAgain).

    Example: The following demonstrates the use of the Functions script library containing Get-DateMessage.

    Some names we've used included:

    • Beginner Tutorials

    • Content Editor

    • Content Maintenance

    • Content Interrogation

    Many of the libraries are integration points for the module. When the integration point wizard runs, you will see that these can be generated automatically.

    Fields

    Interactive : The following fields support the two custom rules as well as a variety of out-of-the-box rules.

    • ShowRule (Show if rules are met or not defined) - typically controls visibility of integration points.

      • PowerShell

        • where calling the specific PowerShell script returns $True

    Rules Usage

    There are a number of use cases for the EnableRule and ShowRule.

    • If there is a UI component the ShowRule can be used to ensure it appears while the EnableRule can toggle when it can be clicked.

    • If there is no UI component, the EnableRule is used to determine when the script should be executed; useful to limit creation of PowerShell runspaces.

    ShowRule
    EnableRule

    PowerShell Script

    The script items represent the code that will be executed.

    Naming Convention

    There are three conventions that we recommend you follow which are shown with an example below.

    • Title Casing - This should be used when the name will be exposed in places such as the Content Editor, script library names, and Reports root directory.

    • Sentence casing - This should be used when the name is long and will not be visible to the user or is a report with a very long name.

    • Noun-Verb - This should be used when the script is stored within the Functions script library and will be imported using the command Import-Function.

    Fields

    Interactive : Refer to the description shown for PowerShell Script Library .

    Scripting

    • Script (Script body) : This is a multi-line text than should be edited using the PowerShell ISE application.

    Session Persistency

    • PersistentSessionId (Persistent Session ID) : Context scripts using this ID will execute in a single session and be reused; leaving empty will cause the session to be discarded after execution. This value should be used for rules requesting the session ID.

    Expand-Token

    Expands tokens in fields for items.

    Syntax

    Expand-Token [-Item] <Item> [-Language <String[]>]

    Expand-Token [-Path] <String> [-Language <String[]>]

    Expand-Token -Id <String> [-Database <String>] [-Language <String[]>]

    Detailed Description

    The Expand-Token command expands the tokens in fields for items.

    Some example of tokens include:

    • $name

    • $time

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Language <String[]>

    Language that will be processed. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    -Item <Item>

    The item to be processed.

    Aliases

    -Path <String>

    Path to the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to be processed - can work with Language parameter to narrow the publication scope.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    The following expands tokens in fields on the item.

    EXAMPLE 2

    The following expands tokens in fields on the item. If the standard value of the field contains a token we modify the field to the token so the expansion will work (Sitecore API does not expand if the field is the same as Standard Values and never modified).

    Related Topics

    Code Snippets

    Useful code snippets to help you with those complex scripts.

    List fields on template

    Example: The following demonstrates how to list all of the fields of a template excluding the Standard Template fields.

    Media item url

    Example: The following demonstrates how to generate the public facing url from a media item.

    Parse Html

    Example: The following demonstrates the use of the HtmlAgilityPack for parsing html.

    Example: The following demonstrates how to update text in the document and exclude certain nodes.

    Example: The following demonstrates how to remove empty paragraph tags in an html field.

    Example: The following demonstrates removing style attributes from the html.

    Workflow History

    Example: The following prints the workflow history of the home item.

    Restore Recycle bin items

    Example: The following restores items in the media library that were removed yesterday. @technomaz.

    Purge Recycle bin items

    Example: The following will incrementally purge items from the recycle bin (master db) with a progress counter.

    Run JavaScript

    Example: The following logs messages to the browser console and then alerts the user with a message.

    Remoting

    Example:

    Not seeing what you are looking for? You can always check out some Github Gists that and have shared or the .

    Get-ItemReferrer

    Returns all the items referring to the specified item.

    Syntax

    Get-ItemReferrer -Item <Item>

    Get-ItemReferrer -Item <Item> -ItemLink

    Get-ItemReferrer -Path <String> [-Language <String[]>]

    Get-ItemReferrer -Path <String> [-Language <String[]>] -ItemLink

    Get-ItemReferrer -Id <String> [-Database <String>] [-Language <String[]>]

    Get-ItemReferrer -Id <String> [-Database <String>] [-Language <String[]>] -ItemLink

    Detailed Description

    The Get-ItemReferrer command returns all items referring to the specified item. If -ItemLink parameter is used the command will return links rather than items.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    The item to be analysed.

    Aliases

    -Path <String>

    Path to the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to be processed - can work with Language parameter to narrow the publication scope.

    Aliases

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    -ItemLink <SwitchParameter>

    Return ItemLink that define both source and target of a link rather than items linking to the specified item.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

      Sitecore.Links.ItemLink

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    EXAMPLE 2

    Related Topics

    Get-ArchiveItem

    Retrieves a list of items found in the specified archive.

    Syntax

    Detailed Description

    The Get-ArchiveItem command returns items found in the "archive" and "recyclebin" archives.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Archive <Archive>

    Specifies the archive to use when determining which ArchiveEntry items to process. Use Get-Archive to find the appropriate archive.

    Aliases

    -ItemId <ID>

    Specifies the ID for the original item that should be processed. This is NOT the ArchivalId.

    Aliases

    -Identity <AccountIdentity>

    Specifies the user responsible for moving the item to the archive.

    Aliases

    Inputs

    None.

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Archiving.ArchiveEntry

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    The following returns all items found in the specified archive.

    EXAMPLE 2

    The following returns items matching the ItemId found in the specified archive.

    EXAMPLE 3

    The following returns items moved to the recycle bin by the user found in the specified archive.

    EXAMPLE 4

    The following demonstrates changing the archive date on an item followed by retrieving the archived item.

    Related Topics

    • Remove-ArchiveItem

    • Restore-ArchiveItem

    • Remove-Item

    • Remove-ItemVersion

    ConvertFrom-ItemClone

    Converts an item from a clone to a fully independent item.

    Syntax

    ConvertFrom-ItemClone [-Item] <Item> [-Recurse] [-PassThru]

    ConvertFrom-ItemClone [-Path] <String> [-Recurse] [-PassThru]

    ConvertFrom-ItemClone -Id <String> [-Database <String>] [-Recurse] [-PassThru]

    Detailed Description

    Converts an item from a clone to a fully independent item.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Recurse <SwitchParameter>

    Aliases

    -PassThru <SwitchParameter>

    Aliases

    -Item <Item>

    The item to be converted.

    Aliases

    -Path <String>

    Path to the item to be converted

    Aliases

    -Id <String>

    Id of the item to be converted

    Aliases

    -Database <String>

    Database containing the item to be converted

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    Get-SpeModuleFeatureRoot

    Returns the library item or path to the library where scripts for a particular integration point should be located for a specific module.

    Syntax

    Get-SpeModuleFeatureRoot [-Module <Module>] [-ReturnPath] [-Feature] <String>

    Detailed Description

    The Get-SpeModuleFeatureRoot command returns library item or path to the library where scripts for a particular integration point should be located for a specific module.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Module <Module>

    Module for which the feature root library should be returned. If not provided the feature root will be returned for all modules.

    Aliases

    -ReturnPath <SwitchParameter>

    Aliases

    -Feature <String>

    Feature for which the root library should be provided. If root item does not exist and -ReturnPath parameter is not specified - nothing will be returned, If -ReturnPath parameter is provided the path in which the feature root should be located will be returned

    Valid features:

    • contentEditorContextMenu

    • contentEditorGutters

    • contentEditorRibbon

    • controlPanel

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

      System.String

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Return the library item for "Content Editor Context Menu"

    EXAMPLE 2

    Return the Path to where "List View Export" scripts would be located if this feature was defined

    Related Topics

    Get-ItemTemplate

    Returns the item template and its base templates.

    Syntax

    Get-ItemTemplate [-Item] <Item> [-Recurse]

    Get-ItemTemplate [-Path] <String> [-Recurse]

    Get-ItemTemplate -Id <String> [-Database <String>] [-Recurse]

    Get-SpeModule

    Returns the object that describes a Sitecore PowerShell Extensions Module

    Syntax

    Get-SpeModule -Item <Item>

    Get-SpeModule -Path <String>

    Get-SpeModule -Id <String> -Database <String>

    Get-SpeModule -Database <String>

    Get-SpeModule [-Database <String>] -Name <String>

    Invoke-Script

    Executes a script from Sitecore PowerShell Extensions Script Library. This command used to be named Execute-Script - a matching alias added for compatibility with older scripts.

    Syntax

    Invoke-Script [-Item] <Item> [-ArgumentList <Object[]>]

    Invoke-Script [-Path] <String> [-ArgumentList <Object[]>]

    # Default returns all configurations
    Get-UnicornConfiguration
    
    # Exact match
    Get-UnicornConfiguration -Filter "Foundation.Foo"
    
    # Filter using a wildcard
    Get-UnicornConfiguration -Filter "Foundation.*"
    # Sync one
    Sync-UnicornConfiguration "Foundation.Foo"
    
    # Sync multiple by name
    Sync-UnicornConfiguration @("Foundation.Foo", "Foundation.Bar")
    
    # Sync multiple from pipeline
    Get-UnicornConfiguration "Foundation.*" | Sync-UnicornConfiguration
    
    # Sync all, except transparent sync-enabled configurations
    Get-UnicornConfiguration | Sync-UnicornConfiguration -SkipTransparent
    
    # Optionally set log output level (Debug, Info, Warn, Error)
    Sync-UnicornConfiguration -LogLevel Warn
    # Sync a single item (note: must be under Unicorn control)
    Get-Item "/sitecore/content" | Sync-UnicornItem
    
    # Sync multiple single items (note: all must be under Unicorn control)
    Get-ChildItem "/sitecore/content" | Sync-UnicornItem 
    
    # Sync an entire item tree, show only warnings and errors
    Get-Item "/sitecore/content" | Sync-UnicornItem -Recurse -LogLevel Warn
    # Reserialize one
    Export-UnicornConfiguration "Foundation.Foo"
    
    # Reserialize multiple by name
    Export-UnicornConfiguration @("Foundation.Foo", "Foundation.Bar")
    
    # Reserialize from pipeline
    Get-UnicornConfiguration "Foundation.*" | Export-UnicornConfiguration
    # Reserialize a single item (note: must be under Unicorn control)
    Get-Item "/sitecore/content" | Export-UnicornItem
    
    # Reserialize multiple single items (note: all must be under Unicorn control)
    Get-ChildItem "/sitecore/content" | Export-UnicornItem 
    
    # Reserialize an entire item tree
    Get-Item "/sitecore/content" | Export-UnicornItem -Recurse
    # Convert an item to YAML format (always uses default excludes and field formatters)
    Get-Item "/sitecore/content" | ConvertTo-RainbowYaml
    
    # Convert many items to YAML strings
    Get-ChildItem "/sitecore/content" | ConvertTo-RainbowYaml
    
    # Disable all field formats and field filtering
    # (e.g. disable XML pretty printing,
    # and don't ignore the Revision and Modified fields, etc)
    Get-Item "/sitecore/content" | ConvertTo-RainbowYaml -Raw
    # Get IItemDatas from YAML variable
    $rawYaml | ConvertFrom-RainbowYaml
    
    # Get IItemData and disable all field filters
    # (use this if you ran ConvertTo-RainbowYaml with -Raw)
    $yaml | ConvertFrom-RainbowYaml -Raw
    # Deserialize IItemDatas from ConvertFrom-RainbowYaml
    $rawYaml | ConvertFrom-RainbowYaml | Import-RainbowItem
    
    # Deserialize raw YAML from pipeline into Sitecore 
    # Shortcut bypassing ConvertFrom-RainbowYaml
    $yaml | Import-RainbowItem
    
    # Deserialize and disable all field filters
    # (use this if you ran ConvertTo-RainbowYaml with -Raw)
    $yaml | Import-RainbowItem -Raw
    
    # Deserialize multiple at once
    $yamlStringArray | Import-RainbowItem
    
    # Complete example that does nothing but eat CPU
    Get-ChildItem "/sitecore/content" | ConvertTo-RainbowYaml | Import-RainbowItem
    # Create a new Sitecore Package (SPE cmdlet)
    $pkg = New-Package -Name MyCustomPackage
    
    # Get the Unicorn Configuration(s) we want to package
    $configs = Get-UnicornConfiguration "Foundation.*" 
    
    # Pipe the configs into New-UnicornItemSource 
    # to process them and add them to the package project
    # (without -Project, this would emit the source object(s) 
    #   which can be manually added with $pkg.Sources.Add())
    $configs | New-UnicornItemSource -Project $pkg
    
    # Export the package to a zip file on disk
    Export-Package -Project $pkg -Path "C:\foo.zip" -Zip
    # When you open the Console, you start here:
    PS master:\>
    # Master database
    Get-Item -Path "master:\content\home"
    
    # Web database
    Get-Item -Path "web:\content\home"
    
    # Core database
    Get-Item -Path "core:\content"
    database:\path\to\item
    master:\content\home
    master:\content\home\articles\my-article
    web:\content
    core:\system
    PS master:\> cd c:\
    PS C:\> cd hklm:
    PS HKLM:\> cd env:
    PS Env:\> cd master:
    PS master:\>
    # Get a single item
    $home = Get-Item -Path "master:\content\home"
    
    # Get children
    $children = Get-ChildItem -Path "master:\content\home"
    
    # Get all descendants
    $all = Get-ChildItem -Path "master:\content\home" -Recurse
    # Create a new item
    New-Item -Path "master:\content\home" -Name "My New Item" -ItemType "Sample/Sample Item"
    # Remove an item (goes to Recycle Bin)
    Remove-Item -Path "master:\content\home\test-item"
    # Check if an item exists
    if(Test-Path -Path "master:\content\home\my-item") {
        Write-Host "Item exists!"
    }
    # Get item with specific language
    Get-Item -Path "master:\content\home" -Language "de-DE"
    
    # Get specific version
    Get-Item -Path "master:\content\home" -Version 5
    
    # Include standard fields
    Get-Item -Path "master:\content\home" | Get-ItemField -IncludeStandardFields
    # Get files with filter
    Get-ChildItem -Path "C:\temp" -Filter "*.txt"
    
    # Get files with specific attributes
    Get-ChildItem -Path "C:\temp" -File
    Get-ChildItem -Path "C:\temp" -Directory
    # Get Sitecore items
    $items = Get-ChildItem -Path "master:\content\home\articles"
    
    # Export to file system
    $items | Select-Object Name, TemplateName |
        Export-Csv -Path "$($SitecoreDataFolder)\articles.csv" -NoTypeInformation
    $sourcePath = "master:\content\home\sample item"
    $destinationPath = "master:\content\home\moved"
    Move-Item -Path $sourcePath -Destination $destinationPath
    # If "new-name" doesn't exist, item is moved and renamed
    $oldPath = "master:\content\home\old-name"
    $newPath = "master:\content\home\new-name"
    Move-Item -Path $oldPath -Destination $newPath
    Get-Item -Path "master:" -ID "{65736CA0-7D69-452A-A16F-2F42264D21C5}" |
        Move-Item -Destination "master:{DFDDF372-3AB7-45B1-9E7C-0D0B27350439}"
    Move-Item -Path "master:\content\home\old-section" `
              -Destination "master:\content\archive\"
    $originalPath = "master:\content\home\original"
    $copyPath = "master:\content\home\copy"
    Copy-Item -Path $originalPath -Destination $copyPath
    $originalPath = "master:\content\home\original"
    $copyPath = "master:\content\home\copy"
    $newItem = Copy-Item -Path $originalPath -Destination $copyPath -PassThru
    $newItem."__Display Name" = "Copy"
    
    Write-Host "New item ID: $($newItem.ID)"
    $sourceId = "{AF27FAD3-2AF0-4682-9BF7-375197587579}"
    $destinationId = "{53F94442-555B-4622-B813-A16ED2CAB01B}"
    
    Get-Item -Path "master:" -ID $sourceId | Copy-Item -Destination $destinationId -Recurse
    Copy-Item -Path "master:\content\home" `
              -Destination "web:\content\home" `
              -TransferOptions 0
    # These are equivalent
    Copy-Item -Path "master:\content\home\sampleitem" -Destination "web:\content\home\sampleitem"
    Copy-Item -Path "master:\content\home\sampleitem" -Destination "web:\content\home\sampleitem" -TransferOptions 1
    Get-ChildItem -Path "master:\content\temp" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" } |
        ForEach-Object {
            Move-Item -Path $_.ProviderPath -Destination "master:\content\archive"
        }
    $templates = @("Sample Item", "Article", "News Item")
    
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $templates -contains $_.TemplateName } |
        ForEach-Object {
            Copy-Item -Path $_.ProviderPath -Destination "master:\content\backup"
        }
    # Move all items of a specific template to a new location
    $targetTemplate = "Article"
    $newParent = Get-Item -Path "master:\content\articles"
    
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq $targetTemplate } |
        ForEach-Object {
            Move-Item -Path $_.ProviderPath -Destination $newParent.ProviderPath
            Write-Host "Moved: $($_.Name)"
        }
    $itemsToCopy = Get-ChildItem -Path "master:\content\home\original" -Recurse
    $total = $itemsToCopy.Count
    $current = 0
    
    foreach($item in $itemsToCopy) {
        $current++
        Write-Progress -Activity "Copying items" `
                       -Status "Copying $($item.Name)" `
                       -PercentComplete (($current / $total) * 100)
    
        Copy-Item -Path $item.ProviderPath `
                  -Destination "master:\content\home\copied" `
                  -Recurse
    }
    Write-Progress -Activity "Copying items" -Completed
    $sourceRoot = Get-Item -Path "master:\content\home\job-search"
    $destinationRoot = Get-Item -Path "master:\content\home\careers"
    
    $sourceRoot | Copy-Item -Destination $destinationRoot.ProviderPath -Recurse
    
    # Produces a new tree /sitecore/content/home/careers/job-search
    # Existing content remains at /sitecore/content/home/job-search
    # BAD - if parent doesn't exist, item is renamed
    Move-Item -Path "master:\content\home\demo" `
              -Destination "master:\content\nonexistent"
    # GOOD - verify parent exists
    $destination = "master:\content\archive"
    if (Test-Path $destination) {
        Move-Item -Path "master:\content\home\demo" -Destination $destination
    } else {
        Write-Host "Destination does not exist" -ForegroundColor Red
    }
    # BAD - can't access the new item
    Copy-Item -Path "master:\content\home\demo" -Destination "master:\content\copy"
    # No reference to the copied item
    # GOOD - use PassThru to get reference
    $sourcePath = "master:\content\home\demo"
    $destinationPath = "master:\content\home\demo-copy"
    $copiedItem = Copy-Item -Path $sourcePath -Destination $destinationPath -PassThru
    $copiedItem.Title = "Updated Title"
    New-WebServiceProxy : The request failed with HTTP status 401: Unauthorized.
    Import-Module -Name SPE
    $credential = Get-Credential
    $session = New-ScriptSession -Username admin -Password b -ConnectionUri https://remotesitecore -Credential $credential
    Invoke-RemoteScript -Session $session -ScriptBlock { Get-User -id admin }
    Stop-ScriptSession -Session $session
    
    # Name                     Domain       IsAdministrator IsAuthenticated
    # ----                     ------       --------------- ---------------
    # sitecore\admin           sitecore     True            False
    # If you need to connect to more than one instance of Sitecore add it to the list.
    $instanceUrls = @("https://remotesitecore","https://remotesitecore2")
    $session = New-ScriptSession -Username admin -Password b -ConnectionUri $instanceUrls
    Invoke-RemoteScript -Session $session -ScriptBlock { $env:computername }
    Stop-ScriptSession -Session $session
    Import-Module -Name SPE
    $session = New-ScriptSession -Username admin -Password b -ConnectionUri https://remotesitecore
    Receive-RemoteItem -Session $session -Path "default.js" -RootPath App -Destination "C:\Files\"
    Stop-ScriptSession -Session $session
    Import-Module -Name SPE
    $session = New-ScriptSession -Username admin -Password b -ConnectionUri https://remotesitecore
    Receive-RemoteItem -Session $session -Path "/Default Website/cover" -Destination "C:\Images\" -Database master
    Stop-ScriptSession -Session $session
    Import-Module -Name SPE
    $session = New-ScriptSession -Username admin -Password b -ConnectionUri https://remotesitecore
    $jobId = Invoke-RemoteScript -Session $session -ScriptBlock {
            "master", "web" | Get-Database | 
                ForEach-Object { 
                    [Sitecore.Globals]::LinkDatabase.Rebuild($_)
                }
    } -AsJob
    Wait-RemoteScriptSession -Session $session -Id $jobId -Delay 5 -Verbose
    Stop-ScriptSession -Session $session
    $jobId = Invoke-RemoteScript -Session $session -ScriptBlock {
        Get-Session -ParameterDoesNotExist "SomeData"
    } -AsJob
    # This delay could actually be that you got up to get some coffee or tea.
    Start-Sleep -Seconds 2
    
    Invoke-RemoteScript -Session $session -ScriptBlock {
        $ss = Get-ScriptSession -Id $using:JobId
        $ss | Receive-ScriptSession
    
        if($ss.LastErrors) {
            $ss.LastErrors
        }
    }
    Invoke-RemoteScript -ScriptBlock {
        Write-Verbose "Hello from the other side" -Verbose 4>&1
        "data"    
        Write-Verbose "Goodbye from the other side" -Verbose 4>&1
    } -Session $session
    Invoke-RemoteScript -ScriptBlock {
        function Write-Verbose {
            param([string]$Message)
            Microsoft.PowerShell.Utility\Write-Verbose -Message $Message -Verbose 4>&1
        }
    
        Write-Verbose "Hello from the other side"
        "data"    
        Write-Verbose "Goodbye from the other side"
    } -Session $session
        + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.NewItemCommand
    Invoke-RemoteScript -ScriptBlock {
        Set-Location -Path "master:"
        ...
        [The rest of your script]
        ...
    }
    # Create a list of field names on the Standard Template. This will help us filter out extraneous fields.
    $standardTemplate = Get-Item -Path "master:" -ID "{1930BBEB-7805-471A-A3BE-4858AC7CF696}"
    $standardTemplateTemplateItem = [Sitecore.Data.Items.TemplateItem]$standardTemplate
    $standardFields = $standardTemplateTemplateItem.OwnFields + $standardTemplateTemplateItem.Fields | Select-Object -ExpandProperty key -Unique
    
    $itemTemplate = Get-Item -Path "master:" -ID "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    $itemTemplateTemplateItem = [Sitecore.Data.Items.TemplateItem]$itemTemplate
    $itemTemplateFields = $itemTemplateTemplateItem.OwnFields + $itemTemplateTemplateItem.Fields | Select-Object -ExpandProperty key -Unique
    
    $filterFields = $itemTemplateFields | Where-Object { $standardFields -notcontains $_ } | Sort-Object
    Get-ArchiveItem -Archive <Archive>
    Get-ArchiveItem -Archive <Archive> [-ItemId <ID>]
    Get-ArchiveItem -Archive <Archive> [-Identity <AccountIdentity>]

    Function

    Function

    Get-Item -Path function:\prompt

    Registry

    HKLM, HKCU

    Get-Item -Path hklm:\SOFTWARE

    Variable

    Variable

    Get-Item -Path variable:\PSVersionTable

    Remove-Item master:\content\home\item

    Test exists

    Test-Path C:\file.txt

    Test-Path master:\content\home\item

    Move

    Move-Item C:\old.txt C:\new.txt

    Move-Item master:\a master:\b

    Copy

    Copy-Item C:\old.txt C:\new.txt

    Copy-Item master:\a master:\b

    -TransferOptions 0

    PassThru

    Copy-Item

    Returns the new item

    -PassThru

    Recurse

    Copy-Item

    Includes all descendants

    -Recurse

    Items with Invalid Names

    Items with security for an account2

    Items with Security for an account

    Items with Tokens in Fields

    Links

    Locked Items2

    Locked Items

    Logged errors

    Logged in Session Manager5

    Logged in Users

    Limit number of versions4

    Multiple versions

    My Owned Items

    Media items last updated before date3

    Not recently modified

    Media items not used by content items3

    Orphaned media assets report

    Owned items

    Recent workflow history2

    Recent Workflow History

    Media items last updated after date3

    Recently Modified

    Regex Item Searcher

    Renderings

    Index Viewer5

    -

    Rules based report5

    -

    Task Manager report5

    -

    Reports with Access

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/
    https://sitecorejunkie.com/2014/05/27/launch-powershell-scripts-in-the-item-context-menu-using-sitecore-powershell-extensions/
    https://sitecorejunkie.com/2014/06/02/make-bulk-item-updates-using-sitecore-powershell-extensions/
    Sitecore Stack Exchanage
    Credit
    Remote Package Installation
    Adam
    Michael
    Sitecore Stack Exchange
    Invoke JavaScript

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Get-ItemReference
    Update-ItemReferrer
    https://github.com/SitecorePowerShell/Console/

    https://github.com/SitecorePowerShell/Console/

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    New-ItemClone
    Get-ItemClone
    https://github.com/SitecorePowerShell/Console/

    functions

  • listViewExport

  • listViewRibbon

  • pipelineLoggedIn

  • pipelineLoggingIn

  • pipelineLogout

  • toolbox

  • startMenuReports

  • eventHandlers

  • webAPI

  • pageEditorNotification

  • isePlugi

  • Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Get-SpeModule
    https://blog.najmanowicz.com/2014/11/01/sitecore-powershell-extensions-3-0-modules-proposal/
    https://github.com/SitecorePowerShell/Console/
    Detailed Description

    The Get-SpeModule command returns the object that describes a Sitecore PowerShell Extensions Module.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    A script or library item that is defined within the module to be returned.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to a script or library item that is defined within the module to be returned.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of a script or library item that is defined within the module to be returned.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database containing the module to be returned.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    -Name <String>

    Name fo the module to return. Supports wildcards.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

      System.String

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Spe.Core.Modules.Module

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Return all modules defined in the provided database

    EXAMPLE 2

    Return all modules defined in the master database Matching the "Content*" wildcard

    EXAMPLE 3

    Return the module the piped script belongs to

    Related Topics

    • Get-SpeModuleFeatureRoot

    • https://blog.najmanowicz.com/2014/11/01/sitecore-powershell-extensions-3-0-modules-proposal/

    • https://github.com/SitecorePowerShell/Console/

    Detailed Description

    Executes a script from Sitecore PowerShell Extensions Script Library.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Aliases

    The following abbreviations are aliases for this cmdlet:

    • Execute-Script

    Parameters

    -Item <Item>

    The script item to be executed.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the script item to be executed. Path can be absolute or Relavie to Script library root. e.g. the following two commands are equivalent:

    PS master:&gt; Invoke-Script 'master:\system\Modules\PowerShell\Script Library\Examples\Script Testing\Long Running Script with Progress Demo' PS master:&gt; Invoke-Script 'Examples\Script Testing\Long Running Script with Progress Demo'

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -ArgumentList <Object[]>

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • System.Object

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    EXAMPLE 2

    Run a script with arguments passed in.

    The arguments are passed and used in the called script like below:

    Related Topics

    • https://github.com/SitecorePowerShell/Console/

    • Import-Function

    Get-Item -Path "master:\content\home" | Expand-Token
    $tokens = @('$name', '$id', '$parentId', '$parentname', '$date', '$time', '$now')
    
    $item = Get-Item -Path "master:\content\home"
    
    $standardValueFields = Get-ItemField -Item $item -ReturnType Field -Name "*" `
        | Where-Object { $_.ContainsStandardValue }
        
    $item.Editing.BeginEdit()
    
    foreach ($field in $standardValueFields) {
        $value = $field.Value
        
        if ($tokens -contains $value) {
            $item[$field.Name] = $value
        }
    }
    
    $item.Editing.EndEdit()
    
    Expand-Token -Item $item
    $item = Get-Item -Path "master:{04DAD0FD-DB66-4070-881F-17264CA257E1}"
    $siteName = "website"
    
    $site = [Sitecore.Sites.SiteContextFactory]::GetSiteContext($siteName)
    New-UsingBlock (New-Object Sitecore.Sites.SiteContextSwitcher $site) {
        [Sitecore.Resources.Media.MediaManager]::GetMediaUrl($item)
    }
    
    # /-/media/default-website/cover.jpg
    $html = "<ul><li>foo</li><li>bar</li></ul>"
    $htmlDocument = New-Object -TypeName HtmlAgilityPack.HtmlDocument
    $htmlDocument.LoadHtml($html)
    foreach($x in $htmlDocument.DocumentNode.SelectNodes("//li")) {
        $x.InnerText;
    }
    $html = @"
    <div class="kitchen">
       <div class="kitchen">
            <blockquote>kitchen<br />
                <span class="kitchen">kitchen</span>
            </blockquote>
            <a><img title="kitchen" src="https://kitchen-sink.local" /></a>
        </div>
    </div>
    "@
    
    $htmlDocument = New-Object -TypeName HtmlAgilityPack.HtmlDocument
    $htmlDocument.LoadHtml($html)
    foreach($x in $htmlDocument.DocumentNode.Descendants()) {
        if($x.Name -ne "img" -and ![string]::IsNullOrEmpty($x.Text)) {
            $x.Text = $x.Text.Replace("kitchen", "sink")
        }
    }
    
    $htmlDocument.DocumentNode.OuterHtml
    $html = @"
    <div style='padding: 10px 10px;'>Some Text</div>
    "@
    
    $htmlDocument = New-Object -TypeName HtmlAgilityPack.HtmlDocument
    $htmlDocument.LoadHtml($html)
    $nodes = $htmlDocument.DocumentNode.SelectNodes("//@style");
    foreach($node in $nodes) {
        $node.Attributes["style"].Remove()
    }
    $htmlDocument.DocumentNode.OuterHtml
    $item = Get-Item -Path "master:" -Id "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    
    $db = Get-Database -Name "master"
    $workflowProvider = $db.WorkflowProvider
    
    foreach($version in $item.Versions.GetVersions()) {
        $workflowEvents = $workflowProvider.HistoryStore.GetHistory($version)
        foreach($workflowEvent in $workflowEvents) {
            "[$($workflowEvent.Date)] ($($workflowEvent.User)) $(($workflowEvent.Text -replace '(\r|\n)',''))"
        }
    }
    Write-Host "Restoring items recycled after $($archivedDate.ToShortDateString())"
    
    foreach($archive in Get-Archive -Name "recyclebin") {
        Write-Host " - Found $($archive.GetEntryCount()) entries"
        $entries = $archive.GetEntries(0, $archive.GetEntryCount())
        foreach($entry in $entries) {
            if($entry.ArchiveLocalDate -ge $archivedDate) { 
                Write-Host "Restoring item: $($entry.OriginalLocation) {$($entry.ArchivalId)}on date $($entry.ArchiveLocalDate)"
                $archive.RestoreItem($entry.ArchivalId)
            } else {
                Write-Host "Skipping $($entry.OriginalLocation) on date $($entry.ArchiveLocalDate)"
            }
        }
    }
    $database = Get-Database -Name "master"
    $archiveName = "recyclebin"
    $archive = Get-Archive -Database $database -Name $archiveName
    $items = Get-ArchiveItem -Archive $archive
    
    $count = 0
    $total = $items.Count
    foreach($item in $items) {
        $count++
        if($count % 100 -eq 0) {
            Write-Host "[$(Get-Date -Format 'yyyy-MM-dd hh:mm:ss')] $([math]::round($count * 100 / $total, 2))% complete"
        }
        $item | Remove-ArchiveItem
    }
    Write-Host "Completed processing recycle bin"
    1..5 | ForEach-Object { 
        Start-Sleep -Seconds 1
        Invoke-JavaScript -Script "console.log('Hello World! Call #$($_) from PowerShell...');" 
    }
    
    Invoke-JavaScript -Script "alert('hello from powershell');"
    Import-Module -Name SPE -Force
    
    $packageName = "$($SitecorePackageFolder)\[PACKAGE].zip"
    
    $session = New-ScriptSession -Username "admin" -Password "b" -ConnectionUri "https://remotesitecore"
    Test-RemoteConnection -Session $session -Quiet
    $jobId = Invoke-RemoteScript -Session $session -ScriptBlock {
        [Sitecore.Configuration.Settings+Indexing]::Enabled = $false
        Get-SearchIndex | ForEach-Object { Stop-SearchIndex -Name $_.Name }
        Import-Package -Path "$($SitecorePackageFolder)\$($using:packageName)" -InstallMode Merge -MergeMode Merge
        [Sitecore.Configuration.Settings+Indexing]::Enabled = $true
    } -AsJob
    Wait-RemoteScriptSession -Session $session -Id $jobId -Delay 5 -Verbose
    Stop-ScriptSession -Session $session
    PS master:\>Get-ItemReferrer -Path master:\content\home
    
    Name                             Children Languages                Id                                     TemplateName
    ----                             -------- ---------                --                                     ------------
    Home                             True     {en, de-DE, es-ES, pt... {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Form                             False    {en, de-DE, es-ES, pt... {6D3B4E7D-FEF8-4110-804A-B56605688830} Webcontrol
    news                             True     {en, de-DE, es-ES, pt... {DB894F2F-D53F-4A2D-B58F-957BFAC2C848} Article
    learn-about-oms                  False    {en, de-DE, es-ES, pt... {79ECF4DF-9DB7-430F-9BFF-D164978C2333} Link
    PS master:\>Get-Item master:\content\home | Get-ItemReferrer -ItemLink
    
    SourceItemLanguage : en
    SourceItemVersion  : 1
    TargetItemLanguage :
    TargetItemVersion  : 0
    SourceDatabaseName : master
    SourceFieldID      : {F685964D-02E1-4DB6-A0A2-BFA59F5F9806}
    SourceItemID       : {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}
    TargetDatabaseName : master
    TargetItemID       : {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}
    TargetPath         : /sitecore/content/Home
    $database = Get-Database -Name "master"
    $archiveName = "recyclebin"
    $archive = Get-Archive -Database $database -Name $archiveName
    Get-ArchiveItem -Archive $archive
    $database = Get-Database -Name "master"
    $archiveName = "recyclebin"
    $archive = Get-Archive -Database $database -Name $archiveName
    Get-ArchiveItem -Archive $archive -ItemId "{1BB32980-66B4-4ADA-9170-10A9D3336613}"
    $database = Get-Database -Name "master"
    $archiveName = "recyclebin"
    $archive = Get-Archive -Database $database -Name $archiveName
    Get-ArchiveItem -Archive $archive -Identity "sitecore\admin"
    $item = Get-Item -Path "master:" -ID "{1BB32980-66B4-4ADA-9170-10A9D3336613}"
    $date = $item[[Sitecore.FieldIDs]::ArchiveDate]
    $serverTime = [Sitecore.DateUtil]::IsoDateToServerTimeIsoDate($date)
    $serverTimeDateTime = [Sitecore.DateUtil]::IsoDateToDateTime($serverTime, [datetime]::MinValue)
    
    # Here you could add more time to the $serverTimeDateTime
    
    $utcTimeDateTime = [Sitecore.DateUtil]::ToUniversalTime($serverTimeDateTime)
    $isoTime = [Sitecore.DateUtil]::ToIsoDate($utcTimeDateTime)
    
    $item.Editing.BeginEdit()
    $item[[Sitecore.FieldIDs]::ArchiveDate] = $isoTime
    $item.Editing.EndEdit()
    
    # Some time after the date has passed
    $database = Get-Database -Name "master"
    $archiveName = "archive"
    $archive = Get-Archive -Database $database -Name $archiveName
    Get-ArchiveItem -Archive $archive -ItemId "{1BB32980-66B4-4ADA-9170-10A9D3336613}"
    PS master:\> ConvertFrom-ItemClone -Path master:\content\home
    $module = Get-SpeModule -Name "Copy Renderings"
    Get-SpeModuleFeatureRoot -Feature contentEditorContextMenu -Module $module
    $module = Get-SpeModule -Name "Copy Renderings"
    Get-SpeModuleFeatureRoot -Module $module -Feature listViewExport -ReturnPath
    PS master:\> Get-SpeModule -Database (Get-Database "master")
    PS master:\> Get-SpeModule -Database (Get-Database "master")
    PS master:\> Get-item "master:\system\Modules\PowerShell\Script Library\Copy Renderings\Content Editor\Context Menu\Layout\Copy Renderings" |  Get-SpeModule
    Invoke-Script 'Examples\Script Testing\Long Running Script with Progress Demo'
    $scriptItem = Get-Item -Path "master:" -ID "{35311878-54EF-4E7A-9B95-3B63F5DEE97D}"
    
    $arguments = @{
        TemplateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    }
    $scriptItem | Invoke-Script -ArgumentList $arguments
    param($params)
    $templateId = $params.templateId
    
    Get-ItemReferrer -ID $templateId

    Package Generator

    Package Generator
  • Task Management

  • Return the gutter object

  • Configure any Enable rules to ensure the script runs only when necessary.

  • Rebuild the gutter integration from within the ISE.

    • Settings tab

    • Integration chunk

    • Sync Library with Content Editor Gutter command

  • rules as needed.
    library. The name of the script will appear in the ribbon chunk as a command.
  • Optionally add a short description on the item, which is found as a standard field on the item. The description will appear as a tooltip on the ribbon button.

  • Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.

  • Change the icon of the item to match the script purpose.

  • Configure any Enable or Show rules as needed.

  • Include options to the warning by adding one or more secondary scripts to the script library.
  • Configure any Enable rules to ensure the script only runs when required.

  • context menu PowerShell scripts
    extending the Sitecore ribbon with powershell scripts
    5 steps to extending the Sitecore ribbon
    here
    Publishing Status
    Insert Scheduled Task
    Ribbon Script Library Structure
    Small and Combo Buttons
    Buttons in the Ribbon
    Contextual Ribbon Command
    Script Library Structure
    License Expiration Warning
    Development
  • Event Handlers

  • Functions

  • Internal

  • Page Editor

  • Pipelines

  • Profile and Security

  • Reports

  • Script Testing

  • Tasks

  • Toolbox

  • User Interaction

  • Web API

  • where calling the specific PowerShell script returns value that compares to value #1388
  • where specific persistent PowerShell session was already initiated #153

  • where specific persistent PowerShell session was already initiated and has the specific variable defined and not null

  • where exposed in a specific view #156

    • Used with the command Show-ListView to allow actions to be visible only on views with a corresponding name.

  • PowerShell ISE

    • when length script length is compares to number characters long #383

    • when the edited script is in a state #383

  • PowerShell Security

    • where the current user has delegated access #1283

    • where the current user is a member of the specific role, either directory or through inheritance #1036

  • PowerShell System

    • where the Sitecore.config numeric setting name compares to number #1385

    • where the Sitecore.config string setting name compares to value #1385

    • where the Web.config numeric AppSetting name compares to number

    • where the Web.config string setting name compares to value

  • EnableRule (Enable if rules are met or not defined) - typically controls enabled state of integration points.

    • Same as above

  • ISE Plugin

    ISE Plugin

    Reports List View Action

    Reports List View Action

    Reports List View Export

    Reports List View Export

    Page Editor

    Page Editor

    Content Editor Context Menu

    Content Editor Context Menu

    Content Editor Gutter

    Content Editor Insert Item

    Content Editor Ribbon

    Content Editor Ribbon

    Content Editor Warning

    DataSources

    #1388
    fields

    Detailed Description

    The Get-ItemTemplate command returns the item template and its base templates.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Recurse <SwitchParameter>

    Return the template the item is based on and all of its base templates.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Item <Item>

    The item to be analysed.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the item to be analysed.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of the item to be analysed.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database containing the item to be analysed - required if item is specified with Id.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.TemplateItem

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Get template of /sitecore/conent/home item

    EXAMPLE 2

    Get template of /sitecore/conent/home item and all of the templates its template is based on then format it to only show the template name, path and Key

    Related Topics

    • Get-ItemField

    • Set-ItemTemplate

    • Add-BaseTemplate

    • Remove-BaseTemplate

    Security

    Minimal Deployment

    For CI/CD and automation environments where you only need SPE web services (without the full UI), a minimal deployment reduces the attack surface while maintaining remote automation capabilities.

    Overview

    The minimal deployment includes only the files necessary to support SPE web services, removing all UI components (Console, ISE, Content Editor integrations).

    Benefits:

    • Smaller attack surface

    • Fewer files to maintain

    • Faster deployment

    • Ideal for build/deployment servers

    • Only what's needed for automation

    Limitations:

    • No PowerShell Console

    • No PowerShell ISE

    • No Content Editor integration

    • No Reports UI

    This deployment is specifically designed for environments that only need remote script execution via SPE Remoting.

    Use Cases

    CI/CD Environments

    Scenario: Build servers need to execute deployment scripts remotely.

    Requirements:

    • Remoting service

    • Minimal file footprint

    • No interactive UI

    Automated Content Deployment

    Scenario: Automated systems deploy content packages to Sitecore.

    Requirements:

    • Remote script execution

    • File upload capability

    • Package installation commands

    Headless/API-Only Instances

    Scenario: Sitecore instances that serve as API backends without content authoring.

    Requirements:

    • Remote automation capability

    • No UI overhead

    • Security-focused configuration

    Required Files

    Core Files

    File Path
    Purpose
    Required

    Web Service Files

    File Path
    Purpose
    Required

    Excluded Files (Not Needed)

    The following are NOT included in minimal deployment:

    ❌ PowerShell Console UI files ❌ PowerShell ISE files ❌ Content Editor integration files ❌ Report UI files ❌ Gutter renderers ❌ Ribbon extensions ❌ All UI-related files in sitecore modules\Shell\PowerShell\

    Installation Steps

    Option 1: Using Minimal Package

    SPE provides a pre-built minimal package: SPE.Minimal-6.x.zip

    1. Download SPE.Minimal-8.x.zip from SPE releases

    2. Extract to your Sitecore instance

    3. Enable disabled config files (see below)

    4. Configure security settings

    Option 2: Manual Installation

    Deploy required files using your favorite scripting language.

    Step 3: Disable UI Control Sources

    Create a config patch to disable UI control sources:

    File: App_Config\Include\Spe\Custom\Spe.DisableUI.config

    Configuration

    Enable Remoting Service

    By default, Remoting is disabled. Enable it with proper security:

    File: App_Config\Include\Spe\Custom\Spe.Remoting.config

    Secure Web Services

    File: sitecore modules\PowerShell\Services\web.config

    Testing the Deployment

    Verify Minimal Installation

    Security Best Practices

    Minimal Deployment Security Checklist

    Recommended Security Layers

    1. Network - Firewall rules, VPN if possible

    2. IIS - IP restrictions, Windows Auth (optional), HTTPS

    3. Sitecore - Specific user accounts with minimal roles

    4. SPE - requireSecureConnection, file upload restrictions

    Troubleshooting

    Remoting connection fails

    Possible causes:

    1. Remoting service not enabled

    2. User not in authorization list

    3. HTTPS required but using HTTP

    4. Anonymous access denied but not providing credentials

    Solution: Check configuration, verify credentials, ensure HTTPS.

    UI elements still appear

    Cause: controlSources not disabled in configuration.

    Solution: Verify Spe.DisableUI.config patch is present and loading.

    Related Topics

    • - Detailed web service configuration

    • - IIS-level hardening

    • - Configure upload limits

    • - Validation checklist

    References

    Invoke-ShellCommand

    Executes Sitecore Shell command for an item. This command used to be named Execute-ShellCommand - a matching alias added for compatibility with older scripts.

    Syntax

    Invoke-ShellCommand [-Item] <Item> [-Name] <String> [-Language <String[]>]

    Invoke-ShellCommand [-Path] <String> [-Name] <String> [-Language <String[]>]

    Invoke-ShellCommand -Id <String> [-Database <String>] [-Name] <String> [-Language <String[]>]

    Detailed Description

    Executes Sitecore Shell command for an item. e.g. opening dialogs or performing commands that you can find in the Content Editor ribbon or context menu.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Aliases

    The following abbreviations are aliases for this cmdlet:

    • Execute-ShellCommand

    Parameters

    -Name <String>

    Name of the sitecore command e.g. "item:publishingviewer"

    Aliases

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    -Item <Item>

    The item to be sent to the command.

    Aliases

    -Path <String>

    Path to the item to be sent to the command - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the the item to be sent to the command - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to be sent to the command - can work with Language parameter to narrow the publication scope.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Launch Publishing Viewer for /sitecore/content/home item.

    EXAMPLE 2

    Initiate /sitecore/content/home item duplication.

    EXAMPLE 3

    Show properties of the /sitecore/content/home item.

    Related Topics

    Get-ItemWorkflowEvent

    Returns entries from the history store notifying of workflow state change for the specified item.

    Syntax

    Get-ItemWorkflowEvent [-Item] <Item> [-Identity <String>] [-Language <String[]>]

    Get-ItemWorkflowEvent [-Path] <String> [-Identity <String>] [-Language <String[]>]

    Get-ItemWorkflowEvent -Id <String> [-Database <String>] [-Identity <String>] [-Language <String[]>]

    Detailed Description

    The Get-ItemWorkflowEvent command returns entries from the history store notifying of workflow state change for the specified item.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Identity <String>

    User that has been associated with the enteries. Wildcards are supported.

    Aliases

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    -Item <Item>

    The item to have its history items returned.

    Aliases

    -Path <String>

    Path to the item to have its history items returned - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the the item to have its history items returned - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to have its history items returned - can work with Language parameter to narrow the publication scope.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Workflows.WorkflowEvent

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Related Topics

    • Execute-Workflow

    Get-TaskSchedule

    Returns one or more task schedule items using the specified criteria.

    Syntax

    Get-TaskSchedule -Item <Item>

    Get-TaskSchedule -Path <String>

    Get-TaskSchedule [[-Database] <Database>] [[-Name] <String>]

    Detailed Description

    The Get-TaskSchedule command returns one or more task schedule items, based on name/database filter, path or simply converting a Sitecore item.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    Task item to be converted.

    Aliases

    -Path <String>

    Path to the item to be returned as Task Schedule.

    Aliases

    -Database <Database>

    Database containing the task items to be returned. If not provided all databases will be considered for filtering using the "Name" parameter.

    Aliases

    -Name <String>

    Task filter - supports wildcards. Works with "Database" parameter to narrow tassk to only single database.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Tasks.ScheduleItem

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    EXAMPLE 2

    EXAMPLE 3

    Related Topics

    Invoke-Workflow

    Executes Workflow action for an item. This command used to be named Execute-Workflow - a matching alias added for compatibility with older scripts.

    Syntax

    Invoke-Workflow [-Item] <Item> [-CommandName <String>] [-Comments <String>] [-Language <String[]>]

    Invoke-Workflow [-Path] <String> [-CommandName <String>] [-Comments <String>] [-Language <String[]>]

    Invoke-Workflow -Id <String> [-Database <String>] [-CommandName <String>] [-Comments <String>] [-Language <String[]>]

    Detailed Description

    Executes Workflow action for an item. If the workflow action could not be performed for any reason - an appropriate error will be raised.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Aliases

    The following abbreviations are aliases for this cmdlet:

    • Execute-Workflow

    Parameters

    -CommandName <String>

    Namer of the workflow command.

    Aliases

    -Comments <String>

    Comment to be saved in the history table for the action.

    Aliases

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    -Item <Item>

    The item to have the workflow action executed.

    Aliases

    -Path <String>

    Path to the item to have the workflow action executed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the the item to have the workflow action executed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to have the workflow action executed - can work with Language parameter to narrow the publication scope.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Submit item to approval, item gotten from path

    EXAMPLE 2

    Reject item, item gotten from pipeline

    Related Topics

    Getting Started

    Quick start guide to get up and running with SPE.

    Ready to start using SPE? This guide will get you up and running in minutes.

    What You Need

    Before starting, ensure you have:

    • ✅ SPE installed in your Sitecore instance →

    Next Steps

    Where to go after completing the training guide.

    Congratulations on completing the SPE training guide! You now have a solid foundation in PowerShell and SPE. Here's where to go next on your journey to mastery.

    Continue Learning

    Deepen Your Knowledge

    Retrieving Items

    This page covers all the methods for finding and retrieving Sitecore items using SPE. Whether you need a single item or a collection, SPE provides flexible query options to meet your needs.

    Core Cmdlets

    Get-Item

    Use

    Security Policies

    Understanding the security policies that govern SPE is essential for properly securing your installation. SPE operates under two primary security contexts that work together to control what scripts can do.

    Overview

    SPE security operates on two levels:

    1. Application Pool Service Account - Controls OS-level access (file system, registry, network)

    File Upload Restrictions

    File upload capabilities in SPE can be restricted by file type and destination path. This provides defense in depth by preventing malicious file uploads even if the upload service is enabled.

    Overview

    When the is enabled, SPE enforces restrictions on:

    • File Types - Which file extensions and MIME types can be uploaded

    Get-ItemField

    Retrieves item fields as either names or fields or template fields.

    Syntax

    Get-ItemField [-Item] <Item> [-IncludeStandardFields] [-ReturnType <Name | Field | TemplateField>] [-Name <String[]>] [-Language <String[]>]

    Get-ItemField [-Path] <String> [-IncludeStandardFields] [-ReturnType <Name | Field | TemplateField>] [-Name <String[]>] [-Language <String[]>]

    Get-ItemField -Id <String> [-Database <String>] [-IncludeStandardFields] [-ReturnType <Name | Field | TemplateField>] [-Name <String[]>] [-Language <String[]>]

    New-ItemClone

    Creates a new item clone based on the item provided.

    Syntax

    New-ItemClone [-Item] <Item> -Destination <Item> [-Name <String>] [-Recurse]

    New-ItemClone [-Path] <String> -Destination <Item> [-Name <String>] [-Recurse]

    New-ItemClone -Id <String> [-Database <String>] -Destination <Item> [-Name <String>] [-Recurse]

    Get-ItemReference

    Returns all the items linked to the specified item..

    Syntax

    Get-ItemReference -Item <Item>

    Get-ItemReference -Item <Item> -ItemLink

    Get-ItemReference -Path <String> [-Language <String[]>]

    Get-ItemReference -Path <String> [-Language <String[]>] -ItemLink

    Get-ItemReference -Id <String> [-Database <String>] [-Language <String[]>]

    Add-BaseTemplate

    Add one or more base templates to a template item.

    Syntax

    Add-BaseTemplate -Item <Item> -TemplateItem <TemplateItem[]>

    Add-BaseTemplate -Item <Item> -Template <String[]>

    Add-BaseTemplate -Path <String> -TemplateItem <TemplateItem[]>

    Add-BaseTemplate -Path <String> -Template <String[]>

    Add-BaseTemplate -Id <String> -TemplateItem <TemplateItem[]>

    # Use the notation "." to get the current directory/item.
    $item = Get-Item -Path .
    Show-Alert -Title $item.Name
    # /sitecore/system/modules/powershell/script library/spe rocks/functions/get-datemessage
    function Get-DateMessage {
      "The current date and time is: $(Get-Date)"
    }
    # /sitecore/system/modules/powershell/script library/spe rocks/alerts/show-datemessage
    Import-Function -Name Get-DateMessage
    
    Show-Alert (Get-DateMessage)
    PS master:\> Get-ItemTemplate -Path master:\content\home
    
           BaseTemplates  : {Standard template}
           Fields         : {__Context Menu, __Display name, __Editor, __Editors...}
           FullName       : Sample/Sample Item
           Key            : sample item
           OwnFields      : {Title, Text, Image, State...}
           StandardValues : Sitecore.Data.Items.Item
           Database       : master
           DisplayName    : Sample Item
           Icon           : Applications/16x16/document.png
           ID             : {76036F5E-CBCE-46D1-AF0A-4143F9B557AA}
           InnerItem      : Sitecore.Data.Items.Item
           Name           : Sample Item
    PS master:\> Get-Item -Path master:/content/Home | Get-ItemTemplate -Recurse | ft Name, FullName, Key -auto
    
           Name              FullName                                 Key
           ----              --------                                 ---
           Sample Item       Sample/Sample Item                       sample item
           Standard template System/Templates/Standard template       standard template
           Advanced          System/Templates/Sections/Advanced       advanced
           Appearance        System/Templates/Sections/Appearance     appearance
           Help              System/Templates/Sections/Help           help
           Layout            System/Templates/Sections/Layout         layout
           Lifetime          System/Templates/Sections/Lifetime       lifetime
           Insert Options    System/Templates/Sections/Insert Options insert options
           Publishing        System/Templates/Sections/Publishing     publishing
           Security          System/Templates/Sections/Security       security
           Statistics        System/Templates/Sections/Statistics     statistics
           Tasks             System/Templates/Sections/Tasks          tasks
           Validators        System/Templates/Sections/Validators     validators
           Workflow          System/Templates/Sections/Workflow       workflow
    https://github.com/SitecorePowerShell/Console/
    #1385
    #1385
    Event Handlers
    Reports
    Reports
    Notification
    Experience Button
    Pipelines
    Tasks
    Toolbox
    Workflow Action
    Web services only (Remoting)

    Test connectivity

  • Monitoring - Comprehensive logging and alerts

    IP address blocked

    Logging and Monitoring - Monitoring remote operations

  • Remoting - Using SPE Remoting features

  • App_Config\Include\Spe\Spe.config

    Core configuration

    ✓ Yes

    App_Config\Include\Spe\Spe.Minimal.config

    Minimal deployment config

    ✓ Yes

    bin\Spe.dll

    Main assembly

    ✓ Yes

    bin\Spe.Abstractions.dll

    Abstractions assembly

    ✓ Yes

    sitecore modules\PowerShell\Services\web.config

    IIS configuration

    ✓ Yes

    sitecore modules\PowerShell\Services\RemoteAutomation.asmx

    Remoting service

    ✓ Yes

    sitecore modules\PowerShell\Services\RemoteScriptCall.ashx

    RESTful/file services

    ✓ Yes

    Web Services Security
    IIS Security
    File Upload Restrictions
    Security Checklist
    SPE Remoting Documentation
    SPE Minimal Package Download

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    New-ItemWorkflowEvent
    https://github.com/SitecorePowerShell/Console/

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    2

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Start-TaskSchedule
    https://github.com/SitecorePowerShell/Console/
    https://www.youtube.com/watch?v=N3xgZcU9FqQ&list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b&index=9

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/
    Detailed Description

    Retrieves item fields as either names or fields or template fields.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -IncludeStandardFields <SwitchParameter>

    Includes fields that are defined on "Standard template"

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -ReturnType <ReturnValue>

    Determines type returned. The possible values include:

    • Name - strings with field names.

    • Field - fields on the item

    • TemplateField - template fields.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Name <String[]>

    Array of names to include - supports wildcards.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Language <String[]>

    Language that will be analysed. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Item <Item>

    The item to be analysed.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the item to be analysed.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of the item to be analysed.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database containing the item to be analysed - can work with Language parameter to narrow the publication scope.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

      Sitecore.Data.Templates.TemplateField

      Sitecore.Data.Fields.Field

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Get list of names of non standard fields from /sitecore/content/home item

    EXAMPLE 2

    Get list of fields including standard fields from /sitecore/content/home item and list their Name, DisplayName, SectionDisplayName and Description in a table.

    Related Topics

    • Get-ItemTemplate

    • Reset-ItemField

    • https://github.com/SitecorePowerShell/Console/

    Get-ItemReference -Id <String> [-Database <String>] [-Language <String[]>] -ItemLink

    Detailed Description

    The Get-ItemReference command returns all items linked to the specified item. If -ItemLink parameter is used the command will return links rather than items.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    The item to be analysed.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of the the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database containing the item to be processed - can work with Language parameter to narrow the publication scope.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used. Globbing/wildcard supported.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -ItemLink <SwitchParameter>

    Return ItemLink that define both source and target of a link rather than items that are being linked to from the specified item.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

      Sitecore.Links.ItemLink

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    EXAMPLE 2

    Related Topics

    • Get-ItemReferrer

    • Update-ItemReferrer

    • https://github.com/SitecorePowerShell/Console/

    Add-BaseTemplate -Id <String> -Template <String[]>

    Add-BaseTemplate [-Database <String>]

    Detailed Description

    The Add-BaseTemplate command adds one or more base templates to a template item.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Item <Item>

    The item to add the base template to.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    true (ByValue)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the item to add the base template to.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of the item to add the base template to.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -TemplateItem <TemplateItem[]>

    Sitecore item or list of items of base templates to add.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Template <String[]>

    Path representing the template item to add as a base template. This must be of the same database as the item to be altered. Note that this parameter only supports a single template.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database containing the item to add the base template to - required if item is specified with Id.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West, Alex Washtell

    Examples

    EXAMPLE 1

    Add base template of /sitecore/templates/User Defined/BaseTemplate to a template, using a path.

    EXAMPLE 2

    Add multiple base templates to a template, using items.

    Related Topics

    • Remove-BaseTemplate

    • Get-ItemTemplate

    • Set-ItemTemplate

    • https://github.com/SitecorePowerShell/Console/

    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
        <sitecore>
            <controlSources>
                <source mode="on" namespace="Spe.Client.Controls" assembly="Spe">
                    <patch:delete />
                </source>
                <source mode="on" namespace="Spe.Client.Applications"
                      folder="/sitecore modules/Shell/PowerShell/" deep="true">
                    <patch:delete />
                </source>
            </controlSources>
        </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <!-- Enable remoting with HTTPS requirement -->
            <remoting>
              <patch:attribute name="enabled">true</patch:attribute>
              <patch:attribute name="requireSecureConnection">true</patch:attribute>
    
              <!-- Clear default authorization -->
              <authorization>
                <patch:delete />
              </authorization>
    
              <!-- Add specific service account -->
              <authorization>
                <add Permission="Allow" IdentityType="User" Identity="sitecore\automation-user" desc="CI/CD automation account" />
              </authorization>
            </remoting>
    
            <!-- Optionally enable file operations for package deployment -->
            <fileDownload>
              <patch:attribute name="enabled">true</patch:attribute>
            </fileDownload>
    
            <fileUpload>
              <patch:attribute name="enabled">true</patch:attribute>
            </fileUpload>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <!-- Deny anonymous access -->
          <deny users="?" />
        </authorization>
      </system.web>
    
      <system.webServer>
        <security>
          <!-- Require HTTPS -->
          <access sslFlags="Ssl" />
    
          <!-- Optional: IP restrictions for build servers -->
          <ipSecurity allowUnlisted="false">
            <add ipAddress="10.0.0.100" allowed="true" desc="Build Server 1" />
            <add ipAddress="10.0.0.101" allowed="true" desc="Build Server 2" />
          </ipSecurity>
        </security>
      </system.webServer>
    </configuration>
    # Test from remote machine using SPE Remoting module
    
    Import-Module SPE
    
    # Create session
    $session = New-ScriptSession `
        -Username "sitecore\automation-user" `
        -Password "SecurePassword123!" `
        -ConnectionUri "https://sitecore-instance.local"
    
    # Test script execution
    $result = Invoke-RemoteScript -Session $session -ScriptBlock {
        Get-Item -Path "master:\content\home" | Select-Object -ExpandProperty Name
    }
    
    Write-Host "Result: $result" -ForegroundColor Green
    
    # Close session
    Stop-ScriptSession -Session $session
    PS master:\> Get-Item master:\content\home\ | Invoke-ShellCommand "item:publishingviewer"
    PS master:\> Get-Item master:/content/home | Invoke-ShellCommand "item:duplicate"
    PS master:\> Get-Item master:/content/home | Invoke-ShellCommand "contenteditor:properties"
    PS master:\> Get-ItemWorkflowEvent -Path master:\content\home
    Date     : 2014-07-27 14:23:33
    NewState : {190B1C84-F1BE-47ED-AA41-F42193D9C8FC}
    OldState : {46DA5376-10DC-4B66-B464-AFDAA29DE84F}
    Text     : Automated
    User     : sitecore\admin
    
    Date     : 2014-08-01 15:43:29
    NewState : {190B1C84-F1BE-47ED-AA41-F42193D9C8FC}
    OldState : {190B1C84-F1BE-47ED-AA41-F42193D9C8FC}
    Text     : Just leaving a note
    User     : sitecore\admin
    PS master:\> Get-TaskSchedule
    Name                             Database        Active   Auto Remove  Is Due   Expired  Completed    Last Run               Next Run
    ----                             --------        ------   -----------  ------   -------  ---------    --------               --------
    __Task Schedule                  master          True     False        True     False    False        0001-01-01 00:00:00    0001-01-01 00:00:00
    Check Bounced Messages           master          True     False        False    False    False        2014-07-29 10:18:43    2014-07-29 22:48:43
    Check DSN Messages               master          True     False        False    False    False        2014-07-29 10:19:18    2014-07-29 22:49:18
    Clean Confirmation IDs           master          True     False        False    False    False        2014-07-28 22:14:30    2014-07-31 02:14:30
    Clean Message History            master          True     False        False    False    False        2014-07-29 10:19:18    2014-07-29 22:49:18
    Close Outdated Connections       master          True     False        False    False    False        2014-07-29 12:30:22    2014-07-29 13:30:22
    Test-PowerShell                  master          True     False        False    False    False        2014-07-28 14:30:06    2014-08-01 17:32:07
    __Task Schedule                  web             True     False        True     False    False        0001-01-01 00:00:00    0001-01-01 00:00:00
    Check Bounced Messages           web             True     False        True     False    False        2013-11-04 08:36:22    2013-11-04 21:06:22
    Check DSN Messages               web             True     False        True     False    False        2013-11-04 08:36:22    2013-11-04 21:06:22
    Clean Confirmation IDs           web             True     False        False    False    False        2013-11-04 08:36:22    2013-11-04 21:36:22
    Clean Message History            web             True     False        True     False    False        2013-11-04 08:36:22    2013-11-04 21:06:22
    Close Outdated Connections       web             True     False        True     False    False        2013-11-04 09:36:23    2013-11-04 10:36:23
    Test-PowerShell                  web             True     False        True     False    False        2013-11-04 09:46:29    2013-11-04 09:46:30
    PS master:\> Get-TaskSchedule -Name "*Check*"
    Name                             Database        Active   Auto Remove  Is Due   Expired  Completed    Last Run               Next Run
    ----                             --------        ------   -----------  ------   -------  ---------    --------               --------
    Check Bounced Messages           master          True     False        False    False    False        2014-07-29 10:18:43    2014-07-29 22:48:43
    Check DSN Messages               master          True     False        False    False    False        2014-07-29 10:19:18    2014-07-29 22:49:18
    Check Bounced Messages           web             True     False        True     False    False        2013-11-04 08:36:22    2013-11-04 21:06:22
    Check DSN Messages               web             True     False        True     False    False        2013-11-04 08:36:22    2013-11-04 21:06:22
    PS master:\> Get-TaskSchedule -Name "*Check*" -Database "master"
    Name                             Database        Active   Auto Remove  Is Due   Expired  Completed    Last Run               Next Run
    ----                             --------        ------   -----------  ------   -------  ---------    --------               --------
    Check Bounced Messages           master          True     False        False    False    False        2014-07-29 10:18:43    2014-07-29 22:48:43
    Check DSN Messages               master          True     False        False    False    False        2014-07-29 10:19:18    2014-07-29 22:49:18
    PS master:\> Invoke-Workflow -Path master:/content/home -CommandName "Submit" -Comments "Automated"
    PS master:\> Get-Item master:/content/home | Invoke-Workflow -CommandName "Reject" -Comments "Automated"
    PS master:\> Get-ItemField -Path master:\content\home
    
    Text
    Title
    Image
    PS master:\> Get-Item master:\content\home | Get-ItemField -IncludeStandardFields -ReturnType Field -Name "*" | ft Name, DisplayName, SectionDisplayName, Description -auto
    
    Name                                DisplayName                        SectionDisplayName Description
    ----                                -----------                        ------------------ -----------
    __Revision                          Revision                           Statistics
    __Standard values                   __Standard values                  Advanced
    __Updated by                        Updated by                         Statistics
    __Validate Button Validation Rules  Validation Button Validation Rules Validation Rules
    __Created                           Created                            Statistics
    __Thumbnail                         Thumbnail                          Appearance
    __Insert Rules                      Insert Rules                       Insert Options
    __Short description                 Short description                  Help
    __Created by                        Created by                         Statistics
    __Presets                           Presets                            Layout
    Text                                Text                               Data               The text is the main content of the document.
    PS master:\>Get-ItemReference -Path master:\content\home
    
    Name                             Children Languages                Id                                     TemplateName
    ----                             -------- ---------                --                                     ------------
    Home                             True     {en, de-DE, es-ES, pt... {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Home                             True     {en, de-DE, es-ES, pt... {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    PS master:\>Get-Item master:\content\home | Get-ItemReference -ItemLink
    
    SourceItemLanguage : en
    SourceItemVersion  : 1
    TargetItemLanguage :
    TargetItemVersion  : 0
    SourceDatabaseName : master
    SourceFieldID      : {F685964D-02E1-4DB6-A0A2-BFA59F5F9806}
    SourceItemID       : {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}
    TargetDatabaseName : master
    TargetItemID       : {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}
    TargetPath         : /sitecore/content/Home
    PS master:\> Add-BaseTemplate -Path "master:/sitecore/content/User Defined/Page" -Template "/sitecore/templates/User Defined/BaseTemplate"
    PS master:\> $baseA = Get-Item -Path master:/sitecore/content/User Defined/BaseTemplateA
           PS master:\> $baseB = Get-Item -Path master:/sitecore/content/User Defined/BaseTemplateB
           PS master:\> Add-BaseTemplate -Path "master:/sitecore/content/User Defined/Page" -TemplateItem @($baseA, $baseB)

    ✅ Appropriate permissions to access PowerShell tools → Security

  • ✅ Basic understanding of Sitecore concepts (items, templates, fields)

  • You don't need to know PowerShell or programming to get started! This guide is designed for Sitecore users who want to automate tasks.

    Opening the PowerShell Interfaces

    SPE provides two main interfaces for running scripts:

    The Console - Quick Commands

    The PowerShell Console is perfect for running quick, one-off commands.

    How to open:

    1. Log into Sitecore

    2. Go to Desktop (bottom left icon)

    3. Click PowerShell Console

    Console Interface

    When to use the Console:

    • Running single commands

    • Quick queries and checks

    • Interactive exploration

    • Testing command syntax

    The ISE - Script Development

    The PowerShell ISE (Integrated Scripting Environment) is a full-featured script editor.

    How to open:

    1. Log into Sitecore

    2. Go to Desktop (bottom left icon)

    3. Click Development Tools

    4. Click PowerShell ISE

    ISE Interface

    When to use the ISE:

    • Writing multi-line scripts

    • Developing reusable tools

    • Saving scripts for later use

    • Debugging complex logic

    Learn more: Console | ISE

    Your First Command

    Let's run your very first SPE command!

    Step 1: Open the Console

    Follow the instructions above to open the PowerShell Console.

    Step 2: Run a Command

    Type this command and press Enter:

    Step 3: Examine the Results

    You should see output showing details about your Home item:

    Congratulations! You just retrieved a Sitecore item using PowerShell. This is the foundation of everything you'll do with SPE.

    Understanding What Just Happened

    Let's break down that command:

    • Get-Item - The command (cmdlet) that retrieves an item

    • -Path - A parameter that specifies which item to get

    • "master:\content\home" - The location of the item

      • master: - The database

      • \content\home - The path to the item

    Try These Next

    Now that you've run your first command, try these:

    List Children of Home

    This shows all direct children of the Home item.

    List All Descendants

    Be careful with -Recurse on large content trees! It can take a long time. See Common Pitfalls for more.

    Get Item Properties

    PowerShell has a default set of properties to format to the output window even though the objects returned still contain all the properties.

    Using Select-Object, the properties are trimmed and the output window reflects the specific fields.

    Output:

    Find Items by Name

    This finds all items under Home that have "Sample" in their name.

    Using the ISE

    The ISE is more powerful for writing longer scripts. Let's try it out.

    Step 1: Open the ISE

    Follow the instructions above to open the PowerShell ISE.

    Step 2: Write a Script

    In the top pane (script editor), type:

    Step 3: Execute the Script

    Click the Execute button (▶️) or press Ctrl-E.

    Step 4: View Results

    The bottom pane shows the output of your script.

    The ISE provides IntelliSense - start typing a command and press Ctrl+Space to see suggestions!

    Key Concepts

    Variables

    Variables store data and start with $:

    Learn more: Variables

    Pipelines

    The pipe | chains commands together:

    Learn more: Commands and Pipelines

    Providers

    SPE uses providers to access different data stores. The most important is the Sitecore provider:

    Learn more: Providers

    Common Tasks

    Here are some common tasks you can do right now:

    Check if Item Exists

    Count Items by Template

    Find Items Modified Recently

    Export Data to CSV

    Getting Help

    SPE includes extensive built-in help:

    Get Help for a Command

    Get Detailed Help

    Get Examples

    List All SPE Commands

    Learn more: Help

    Script Library

    The ISE includes a Script Library with ready-to-use examples:

    1. Open the ISE

    2. Click Open in the ribbon

    3. Click to expand SPE in the tree

    4. Expand folders to find examples:

      • Training - Learning exercises

      • Reports - Content reports

      • Tools - Utility scripts

    The Script Library is a great way to learn! Read through examples to see how different commands work together.

    Safety Tips

    Before you continue, remember these important safety rules:

    Always Test First

    • ❌ Don't run scripts in production without testing

    • ✅ Do test in development first

    • ✅ Do understand what a script does before running it

    Be Careful with Modifications

    Commands that change data:

    • Remove-Item - Deletes items (can be recovered from Recycle Bin)

    • Set-Item - Modifies items

    • Move-Item - Moves items

    • Publish-Item - Publishes changes to web database

    Use Version Control

    • Save important scripts to source control

    • Document what your scripts do

    • Share scripts with your team

    Review Security

    IMPORTANT: SPE is powerful and requires proper security configuration. Review the Security Guide before deploying to any non-development environment.

    Next Steps

    Now that you're up and running:

    1. Learn the syntax: Language Basics

    2. Master commands: Commands and Pipelines

    3. Understand providers: Providers

    4. Write your first scripts: Your First Scripts

    5. Avoid mistakes:

    Quick Reference

    Essential Commands

    Command
    Description

    Get-Item

    Returns an object at the specified path.

    Get-ChildItem

    Returns children at the specified path. Supports recursion.

    Get-Help

    Returns the help documentation for the specified command or document.

    Get-Command

    Returns a list of commands.

    ForEach-Object

    Enumerates over the objects passed through the pipeline.

    Where-Object

    Enumerates over the objects passed through the pipeline and filters objects.

    Path Format

    Special Variables

    Ready to dive deeper? Continue with Language Basics!

    Installation Guide
    Working with Items

    Master the core operations for manipulating Sitecore content:

    • Working with Items - Complete guide to item manipulation

    • Retrieving Items - Advanced querying techniques

    • Editing Items - Proper item editing workflows

    • Creating and Removing Items - Item lifecycle management

    • - Reorganizing content

    • - Working with multilingual content

    • - Managing permissions with PowerShell

    • - Tips for writing efficient scripts

    User Interfaces

    Build rich, interactive experiences for your scripts:

    • Interactive Dialogs - Build rich UI for your scripts

    • Show-ListView - Display data in tables with actions

    • Read-Variable - Create custom input forms

    • Show-FieldEditor - Edit item fields in dialogs

    • - Display formatted output

    Building Useful Tools

    Create custom tools that extend Sitecore functionality:

    • Creating Reports - Build custom content reports

    • Creating Tasks - Schedule automated jobs

    • Content Editor Integration - Add context menu items

    • Toolbox Scripts - Create administrative tools

    • - Add Control Panel applications

    • - React to Sitecore events

    Advanced Topics

    Take your skills to the next level:

    • Remoting - Automate Sitecore from external scripts

    • Packaging - Package and deploy your work

    • Workflows - Integrate with Sitecore workflows

    • Web API - Expose scripts via REST API

    • - Organize reusable code

    Reference Materials

    Beyond the learning paths above, you'll find these resources helpful:

    • Command Reference - Complete list of all SPE cmdlets

    • Code Snippets - Ready-to-use examples for common scenarios

    • Interfaces Guide - Deep dive into Console, ISE, and dialogs

    Practice Projects

    Here are some project ideas to practice your skills:

    Beginner Projects

    1. Content Audit Report

      • Find all items without workflow

      • List items with empty required fields

      • Identify orphaned media items

      • Export results to CSV

    2. Bulk Field Updater

      • Prompt user for template and field name

      • Find all items of that template

      • Update the specified field

    3. Publishing Dashboard

      • Show items published in last 24 hours

      • Compare master vs web databases

      • Display publishing statistics

    Intermediate Projects

    1. Content Migration Tool

      • Copy items between databases

      • Preserve all field values and versions

      • Handle item relationships

      • Create detailed log

    2. Security Auditor

      • List all users and their roles

      • Show items with custom security

      • Identify security inheritance breaks

    3. Template Analyzer

      • Find all templates

      • Show template inheritance tree

      • List fields for each template

    Advanced Projects

    1. Custom Reporting Engine

      • Build reusable report framework

      • Support multiple output formats

      • Add scheduling capabilities

      • Email reports automatically

    2. Content Health Monitor

      • Check for broken links

      • Validate media items exist

      • Find duplicate items

    3. Deployment Assistant

      • Compare environments

      • Package changed items

      • Generate deployment scripts

    Essential Security Review

    CRITICAL: Before deploying SPE to any non-development environment, review Security Hardening and complete the Security Checklist. Remember: SPE should NEVER be installed on CD servers or be accessible from internet-facing instances.

    Get Help and Support

    When You Get Stuck

    • Built-in help: Use Get-Help <command-name> in the Console

    • Troubleshooting Guide - Common issues and solutions

    • #module-spe - Sitecore Community Slack channel

    • GitHub - Report issues or request features

    Best Practices Checklist

    As you continue working with SPE, keep these best practices in mind:

    Code Quality

    • ✅ Use full command names (not aliases) in scripts

    • ✅ Write clear, descriptive variable names

    • ✅ Add comments to explain complex logic

    • ✅ Use functions for reusable code

    • ✅ Handle errors with try/catch

    • ✅ Test scripts in development first

    Performance

    • ✅ Filter early in pipelines

    • ✅ Use Content Search for large queries

    • ✅ Avoid -Recurse on large trees

    • ✅ Use efficient collection types

    • ✅ Suppress output properly (> $null)

    • ✅ Measure performance with Measure-Command

    Security

    • ✅ Never run untrusted scripts

    • ✅ Use source control for all scripts

    • ✅ Review security settings regularly

    • ✅ Apply principle of least privilege

    • ✅ Enable audit logging

    • ✅ Test security policies

    Maintenance

    • ✅ Document what scripts do

    • ✅ Use consistent naming conventions

    • ✅ Organize scripts in Script Library

    • ✅ Version control your work

    • ✅ Share knowledge with team

    • ✅ Review and refactor regularly

    Additional Learning Resources

    • Video Series - Official tutorial videos

    • Blog Collection - Community articles and examples

    • Microsoft PowerShell Docs - General PowerShell reference

    Share and Contribute

    As you gain experience:

    • Share your scripts with the community on GitHub

    • Help answer questions on Slack and Stack Exchange

    • Write blog posts about solutions you've built

    • Submit improvements to this documentation

    The best way to solidify your learning is to teach others!

    Quick Reference Card

    Essential Commands

    Common Patterns


    You're Ready!

    You've completed the training and now have the skills to:

    • ✅ Write PowerShell scripts for Sitecore

    • ✅ Understand providers, pipelines, and commands

    • ✅ Avoid common pitfalls

    • ✅ Build useful automation tools

    • ✅ Work safely and securely

    Happy scripting! 🚀

    Remember: The best way to learn is by doing. Start small, experiment often, and don't be afraid to make mistakes in development. You've got this!

    Get-Item
    to retrieve a single item or items matching a query. This cmdlet throws an error if the item doesn't exist (unless using queries that may return zero results).

    Key uses:

    • Retrieve a single item by path

    • Query items using Sitecore query

    • Get items by ID or URI

    Get-ChildItem

    Use Get-ChildItem to retrieve children and descendants of an item. This cmdlet is ideal for traversing content trees.

    Key uses:

    • List immediate children

    • Recursively traverse item trees

    • Filter by template or other properties

    Dynamic Parameters

    SPE extends the standard PowerShell cmdlets with dynamic parameters. These appear when you specify a Sitecore database path:

    Parameter
    Description
    Available On
    Example

    AmbiguousPaths

    Show all items matching ambiguous criteria

    Get-Item

    -AmbiguousPaths

    Database

    Specify database when using ID

    Get-Item

    -Database "master"

    ID

    Match item by GUID

    Get-Item, Get-ChildItem

    Retrieving by Path

    The most common way to retrieve items is by their Sitecore path.

    Example: Retrieve an item by path.

    Output:

    The /sitecore portion of the path is optional. Both master:\content\home and master:\sitecore\content\home work identically.

    Example: The C# equivalent for reference.

    Working with Languages

    Retrieve items in specific languages or all languages using the -Language parameter with wildcards.

    When working with multi-language sites, you may find that specifying the -Language parameter results in a more consistent behavior.

    Example: Retrieve the Danish version of an item.

    Output:

    Example: Retrieve latest version for all languages.

    Output:

    Working with Versions

    Retrieve specific versions or all versions using the -Version parameter.

    Example: Retrieve all versions in all languages.

    Output:

    Example: Using wildcards for partial matches (all English variants).

    Retrieving Children

    Use Get-ChildItem to retrieve an item's children, with optional recursion.

    Example: Retrieve immediate children only.

    Example: Retrieve all descendants recursively.

    Example: Retrieve children in all languages and versions.

    Retrieving by ID

    Use the -ID parameter to retrieve items by their GUID. This is useful when you know the item ID but not its path.

    Example: Retrieve an item by ID.

    Output:

    When using -ID, you must specify the database path (e.g., master:) to activate the dynamic parameter.

    Retrieving by URI

    ItemUri encodes the database, item ID, language, and version in a single string.

    Example: Retrieve an item by URI.

    Output:

    Sitecore Query

    Use Sitecore query to find items matching complex criteria. This is more efficient than traversing the tree when you need specific items.

    Sitecore query paths containing reserved keywords or spaces require # delimiters: #path with spaces#

    Example: Find all items with a specific template.

    Output:

    Example: Query with language and version wildcards.

    Example: Query using dates (ISO format required) filtering by the publishing restriction where the item (not version) has a future date.

    Fast Query

    Sitecore has deprecated this functionality in XM/XP 10.1.

    XPath with Axes

    For complex queries using XPath axes, use the Sitecore API directly or prepend the context path.

    Example: Use XPath axes to find ancestors.

    Custom Property Sets

    Use custom property sets with Select-Object to retrieve specific groups of properties.

    Example: Retrieve security properties using PSSecurity.

    Output:

    Check out Item Security to learn about managing the security settings using SPE.

    Example: Retrieve template information using PSTemplate.

    Output:

    Example: Retrieve image metadata using PSImage.

    Output:

    Example: Retrieve schedule information using PSSchedule.

    Output:

    Using Initialize-Item

    If you retrieve items using the Sitecore API directly, wrap them with Initialize-Item to add SPE's automatic properties.

    Example: Query using Sitecore API and wrap with SPE properties.

    Common Retrieval Patterns

    Pattern: Find Items by Template

    Pattern: Find Recently Modified Items

    Pattern: Find Items by Field Value

    Pattern: Get All Media Items Above Size Threshold

    Performance Tips

    • Use Sitecore query when you need specific items from a large tree

    • Use Get-ChildItem for small trees or when you need all items

    • Filter early - use query predicates instead of Where-Object when possible

    • Limit language/version retrieval - only use -Language * and -Version * when necessary

    See Also

    • Editing Items - Update item properties and fields

    • Best Practices - Performance optimization guidance

    • Appendix - Common Commands - Full cmdlet reference

    References

    • Performance details for different query methods

    • Escaping queries with reserved keywords

    • Working with Sitecore Items in PowerShell Extensions

    Sitecore User Account - Controls Sitecore API access (content, security, configuration)

    Both security contexts work together to determine what a PowerShell script can accomplish.

    Application Pool Service Account

    How It Works

    The Windows PowerShell runspace executes under the identity of the IIS application pool service account. This account determines what OS-level resources the script can access through PowerShell providers.

    Key Providers Affected:

    • FileSystem - Read/write files and directories

    • Registry - Read/write Windows registry keys

    • Environment - Access environment variables

    • Certificate - Access certificate stores

    Security Implications

    The application pool service account gives SPE access to OS-level features. If the service account can delete files from the root directory, SPE can do the same.

    Example: If your application pool runs as NETWORK SERVICE or ApplicationPoolIdentity, the script may have:

    • Read/write access to C:\inetpub\wwwroot

    • Access to the application directories

    • Potentially access to other directories on the system

    Common Service Account Types

    Service Account
    Typical Permissions
    Security Considerations

    ApplicationPoolIdentity

    Limited local access

    No user profile ($HOME is empty); may have broader file system access than expected

    NetworkService

    Network and local access

    Similar to ApplicationPoolIdentity; verify file system permissions

    Custom Domain Account

    Defined by domain policy

    Has a user profile; permissions controlled by Active Directory

    LocalSystem

    Full system access

    Best Practices

    ✅ Do:

    • Use the principle of least privilege

    • Audit file system permissions for the service account

    • Restrict the account to only necessary directories

    • Use a named service account when you need specific permissions

    • Test what directories the account can access

    ❌ Don't:

    • Run as LocalSystem or Administrator

    • Grant the service account unnecessary file system permissions

    • Assume ApplicationPoolIdentity is fully restricted

    • Allow write access to system directories

    Verifying Service Account Access

    Example: Check which directories the service account can access:

    Restricting File System Access

    You can restrict which directories SPE can access by:

    1. NTFS Permissions - Remove unnecessary file system permissions from the service account

    2. AppLocker - Use Windows AppLocker to restrict PowerShell execution paths

    3. File Upload Restrictions - Configure SPE to only allow uploads to specific locations (see Web Services)

    Sitecore User Account

    How It Works

    Scripts execute within the security context of the logged-in Sitecore user. The user's Sitecore roles and permissions determine what content and functionality the script can access through the Sitecore API.

    Key Areas Controlled:

    • Content item access (read/write/delete)

    • Security management (users/roles)

    • Configuration access

    • Workflow operations

    • Publishing operations

    Security Implications

    The Sitecore security model applies to all script operations that use the Sitecore API:

    However, scripts can bypass Sitecore security just like any other Sitecore API code:

    Security Note: Scripts can disable Sitecore security checks using SecurityDisabler and other disablers. This is why limiting who can write and execute scripts is critical.

    Application-Level Security

    SPE features are protected by Sitecore security at the application level. Access to SPE interfaces is controlled through item-level security in the Core database.

    Configuration Location: core:\content\Applications\PowerShell

    Feature
    Default Visibility
    Security Path

    PowerShell Console

    sitecore\Developer (read)

    core:\content\Applications\PowerShell\PowerShellConsole

    PowerShell ISE

    sitecore\Developer (read)

    core:\content\Applications\PowerShell\PowerShellIse

    PowerShell ListView

    sitecore\Sitecore Client Users (read)

    core:\content\Applications\PowerShell\PowerShellListView

    PowerShell Runner

    sitecore\Sitecore Client Users (read)

    Note: Security is validated in each SPE application within the OnLoad function.

    Menu Item Security

    Context menu items in the Content Editor are also protected by security.

    Configuration Location: core:\content\Applications\Content Editor\Context Menues\Default\

    Feature
    Visibility
    Command State

    Edit with ISE

    sitecore\Developer (read)

    Enabled when item template is PowerShell Script, otherwise Hidden

    Console

    sitecore\Developer (read)

    Enabled when user is admin or in role sitecore\Sitecore Client Developing, otherwise Hidden

    Scripts

    sitecore\Sitecore Limited Content Editor (deny read)

    Enabled when the service and user are authorized to execute, otherwise Hidden

    Note: PowerShell Script Library and PowerShell Script items have additional visibility and enabled rules. Adjust role permissions on these items to control menu visibility.

    Best Practices

    ✅ Do:

    • Only grant SPE access to trusted administrators

    • Use Sitecore roles to control feature access

    • Require Session Elevation (UAC) for production environments

    • Audit which users have access to Developer and related roles

    • Review script libraries for appropriate security settings

    • Use delegated access for controlled privilege escalation

    ❌ Don't:

    • Grant sitecore\Developer role to content authors

    • Assume Sitecore security prevents all unauthorized actions

    • Allow untrusted users to write or execute scripts

    • Ignore the fact that scripts can disable security

    • Give broad access to SPE features

    Verifying User Access

    Example: Check current user context and permissions:

    Combined Security Model

    Both security contexts work together. A script is limited by whichever context is more restrictive:

    Example Scenarios:

    Scenario
    Service Account
    User Account
    Result

    Read Sitecore content

    Has file access

    Has read permission

    ✅ Success

    Read Sitecore content

    Has file access

    No read permission

    ❌ Denied by Sitecore

    Delete file outside Sitecore

    No file permission

    Is administrator

    Least Privilege Strategy

    Implement defense in depth by restricting both security contexts:

    Service Account

    • Minimum file system access

    • No access to sensitive directories

    • Regular permission audits

    Sitecore User Account

    • Role-based access control

    • Session elevation required

    • Regular role membership audits

    • Script library security reviews

    Additional Layers

    • Session Elevation (UAC) - Require reauthentication

    • Web Services Security - Disable unnecessary endpoints

    • IIS-Level Security - Block anonymous access

    • Monitoring and Logging - Detect unauthorized access

    Next Steps

    • Configure Session Elevation to add an additional authentication layer

    • Review Web Services Security if you need external access

    • Learn about User and Role Management

    • Complete the Security Checklist

    References

    • Sitecore Security API Documentation

    • IIS Application Pool Identities

    Upload Locations - Which directories files can be written to

    These restrictions apply to uploads via:

    • SPE Remoting file upload

    • Custom scripts using upload functionality

    This feature was introduced in SPE with #1362

    Default Configuration

    By default, SPE allows limited file types and restricts uploads to the Sitecore temp folder:

    File Type Restrictions

    How It Works

    File types can be restricted using:

    1. File Extensions - Specific extensions like .csv, .txt, .xml

    2. MIME Type Patterns - Wildcards like image/*, text/*, application/json

    Configuration Examples

    Allow Specific Extensions

    Allow MIME Type Categories

    Allow Office Documents

    Common File Type Patterns

    File Type
    Extension Pattern
    MIME Type Pattern

    Images

    .jpg, .png, .gif

    image/*

    Documents

    .pdf, .doc, .docx

    application/pdf, application/msword

    Spreadsheets

    .xls, .xlsx, .csv

    application/vnd.ms-excel, text/csv

    Text Files

    .txt, .log

    Security Warning: Be extremely careful allowing executable file types like .exe, .dll, .ps1, .bat, .cmd, .vbs, .js. These can be used to compromise the server.

    Upload Location Restrictions

    How It Works

    SPE restricts where files can be uploaded using path patterns. These paths support Sitecore variables.

    Sitecore Path Variables

    Variable
    Resolves To
    Typical Path

    $SitecoreDataFolder

    Data folder

    C:\inetpub\wwwroot\App_Data

    $SitecoreLogFolder

    Log folder

    C:\inetpub\wwwroot\App_Data\logs

    $SitecorePackageFolder

    Package folder

    C:\inetpub\wwwroot\App_Data\packages

    $SitecoreTempFolder

    Temp folder

    Configuration Examples

    Allow Only Temp Folder (Most Secure)

    Recommended: Standardize your solution with a folder that you will routinely clean.

    Allow Multiple Locations

    Dangerous Locations to NEVER Allow

    ❌ Never allow uploads to these locations:

    Complete Configuration Examples

    Secure Configuration (Data Import Use Case)

    Allow CSV/Excel imports to a dedicated import folder:

    Best Practices

    Security Recommendations

    ✅ Do:

    • Use the principle of least privilege - only allow necessary file types

    • Restrict uploads to non-web-accessible folders when possible

    • Use $SitecoreTempFolder as the primary upload location

    • Create dedicated subdirectories for different upload purposes

    • Regularly clean up uploaded files

    • Monitor upload activity

    • Use both extension AND MIME type patterns for defense in depth

    • Test your restrictions before deploying to production

    ❌ Don't:

    • Allow executable file types (.exe, .dll, .ps1, etc.)

    • Allow uploads to the web root or bin folder

    • Allow uploads to system directories

    • Use wildcard MIME types like */* (allows everything)

    • Forget to restrict both file types AND locations

    • Allow script files that could be executed

    • Trust client-provided file extensions without validation

    Configuration Strategy

    1. Start Restrictive - Begin with minimal allowed types and locations

    2. Add as Needed - Only add permissions when you have a specific use case

    3. Document Reasons - Comment your configuration explaining why each type/location is allowed

    4. Regular Review - Audit allowed types and locations quarterly

    Troubleshooting

    Upload fails even though file type is allowed

    Possible causes:

    1. Location is not in allowedLocations

    2. MIME type doesn't match pattern

    3. File extension doesn't match pattern

    Solution: Check both file type and location configuration.

    MIME type wildcard doesn't work

    Cause: Pattern syntax error or MIME type mismatch.

    Solution: Use specific MIME types or verify wildcard syntax (image/*, not image*).

    Variable like $SitecoreTempFolder doesn't resolve

    Cause: Variable not recognized by SPE configuration.

    Solution: Use supported Sitecore variables or absolute paths.

    Related Topics

    • Web Services Security - Enable/disable file upload service

    • Security Checklist - Validate your configuration

    • Logging and Monitoring - Monitor upload activity

    References

    • GitHub Issue #1362 - Feature introduction

    File Upload service
    Detailed Description

    Creates a new item clone based on the item provided.

    © 2010-2019 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Parameters

    -Destination <Item>

    Parent item under which the clone should be created.

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Name <String>

    Name of the item clone.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Recurse <SwitchParameter>

    Add the parameter to clone thw whole branch rather than a single item.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Item <Item>

    The item to be cloned.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    -Path <String>

    Path to the item to be cloned.

    Aliases

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Id <String>

    Id of the item to be cloned

    Aliases

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    -Database <String>

    Database of the item to be cloned if item is specified through its ID.

    Aliases

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE

    Clone /sitecore/content/home/ under /sitecore/content/new-target/ with the "New Home" name.

    Related Topics

    • Get-ItemClone

    • ConvertFrom-ItemClone

    • New-Item

    • https://github.com/SitecorePowerShell/Console/

    Authoring Reports

    Building reports is a straightforward task. We've provided a variety of examples for you to model when designing your own.

    Dynamic Reports

    The Authorable Reports module includes reports such as Index Viewer and Rules based report that provide input dialogs to help make the reports dynamic.

    Note: The Index Viewer and Rules Based Report are bundled as separate a package on the Sitecore Marketplace.

    Index Viewer

    The Index Viewer report provides a great example at how to build a generic report that queries against the Sitecore index. By navigating to Sitecore -> Toolbox -> Index Viewer you can conveniently launch the report.

    First you will be prompted with a dialog to select the index to search.

    Next you will be prompted with a variety of buttons and knobs to narrow down the search results.

    Finally the report is shown. Each row has an option to show more field results.

    The Show Full Info link will then returns the additional fields not shown in the report.

    The Authorable Reports module has a few points of interest.

    • The script library Internal/List View/Ribbon/SearchResultItem instructs the report to show the action scripts when the row contains an entry with the typename SearchResultItem.

    • The script library Toolbox/Index Viewer represents the shortcut.

    Examples:

    Static Reports

    The Content Reports module includes other reports used for auditing. Below are some examples on how to create your own. You can control the report menu with the Enable and Show rules. This can be helpful if you want to secure specific reports with security roles.

    The rules engine can be used the control the report export and action commands. Use the Enable and Show rules to make the necessary changes.

    Examples:

    Report Actions

    Content extracted from article written by Adam.

    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.

    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

    The variable $selectedData is provided to the script automatically by SPE in context of the content of the results on Show-ListView.

    What input is passed to an action script?

    When your action script is executed the environment is initialized with a number of variables at your disposal as seen below:

    • $selectedData – the selected objects in the list view (the same will be passed to the $resultSet variable for compatibility with older scripts)

    • $allData – all objects passed to the list view using the -Data parameter.

    • $filteredData

    Consequently you get the full state of the report the user sees in the UI and you can act upon it.

    How the report determines if your action is visible?

    You can have multiple actions defined with dynamic visibility. The actions are generally only relevant in the context of your report. This is done on two levels. The first level happens based on the location of the script and .Net object type you are displaying in the report. The second level is based on Sitecore rules. For the action to appear all of the following conditions must be met:

    • All scripts visible in the report should be located in an enabled module.

    • The action script should be within the path /Internal/List View/Ribbon/[Object type]. The [Object type] is the name of the .Net class for which the action is valid. For example, if you want your action to be visible for Sitecore.Data.Items.Item then save the script at the path /Internal/List View/Ribbon/Item.

    Using rules to control action visibility

    Rules add the full power of the Sitecore rules engine – similarly to what you can do on context menu items or ribbon actions in Content Editor. Some examples where this can be useful include only enabling or disabling the action for items located under a specific branch of the tree or if a exists.

    The following screenshot shows how to create an action that only appears in reports that list objects of type Item that are of template Schedule.

    For specific reports this global state might not always be enough. You can narrow down the rules further by using the report name. Name your report by providing an additional parameter to Show-ListView.

    Consider the following script:

    The output of the report will be like any other unnamed report but adds support for additional rules. Let's say I want my action to open a new report that lists all the children of the selected items in the report "ListChildren". After running the action my script should display the new report with the children and close the "ListChildren" report. Not very useful but illustrates the point.

    Now I need to save my script in the proper Script Library in my enabled module:

    At this point my action will show on all reports what list Item objects. But now that my script is saved I can modify its rules to narrow it down only to Show for reports named "ListChildren". For this I can click the Runtime button in the ISE ribbon and edit the Show if rules are met or not defined field.

    Now you can specify that you want the action to only appear when the report is named "ListChildren".

    Confirm the save on all dialogs to persist your changes. Now our action appears when we run this script in ISE.

    The action does not appear if no view name is provided to the -ViewName parameter. Running the script below will produce a report with the action not shown:

    Updating report in place

    The above action works just fine but will close the previous report and open a new report window in the Sitecore desktop. That's not a great user experience. What if you want to update the content of the report in place using the action? That's possible using the Update-ListView command. Consider the following script:

    In this case we're not closing the existing report but rather updating the list in place, all you need to do is send the new data to the Update-ListView command.

    Showing user progress for long running scripts

    One last thing that you might wonder is if the Write-Progress command works as it does in case of ISE or the dialog that runs scripts from Content Editor context menu. Let’s copy the following script into your action:

    And you will see the following output:

    Showing other PowerShell dialogs

    The action runs fully asynchronously so you’re free to show any of the power of the provided commands. This means that you can ask for additional input using the Read-Variable command or Show alert using the Show-Alert command or do just about anything possible otherwise from the context menu, ribbon or other interactive integration points.

    Passing additional data to actions

    The Show-ListView command has one more useful parameter named -ActionData which I mentioned above but is worth mentioning again. Anything passed using this parameter will be set as the $actionData variable – this means your report and actions can pass custom data in them it can be as simple as an object or as complex as a hashtable so there is really no hard limit on what can progress from a report to report. Any object that was passed to Show-ListView using the -ActionData parameter will be available to your action.

    Actions running in persistent sessions

    The persistent session ID will be respected and your script will run in that persistent session if it's already in memory or create a persistent session if it's not.

    Alternatively you can elect to simply freeze the session the initial script that generated report was running in and run actions in that same frozen session by using the -ActionsInSession parameter.

    UI Elements

    The Show-ListView command provides the Hide parameter to control visibility of the UI elements.

    Add parameter -Hide with one or more of the following options:

    • AllExport - hides all export scripts (left-most ribbon panel)

    • NonSpecificExport - hides export filters that are not specific to this view as specified by -ViewName (left-most ribbon panel)

    • Filter - hides filter panel

    Example: The following example all of the UI elements in the report.

    Examples from the community!

    for Sitecore product has published reports on Github that you can checkout .

    Appendix

    Downloads are hosted on Github

    Compatibility Table

    Legend: "–" - not supported; "✓" - supported.

    Sitecore 9.3 and newer

    Sitecore 9.2 and older

    Compatibility Notes

    • [1] Released by Sitecore for SXA which can be download from the however you should be safe simply installing the official SPE release on GitHub.

    • [2] Some features are not available. It is recommended to upgrade to the latest version available for 9.2.

      • Publish-Item command unsupported ()

    Releases

    When reviewing the different download packages you may see some names that are not too clear. The following list outlines what those names should mean.

    • N.X : Full N.X release - This refers to the package used by Standalone and CM roles. This includes what is required to see the PowerShell ISE, Console and their associated services.

    • N.X Minimal : Server-side remoting only - This refers to the package with only files. Useful for remotely connecting to SPE.

    • N.X Authorable Reports : Additional reports and tools - This package is a sublemental installation to the full version with additional reports. With version 6.0 this package is no longer needed as the reports are included with the full release.

    Providers

    PowerShell providers expose data stores through a consistent interface that resembles a file system. SPE extends this model with the CmsItemProvider, enabling you to navigate and manipulate Sitecore content as if it were a file system.

    Understanding Providers

    Run Get-PSProvider to see all available providers in your SPE session:

    Editing Items

    This page covers all methods for updating Sitecore items using SPE, from simple property changes to complex field type handling and bulk operations.

    Overview

    SPE provides multiple ways to edit items, each suited to different scenarios:

    • Automated Properties - Simple, intuitive syntax for single-field updates

    Creating and Removing Items

    This page covers how to create new items and remove existing items using SPE.

    Creating Items

    Use New-Item to create new Sitecore items. The cmdlet requires a path or parent item, a name, and a template reference.

    Session Elevation

    Session Elevation provides a User Account Control (UAC) layer for SPE, similar to Windows UAC. This security feature requires users to reauthenticate or confirm before accessing powerful SPE features, even if they already have the necessary role permissions.

    Overview

    Session Elevation adds a time-based authentication layer on top of Sitecore's role-based security. This provides defense in depth by requiring users to:

    1. Have the appropriate Sitecore role (e.g., sitecore\Developer

    Delegated Access

    Delegated Access allows lower-privileged users to run specific scripts with elevated permissions by impersonating a power user. This provides controlled privilege escalation for trusted operations without granting users permanent elevated access.

    Overview

    Delegated Access solves a common problem: You want to give content authors access to specific administrative tasks without making them full administrators.

    Without Delegated Access:

    Get-Item -Path "master:\content\home"
    Name Children Language Version Id                                     TemplateName
    ---- -------- -------- ------- --                                     ------------
    Home False    en       1       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Get-Item -Path "master:\content\home"
    Get-ChildItem -Path "master:\content\home"
    Get-ChildItem -Path "master:\content\home" -Recurse
    Get-Item -Path "master:\content\home" | Select-Object -Property Name, ID, TemplateName
    Name ID                                     TemplateName
    ---- --                                     ------------
    Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Get-ChildItem -Path "master:\content\home" | Where-Object { $_.Name -like "*Sample*" }
    # Get the home item
    $homeItem = Get-Item -Path "master:\content\home"
    
    # Show its children
    $children = Get-ChildItem -Path $homeItem.ProviderPath
    
    # Display count
    Write-Host "Home has $($children.Count) children" -ForegroundColor Green
    
    # Show the list
    $children | Select-Object Name, TemplateName
    $item = Get-Item -Path "master:\content\home"
    $name = $item.Name
    $count = 5
    Get-ChildItem -Path "master:\content\home" |
        Where-Object { $_.TemplateName -eq "Sample Item" } |
        Select-Object Name, ID
    # Sitecore databases
    Get-Item -Path "master:\content\home"
    Get-Item -Path "web:\content\home"
    Get-Item -Path "core:\content"
    
    # File system
    Get-Item -Path "C:\temp"
    
    # Registry
    Get-Item -Path "HKLM:\SOFTWARE"
    if(Test-Path "master:\content\home\test") {
        Write-Host "Item exists!" -ForegroundColor Green
    } else {
        Write-Host "Item not found" -ForegroundColor Yellow
    }
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    $items | Group-Object TemplateName | Select-Object Name, Count | Sort-Object Count -Descending
    $threshold = (Get-Date).AddDays(-7)
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_."__Updated" -gt $threshold } |
        Select-Object Name, ItemPath, "__Updated"
    $items = Get-ChildItem -Path "master:\content\home"
    $items | Select-Object Name, TemplateName, "__Updated" |
        Export-Csv -Path "$($SitecoreDataFolder)\export\items.csv" -NoTypeInformation
    Get-Help Get-ItemAcl
    Get-Help Read-Variable -Detailed
    Get-Help Find-Item -Examples
    Get-Command | Where-Object { $_.ImplementingType -and $_.ImplementingType.Assembly.GetName().Name -eq "Spe" }
    database:\path\to\item
    
    Examples:
    master:\content\home
    web:\content\home\article
    core:\content
    $_          # Current item in pipeline
    $PSItem     # Same as $_
    $true       # Boolean true
    $false      # Boolean false
    $null       # Null value
    # Items
    Get-Item -Path "master:\content\home"
    Get-ChildItem -Path "master:\content" -Recurse
    New-Item -Path "master:\content\home" -Name "Item"
    Remove-Item -Path "master:\content\home\item"
    
    # Filtering
    ... | Where-Object { $_.TemplateName -eq "Article" }
    ... | Select-Object -Property Name, ID, TemplateName
    ... | Sort-Object -Property Name
    
    # Editing
    $item.Editing.BeginEdit()
    $item["Title"] = "New Value"
    $item.Editing.EndEdit()
    
    # Publishing
    Publish-Item -Item $item -PublishMode Smart -Target web
    
    # Help
    Get-Help Get-Item
    Get-Command *Item*
    $item | Get-Member
    # Safe editing
    foreach($item in $items) {
        $item.Editing.BeginEdit()
        try {
            $item["Field"] = "Value"
            $item.Editing.EndEdit()
        }
        catch {
            $item.Editing.CancelEdit()
            Write-Error $_
        }
    }
    
    # Progress reporting
    $total = $items.Count
    for($i = 0; $i -lt $total; $i++) {
        Write-Progress -Activity "Processing" `
                       -Status "$i of $total" `
                       -PercentComplete (($i / $total) * 100)
        # Process item
    }
    Get-Item -Path "master:\content\home"
    Name Children Language Version Id                                     TemplateName
    ---- -------- -------- ------- --                                     ------------
    Home True     en       2       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
    Sitecore.Data.Items.Item item = master.GetItem("/sitecore/content/home");
    Get-Item -Path "master:\content\home" -Language "da" |
        Format-Table DisplayName, Language, Id, Version, TemplateName
    DisplayName Language ID                                     Version TemplateName
    ----------- -------- --                                     ------- ------------
    Hjem        da       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Get-Item -Path "master:\content\home" -Language * |
        Format-Table DisplayName, Language, Id, Version, TemplateName
    DisplayName Language ID                                     Version TemplateName
    ----------- -------- --                                     ------- ------------
    Home        en       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        de-DE    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        pl-PL    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        en-US    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 3       Sample Item
    Home        en-GB    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Hjem        da       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Get-Item -Path "master:\content\home" -Language * -Version * |
        Format-Table DisplayName, Language, Id, Version, TemplateName
    DisplayName Language ID                                     Version TemplateName
    ----------- -------- --                                     ------- ------------
    Home        en       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        de-DE    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        pl-PL    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        en-US    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Home        en-US    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 2       Sample Item
    Home        en-US    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 3       Sample Item
    Home        en-GB    {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Hjem        da       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
    Get-Item -Path "master:\content\home" -Language "en","en-*"
    Get-ChildItem -Path "master:\content"
    Get-ChildItem -Path "master:\content\home" -Recurse
    Get-ChildItem -Path "master:\content" -Language * -Version * |
        Format-Table DisplayName, Language, Id, Version, TemplateName
    Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}" -Language *
    Name Children Language Version Id                                     TemplateName
    ---- -------- -------- ------- --                                     ------------
    Home True     en       3       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Home True     en-CA    2       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Get-Item -Path "master:" -Uri "sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1"
    Name Children Language Version Id                                     TemplateName
    ---- -------- -------- ------- --                                     ------------
    Home True     en       1       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']"
    Name          Children Language Version Id                                     TemplateName
    ----          -------- -------- ------- --                                     ------------
    Home          True     en       3       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
    Contact       False    en       1       {357D85DB-4F6C-42AF-B9A0-C232FD86F679} Sample Item
    History       False    en       1       {49D54DA4-EEB9-463B-AB19-BD8647270442} Sample Item
    Team          False    en       1       {2E4F7BBB-C71C-4CBC-BBA1-B4C05F946138} Sample Item
    BulkItem1     False    en       1       {81E660ED-0207-4C1F-BCEF-DAD9286B4E02} Sample Item
    Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']" -Language * -Version * |
        Format-Table DisplayName, Language, Id, Version, TemplateName -AutoSize
    $isoDate = [Sitecore.DateUtil]::ToIsoDate([datetime]::Today)
    Get-Item -Path "master:" -Query "/sitecore/content/home//*[@__Publish > '$($isoDate)']" |
        Show-ListView -Property ID, Name, ItemPath
    $query = "ancestor-or-self::*[@@templatename='Sample Item']"
    
    # Option 1: Use Axes directly on an item
    $SitecoreContextItem.Axes.SelectItems($query)
    
    # Option 2: Prepend the context path to the query
    Get-Item -Path "master:" -Query "$($SitecoreContextItem.Paths.Path)/$query"
    Get-Item -Path "master:\content\home" | Select-Object -Property PSSecurity
    Name ID                                     __Owner        __Security
    ---- --                                     -------        ----------
    Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} sitecore\Admin ar|sitecore\Developer|pd|+item:read|pe|+item:read|
    Get-Item -Path "master:" -ID "{04DAD0FD-DB66-4070-881F-17264CA257E1}" | Select-Object -Property PSTemplate
    Name  ID                                     BaseTemplate
    ----  --                                     ------------
    cover {04DAD0FD-DB66-4070-881F-17264CA257E1} {Image, File, Standard template, Advanced...}
    Get-Item -Path "master:\media library\Default Website\cover" | Select-Object -Property PSImage
    Name      : cover
    ID        : {04DAD0FD-DB66-4070-881F-17264CA257E1}
    Alt       :
    Width     : 1600
    Height    : 550
    Extension : jpg
    Size      : 119719
    Get-Item -Path "master:\system\Tasks\Schedules\Forms\FileStorageCleanup" |
        Select-Object -Property PSSchedule
    Name     : FileStorageCleanup
    ID       : {3D8F6795-1C4E-462D-8A81-BE27B1AEC5BD}
    Schedule : 20190101|99990101|127|24:00:00
    Last run : 11/29/2025 4:46:29 AM
    Command  : {D4ADAD17-E648-4FDC-BC4C-43F9D1513720}
    Items    :
    # Get the root node using Get-Item, then call Axes
    $mediaItemContainer = Get-Item -Path "master:\media library"
    $items = $mediaItemContainer.Axes.GetDescendants() |
        Where-Object { [int]$_.Fields["Size"].Value -gt 100000 } |
        Initialize-Item
    # Using Get-ChildItem with filtering
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" }
    
    # Using Sitecore query (more efficient for large trees)
    Get-Item -Path "master:" -Query "/sitecore/content/home//*[@@templatename='Sample Item']"
    $cutoffDate = (Get-Date).AddDays(-7)
    Get-ChildItem -Path "master:\content" -Recurse |
        Where-Object { $_.__Updated -gt $cutoffDate }
    # Using Where-Object
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.Title -like "*Welcome*" }
    
    # Using Sitecore query
    Get-Item -Path "master:" -Query "/sitecore/content/home//*[contains(@Title, 'Welcome')]"
    Get-ChildItem -Path "master:\media library" -Recurse |
        Where-Object { $_.Size -gt 1MB } |
        Select-Object Name, Size, Extension, ItemPath
    # Test file system access
    Test-Path "C:\Windows\System32" -PathType Container
    Test-Path "C:\inetpub\wwwroot" -PathType Container
    
    # Check current identity
    [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    
    # Verify HOME directory
    $HOME
    # This respects Sitecore security
    Get-Item -Path "master:\content\home"
    
    # This also respects Sitecore security
    Get-User -Identity "sitecore\testuser"
    # This bypasses Sitecore security
    New-UsingBlock (New-Object Sitecore.SecurityModel.SecurityDisabler) {
        # Code here runs with full Sitecore permissions
        Get-Item -Path "master:\content\home"
    }
    # Get current user
    $user = Get-User -Current
    Write-Host "Current User: $($user.Name)"
    
    # Check if user is in a role
    $user.IsInRole("sitecore\Developer")
    
    # List all roles for current user
    $user.Roles | ForEach-Object { $_.Name }
    
    # Test item access
    $item = Get-Item -Path "master:\content\home"
    $item.Access.CanRead()
    $item.Access.CanWrite()
    $item.Access.CanDelete()
    <powershell>
      <uploadFile>
        <allowedFileTypes>
          <pattern>image/*</pattern>
          <pattern>.xls</pattern>
          <pattern>.xlsx</pattern>
          <pattern>.csv</pattern>
        </allowedFileTypes>
        <allowedLocations>
          <path>$SitecoreMediaFolder</path>
        </allowedLocations>
      </uploadFile>
    </powershell>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <allowedFileTypes>
              <pattern>.csv</pattern>
              <pattern>.txt</pattern>
              <pattern>.xml</pattern>
              <pattern>.json</pattern>
            </allowedFileTypes>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <allowedFileTypes>
              <!-- All image types -->
              <pattern>image/*</pattern>
    
              <!-- All text types -->
              <pattern>text/*</pattern>
    
              <!-- Specific MIME type -->
              <pattern>application/json</pattern>
              <pattern>application/xml</pattern>
            </allowedFileTypes>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <allowedFileTypes>
              <!-- Excel -->
              <pattern>.xls</pattern>
              <pattern>.xlsx</pattern>
              <pattern>application/vnd.ms-excel</pattern>
              <pattern>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</pattern>
    
              <!-- Word -->
              <pattern>.doc</pattern>
              <pattern>.docx</pattern>
              <pattern>application/msword</pattern>
              <pattern>application/vnd.openxmlformats-officedocument.wordprocessingml.document</pattern>
    
              <!-- PowerPoint -->
              <pattern>.ppt</pattern>
              <pattern>.pptx</pattern>
              <pattern>application/vnd.ms-powerpoint</pattern>
              <pattern>application/vnd.openxmlformats-officedocument.presentationml.presentation</pattern>
            </allowedFileTypes>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <allowedLocations>
              <path>$SitecoreTempFolder</path>
            </allowedLocations>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <allowedLocations>
              <path>$SitecoreTempFolder</path>
              <path>$SitecoreDataFolder\uploads</path>
              <path>$SitecorePackageFolder</path>
            </allowedLocations>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    <!-- DO NOT DO THIS -->
    <allowedLocations>
      <path>C:\</path>                    <!-- Root drive -->
      <path>C:\Windows</path>             <!-- Windows directory -->
      <path>C:\inetpub\wwwroot</path>     <!-- Web root (allows direct access) -->
    </allowedLocations>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <uploadFile>
            <!-- Only allow data file types -->
            <allowedFileTypes>
              <pattern>.csv</pattern>
              <pattern>.xls</pattern>
              <pattern>.xlsx</pattern>
              <pattern>text/csv</pattern>
              <pattern>application/vnd.ms-excel</pattern>
              <pattern>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet</pattern>
            </allowedFileTypes>
    
            <!-- Only allow specific import locations -->
            <allowedLocations>
              <path>$SitecoreTempFolder</path>
              <path>$SitecoreDataFolder\uploads</path>
            </allowedLocations>
          </uploadFile>
        </powershell>
      </sitecore>
    </configuration>
    PS master:\> $newTarget = Get-Item master:\content\new-target\
    PS master:\> New-ItemClone -Path master:\content\home -Destination $newTarget -Name "New Home"

    -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"

    Language

    Specify language versions

    Get-Item, Get-ChildItem

    -Language "en-US" or -Language *

    Query

    Execute Sitecore query

    Get-Item

    -Query "/sitecore/content//*"

    Uri

    Match item by ItemUri

    Get-Item

    -Uri "sitecore://master/{GUID}?lang=en&ver=1"

    Version

    Specify item versions

    Get-Item, Get-ChildItem

    -Version 2 or -Version *

    WithParent

    Include parent in results

    Get-ChildItem

    -WithParent

    ❌ Never use - grants unlimited access

    core:\content\Applications\PowerShell\PowerShellRunner

    PowerShell Reports

    sitecore\Sitecore Client Authoring (read)

    See Reports documentation

    ❌ Denied by Windows

    Delete file outside Sitecore

    Has file permission

    Is administrator

    ✅ Success (dangerous!)

    text/plain, text/*

    Data Files

    .json, .xml

    application/json, application/xml

    Archives

    .zip

    application/zip

    C:\inetpub\wwwroot\temp

    $SitecoreMediaFolder

    Media folder

    C:\inetpub\wwwroot\upload

    Show progress and results
    Highlight unpublished changes
    Export security matrix
    Identify unused templates
    Schedule regular scans
    Validate post-deployment
    Moving and Copying Items
    Item Languages
    Item Security
    Best Practices
    Show-Result
    Control Panel
    Event Handlers
    Libraries and Scripts
    https://github.com/SitecorePowerShell/Console/issues/218

    Select-Object

    Returns objects from the pipeline with the specified properties and filters objects.

    Sort-Object

    Sorts the pipeline objects with the specified criteria; usually a property name.

    Get-Member

    Returns the methods and properties for the specified object.

    Common Pitfalls
    – all objects displayed after filtering is performed with the search criteria entered by the user in the ribbon.
  • $exportData – same as $filteredData, however in this case the objects will have additional properties to support easy display with properties processed as text.

  • $actionData – any object that was passed to Show-ListView using the -ActionData parameter. Useful when you need additional context that the Show-ListView command does not explicitly know about. It’s your custom data.

  • $formatProperty – the content of the –Property parameter when running the command.

  • $title – window title of the list view.

  • $infoTitle – info title of the list view.

  • $infoDescription – info title of the list view.

  • If the action script has no rules defined in the "Show if rules are met or not defined" field it will appear for all objects passed to Show-ListView that are of the type based on location. Rules will provide more granular control and allow for rule-based conditions that determine action visibility.

    PagingWhenNotNeeded - hides paging when list is shorter than the page specified

  • AllActions - hides all actions (right-most ribbon panel)

  • NonSpecificActions - hides actions that are not specific to this view as specified by -ViewName (right-most ribbon panel)

  • StatusBar - hides status bar.

  • Creating Beautiful Sitecore Reports Easily with PowerShell Extensions
    Images with an empty alt field
    Unused media items
    Turn Your Sitecore Powershell Reports into Applications with Action Scripts
    persistent session
    Active Commerce
    here
    Choose report index
    Filter report results
    Final results
    Show Full Info
    Actions seen for scheduled task items
    Rules configuration for actions
    Action script
    Save action script
    Open rules editor for report
    Add rules for report
    Now the List Children action is available
    Now the action is unavailable
    Updating report content
    Show progress of long running actions
    Report with all UI elements hidden

    ✓

    ✓

    ✓

    ✓

    6.4

    ✓

    ✓

    ✓

    ✓

    ✓

    -

    6.3

    ✓

    ✓

    ✓

    ✓

    -

    -

    6.2

    ✓

    ✓

    ✓

    -

    -

    -

    6.1

    ✓

    ✓

    ✓

    -

    -

    -

    6.0

    ✓

    ✓

    ✓

    -

    -

    -

    ✓

    ✓

    ✓

    ✓

    6.4

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    6.3

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    6.2

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    6.1

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    6.0

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    5.1

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    5.0

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    4.7

    ✓

    ✓

    ✓

    ✓

    ✓

    –

    4.6

    ✓

    ✓

    ✓

    –

    –

    –

    4.5

    ✓

    ✓

    ✓

    –

    –

    –

    4.4

    ✓

    ✓

    ✓

    –

    –

    –

    4.3

    ✓

    ✓

    ✓

    –

    –

    –

    4.2

    ✓

    ✓

    ✓

    –

    –

    –

    4.1

    ✓

    ✓

    ✓

    –

    –

    –

    4.0

    ✓

    ✓

    –

    –

    –

    –

    Indexing commands unsupported (#1133)

    N.X Remoting : SPE Remoting module for CI/CD - This provides a Windows PowerShell module for connecting to SPE remotely. Use in combination with the full or minimal packages.

    SPE ↓ / Sitecore→

    9.3

    10.0

    10.1

    10.2

    10.3

    10.4

    8.0

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    7.0

    ✓

    SPE ↓ / Sitecore→

    8.0

    8.1

    8.2

    9.0

    9.1

    9.2

    8.0

    ✓

    ✓

    ✓

    ✓

    ✓

    ✓

    7.0

    ✓

    SXA 1.9.0 release page
    #1129

    ✓

    ✓

    Built-In Providers

    Sitecore

    The Sitecore is the heart of SPE's Sitecore integration. It exposes Sitecore databases as PowerShell drives.

    Features:

    • Navigate Sitecore content trees using paths

    • Access items by ID, query, or URI

    • Support for language and version parameters

    • Filter by template and other properties

    Example: Explore the CmsItemProvider.

    FileSystem Provider

    The FileSystem provider allows interaction with the server's file system.

    Example: Access file system from SPE.

    PowerShell Drives

    Drives are the access points for providers. SPE creates drives for each Sitecore database.

    Sitecore Database Drives

    Example: List all available drives.

    Drive Structure

    Each Sitecore database drive has the following structure:

    The root of each drive represents /sitecore in Sitecore paths.

    The text /sitecore or \sitecore is typically omitted when using the drive names such as core:, master: and web:.

    Navigating Between Providers

    Use cd or Set-Location to switch between drives and providers.

    Example: Navigate between Sitecore databases.

    Example: Navigate between providers.

    When using the FileSystem provider, include the backslash (e.g., C:\) to access the root of the drive. Due to w3wp.exe behavior, cd C: may not behave as expected.

    Path Formats

    The Sitecore provider supports multiple path formats for flexibility.

    Provider Path Format (Recommended)

    Sitecore Path Format

    Mixed Separators

    Both forward and backward slashes work interchangeably:

    Relative Paths

    Use relative paths when you're already in a specific location:

    Provider-Specific Features

    Dynamic Parameters

    When using the Sitecore provider, cmdlets gain Sitecore-specific dynamic parameters:

    Example: Using dynamic parameters.

    Property Access

    The Sitecore provider exposes Sitecore item properties through PowerShell properties:

    Example: Access item properties.

    Common Provider Patterns

    Pattern: Work with Multiple Databases

    Pattern: Compare Items Across Databases

    Pattern: File System Operations

    Pattern: Working Directory Management

    Pattern: Cross-Provider Operations

    Provider Cmdlets

    Common cmdlets work across all providers:

    Cmdlet
    Purpose
    Example

    Get-Location / pwd

    Show current location

    Get-Location

    Set-Location / cd

    Change location

    cd master:\content

    Push-Location

    Save location

    Push-Location

    Pop-Location

    Restore location

    Pop-Location

    Testing Paths

    Example: Verify item existence.

    Example: Conditional operations based on existence.

    Advanced Provider Usage

    Using Provider Paths

    Get the full provider path for an item:

    Example: Access provider path.

    Custom Drive Creation

    While rare, you can create custom drives:

    Example: Create a drive pointing to a specific location.

    Provider Capabilities

    Check what a provider can do:

    Example: View provider capabilities.

    Troubleshooting

    Issue: Dynamic Parameters Not Appearing

    Symptom: Parameters like -Language or -ID are not available.

    Solution: Ensure you're specifying a database path:

    Issue: File System Path Behavior

    Symptom: cd C: doesn't go to C:\ root.

    Solution: Always include the backslash for FileSystem provider root:

    Issue: Path Not Found

    Symptom: "Cannot find path" error.

    Solution: Verify the item exists and the path is correct:

    Performance Considerations

    Provider vs. Direct API

    The Sitecore provider adds convenience but may have overhead for large operations:

    Caching

    Providers may cache data. If you're seeing stale data:

    See Also

    • Variables - Built-in variables for paths

    • Retrieving Items - Finding items using providers

    • Best Practices - Performance optimization

    References

    • PowerShell Providers Documentation

    • Issue #314 - FileSystem Provider Behavior

    Set-ItemProperty - PowerShell-standard cmdlet for property updates

  • BeginEdit/EndEdit - Explicit editing for multiple fields or special cases

  • BulkUpdateContext - High-performance updates for large datasets

  • Automated Properties

    The most convenient way to edit items is through SPE's automated properties. These properties automatically handle BeginEdit and EndEdit operations.

    Example: Update a field using automated properties.

    Example: Update a field with spaces in the name.

    Field names containing spaces must be wrapped in quotes (single or double).

    Example: Update system fields.

    Example: Dynamically reference fields by variable.

    Using Set-ItemProperty

    The PowerShell-standard approach using Set-ItemProperty is also supported.

    Example: Update a property using Set-ItemProperty.

    Manual Edit Context

    For multiple field updates or special scenarios, use explicit BeginEdit and EndEdit calls.

    Example: Update multiple fields in a single edit context.

    Always match BeginEdit() with EndEdit(). If an error occurs between them, the item remains locked. Consider using try/finally blocks for safety.

    Example: Safe edit context with error handling.

    Working with Field Types

    SPE provides intelligent handling for different Sitecore field types through automated properties.

    DateTime Fields

    DateTime fields automatically convert between Sitecore's string format and .NET DateTime objects.

    Example: Read and write DateTime fields.

    Image Fields

    Image fields accept item references from the Media Library.

    Example: Assign an image to an Image field.

    Link Fields (General Link)

    Link fields accept item references and automatically create the link XML.

    Example: Assign a content item to a GeneralLink field.

    Multi-Value Fields

    Multi-value fields (Multilist, Treelist, etc.) accept arrays of items.

    Example: Assign multiple items to a list field.

    Result in Content Editor:

    ItemList Assignment

    Accessing Typed Fields

    Use the ._ or .PSFields property to access strongly-typed field objects.

    Example: Access typed Image field properties.

    Example: Access typed LinkField properties.

    Output:

    Example: Find all TextField instances on an item.

    When to Use Each Method

    Use Automated Properties When:

    • Updating a single field or a few fields

    • Readability is important

    • Working with small datasets

    Example:

    Use BeginEdit/EndEdit When:

    • Updating many fields on a single item

    • Needing explicit control over save timing

    • Working with system properties (like BranchId)

    Example:

    Use BulkUpdateContext When:

    • Updating many items (hundreds or thousands)

    • Performance is critical

    • You need to bypass certain Sitecore events

    Example:

    Automated properties call BeginEdit/EndEdit on every assignment, which can impact performance when updating many fields. Use explicit BeginEdit/EndEdit for multiple updates on the same item.

    Bulk Update Patterns

    Pattern: Update Items with BulkUpdateContext

    Pattern: Update with Progress Reporting

    Pattern: Conditional Updates

    Pattern: Update from CSV Data

    Using Context Switchers

    SPE provides the New-UsingBlock function for working with Sitecore context switchers and disposable objects.

    Example: Generate relative URL with site context.

    Common Context Switchers

    Use these classes with New-UsingBlock for various scenarios:

    • Sitecore.SecurityModel.SecurityDisabler - Bypass security checks

    • Sitecore.Data.BulkUpdateContext - Optimize bulk updates

    • Sitecore.Globalization.LanguageSwitcher - Switch language context

    • Sitecore.Sites.SiteContextSwitcher - Switch site context

    • Sitecore.Data.DatabaseSwitcher - Switch database context

    • Sitecore.Security.Accounts.UserSwitcher - Switch user context

    • Sitecore.Data.Items.EditContext - Item editing context

    • Sitecore.Data.Proxies.ProxyDisabler - Disable proxies

    • Sitecore.Data.DatabaseCacheDisabler - Disable database cache

    • Sitecore.Data.Events.EventDisabler - Disable events

    Example: Read items with security disabled (use with caution).

    Example: Update items with events disabled.

    Advanced Editing Scenarios

    Update Items in Different Language

    Update Specific Version

    Copy Field Values Between Items

    Update Standard Values

    Performance Optimization

    Avoid: Repeated Automated Property Updates

    Prefer: Explicit BeginEdit/EndEdit

    Best: BulkUpdateContext for Large Datasets

    Common Pitfalls

    Pitfall: Forgetting to End Edit

    Pitfall: Modifying System Fields Without Care

    Pitfall: Assuming Item Exists

    See Also

    • Retrieving Items - Find items to edit

    • Best Practices - Performance optimization

    • Item Languages - Manage language versions

    • Appendix - Common Commands - Full cmdlet reference

    References

    • Working with Sitecore Items in PowerShell Extensions

    Basic Item Creation

    Example: Create an item by specifying template name.

    Output:

    The -ItemType parameter accepts either the template path (e.g., "Sample/Sample Item") or the template ID.

    Example: Create an item using template ID.

    Creating Items with Specific IDs

    By default, Sitecore generates a new GUID for each item. Use -ForceId to specify a custom ID.

    Example: Create an item with a predefined ID.

    Output:

    Using -ForceId with an existing ID will cause an error. Only use this when migrating content or when you need a specific ID for integration purposes.

    Creating Items as Children

    Instead of specifying the full path, you can pass a parent item using the -Parent parameter.

    Example: Create a child item under a parent.

    Output:

    Creating Items in Specific Languages

    Use the -Language parameter to create items in specific language versions.

    Example: Create an item with a specific language version.

    Output:

    When you specify a language during creation, only that language version is created. Other language versions are not automatically added.

    Starting Workflows

    Use the -StartWorkflow parameter to initiate the default workflow after item creation.

    Example: Create an item and start its workflow.

    Setting Field Values During Creation

    After creating an item, you can immediately set field values.

    Example: Create and populate an item.

    Bulk Item Creation

    Pattern: Create Items from CSV

    Pattern: Create Items with Progress Reporting

    Pattern: Create Hierarchical Structure

    Pattern: Create Items from JSON

    Removing Items

    Use Remove-Item to delete items. By default, items are moved to the Recycle Bin unless you specify -Permanently.

    Basic Item Removal

    Example: Remove an item (sends to Recycle Bin).

    Example: Remove an item permanently (bypasses Recycle Bin).

    Using -Permanently cannot be undone. Items are deleted from the database immediately. Use with extreme caution, especially in production environments.

    Removing Items via Pipeline

    Example: Remove items from pipeline.

    Example: Remove multiple items matching criteria.

    Bulk Removal Patterns

    Pattern: Remove Old Items

    Pattern: Remove Items by Template

    Pattern: Clean Up Empty Folders

    Pattern: Remove with Confirmation

    Pattern: Safe Removal with Reporting

    Dynamic Parameters

    Both New-Item and Remove-Item support dynamic parameters when working with Sitecore paths:

    Parameter
    Command
    Description
    Example

    ForceId

    New-Item

    Forces specific GUID for new item

    -ForceId "{GUID}"

    Language

    New-Item

    Creates item in specific language

    -Language "en-CA"

    Parent

    New-Item

    Specifies parent item

    Item Naming Considerations

    When creating items, Sitecore applies item naming rules:

    Valid Item Names

    • Alphanumeric characters (a-z, A-Z, 0-9)

    • Hyphens and underscores (-, _)

    • Spaces (converted to hyphens in URLs)

    Invalid Characters

    Sitecore automatically filters or replaces these characters:

    • Forward slash (/)

    • Backslash ()

    • Question mark (?)

    • Hash (#)

    • Colon (:)

    • Semicolon (;)

    • Brackets ([, ])

    Example: Create items with special character handling.

    Error Handling

    Always handle potential errors when creating or removing items.

    Pattern: Create with Error Handling

    Pattern: Bulk Create with Error Logging

    Performance Tips

    • Batch operations - Create or remove many items in a single script execution

    • Use BulkUpdateContext - When creating many items with field values

    • Use SecurityDisabler - If creating items programmatically (no user context needed)

    • Disable events - For large migrations where events aren't needed

    • Progress reporting - Always provide feedback for long-running operations

    Example: Optimized bulk creation.

    See Also

    • Retrieving Items - Find items to work with

    • Editing Items - Update item properties

    • Moving and Copying Items - Transfer items

    • Best Practices - Performance optimization

    • - Full cmdlet reference

    References

    • Working with Sitecore Items in PowerShell Extensions

    )
  • AND provide additional authentication or confirmation

  • This protects against:

    • Hijacked sessions being used to execute malicious scripts

    • Accidental execution of dangerous operations

    • Unauthorized access when a user leaves their workstation unlocked

    How It Works

    Components

    Session Elevation consists of three key components:

    1. Gates

    Entry points where scripts enter Sitecore through built-in interfaces.

    Built-in Gates:

    • Console - PowerShell Console application

    • ISE - Integrated Scripting Environment

    • ItemSave - Saving PowerShell script items in Content Editor

    Each gate can reference a token that controls its elevation requirements.

    2. Tokens

    Configuration objects that define elevation behavior and session lifetime.

    Token Attributes:

    Attribute
    Description
    Values

    name

    Unique identifier referenced by gates

    String (e.g., "Console", "ISE")

    expiration

    How long an elevated session lasts

    Timespan (hh:mm:ss)

    elevationAction

    What happens when elevation is needed

    Allow, Block, Password, Confirm

    3. Elevation Actions

    The behavior when a user attempts to access a gate without an active elevated session.

    Elevation Actions

    Allow

    Use Case: Development environments only

    Always allows access without prompting. The session runs elevated immediately.

    Never use Allow in production! This completely disables session elevation and should only be used on local development machines.

    Block

    Use Case: Completely disable a feature

    Always blocks access. The gate cannot be used at all.

    When to use:

    • Disable the Console entirely in production

    • Prevent script editing via Content Editor

    • Lock down specific gates for security compliance

    Password

    Use Case: Standard authentication (recommended for most environments)

    Prompts the user to enter their password to elevate the session.

    How it works:

    1. User attempts to access the Console/ISE

    2. If no elevated session exists or it has expired, a password prompt appears

    3. User enters their Sitecore password

    4. Upon successful authentication, session is elevated for the expiration duration

    5. During the expiration window, no further prompts appear

    Elevate Session State

    Best for:

    • Standard Sitecore authentication

    • Production environments

    • QA and staging environments

    • Environments with local user accounts

    Confirm

    Use Case: Single Sign-On (SSO) and federated authentication

    Prompts the user to confirm (click a button) to elevate the session. No password is entered.

    When to use:

    • Azure AD authentication

    • ADFS/SAML authentication

    • Any SSO provider where password re-entry isn't possible

    • Identity Server configurations

    Why Confirm instead of Password: When using federated authentication, users don't have a password stored in Sitecore. The Confirm action provides a "speed bump" to prevent accidental operations without requiring credentials that don't exist.

    Interface Behaviors

    PowerShell Console

    When accessing the Console without an elevated session:

    1. Password prompt appears (if using Password action)

    2. Enter credentials to elevate

    3. Console becomes accessible for the token expiration duration

    PowerShell ISE

    Before Elevation:

    The ISE displays a warning banner:

    Elevated session state required

    After Elevation:

    The warning changes to show the session is elevated with a "Drop" option:

    Drop elevated session state

    Users can manually drop the elevated session if they finish working early.

    Content Editor

    Before Elevation:

    When editing PowerShell Module, Script Library, or Script items, sensitive fields are hidden and a warning appears:

    Elevate session

    Click "Elevate session" to authenticate and reveal the fields.

    After Elevation:

    Fields become editable with an option to drop the session:

    Drop session

    Configuration Examples

    Development Environment

    Relaxed settings for local development:

    Production Environment (Standard Auth)

    Strict settings with password requirement:

    Production Environment (SSO/Azure AD)

    Settings for federated authentication:

    Disable Console, Enable ISE Only

    Lock down the Console while allowing ISE access:

    Advanced Configuration

    Shared Tokens

    Multiple gates can share the same token. When a user elevates through one gate, all gates sharing that token are also elevated.

    Example: Share a single token across all gates:

    Independent Tokens

    Each gate can have its own token for fine-grained control:

    Best Practices

    Expiration Times

    Environment
    Recommended Expiration
    Rationale

    Development

    30-60 minutes

    Minimize interruptions during active development

    QA/Staging

    10-15 minutes

    Balance security with testing needs

    Production

    3-5 minutes

    Maximum security, minimal exposure window

    Elevation Actions

    Environment
    Recommended Action
    Rationale

    Local Dev

    Allow

    Convenience for solo developers

    Shared Dev

    Password

    Prevent unauthorized access

    QA/Staging

    Password

    Match production security

    Production (Standard Auth)

    Password

    Security Recommendations

    ✅ Do:

    • Use short expiration times in production (5 minutes or less)

    • Require Password or Confirm in all non-dev environments

    • Test your configuration in each environment

    • Train users on the "Drop session" functionality

    • Document your elevation strategy

    ❌ Don't:

    • Use Allow in production

    • Set expiration times longer than 15 minutes in production

    • Forget to configure all three gates (Console, ISE, ItemSave)

    • Ignore the difference between Password and Confirm for SSO

    Troubleshooting

    Password prompt doesn't appear

    Possible causes:

    • Token elevationAction is set to Allow

    • Gate is not configured to use a token

    • Configuration patch is not being applied

    Solution: Verify configuration and check Sitecore logs.

    "Confirm" doesn't work with Azure AD

    Cause: Configuration shows Password instead of Confirm.

    Solution: Change to elevationAction="Confirm" for SSO environments.

    Session expires too quickly

    Cause: Expiration time is too short.

    Solution: Increase the expiration attribute (but keep it under 15 minutes in production).

    Users can't access Console even with correct role

    Cause: Session elevation is set to Block or user doesn't complete elevation.

    Solution: Check configuration and verify elevation action is appropriate.

    Next Steps

    • Configure Web Services Security for external access

    • Learn about Delegated Access for controlled privilege escalation

    • Review User and Role Management

    • Complete the Security Checklist

    Grant users broad administrative roles
  • Risk: Users have more permissions than needed

  • Violates principle of least privilege

  • With Delegated Access:

    • Users keep limited permissions

    • Specific scripts run with elevated permissions

    • All actions are logged with both user identities

    This feature was introduced in SPE with #1283

    Use Cases

    Content Author Needs Publishing Rights

    Scenario: Content authors need to publish items but shouldn't have global publish rights.

    Solution: Create a script that publishes specific items, configured to run as an administrator via delegated access.

    Reports Requiring Administrative Access

    Scenario: Managers need to run reports that query all items, but they have limited content access.

    Solution: Configure the report script to impersonate an administrator, allowing full content access for the report only.

    Bulk Operations on Protected Content

    Scenario: A user needs to perform bulk updates on items they normally can't modify.

    Solution: Create a controlled script with delegated access that performs the specific operation.

    Workflow Actions

    Scenario: Users need to trigger workflow commands that require elevated permissions.

    Solution: Workflow scripts run with delegated access to perform administrative actions.

    How It Works

    Components

    1. Delegated Access Item - Configuration item that defines the delegation

    2. Requester Role - Sitecore role containing lower-privileged users

    3. Impersonated User - Power user account whose permissions are used

    4. Delegated Scripts - Specific scripts that run with elevated permissions

    Execution Flow

    Configuration Steps

    Step 1: Create Delegated Access Item

    Navigate in Content Editor to where delegated access configurations are stored and use the insert option.

    Create delegated access item
    Delegated access template

    Step 2: Configure Requester Role

    Enter the role that contains the lower-privileged users who should have delegated access.

    Field: Requester Role

    Example Values:

    • sitecore\Elevated Unlock - Custom role for editors

    Why use roles instead of users?

    • Easier to manage

    • Follows role-based access control (RBAC) best practices

    • Changes apply to all role members automatically

    Step 3: Configure Impersonated User

    Enter the user account whose permissions will be used when scripts execute.

    Field: Impersonated User

    Example Values:

    • sitecore\Admin - Full administrative access

    • sitecore\PowerUser - Custom account with specific elevated permissions

    Security Consideration: The impersonated user should have the minimum permissions needed for the delegated scripts. Don't always use sitecore\Admin - create dedicated service accounts with specific permissions instead.

    Step 4: Select Delegated Scripts

    Choose which scripts and libraries should run with delegated access and ensure the appropriate rules are configured.

    See the Security Management script module for more examples:

    /sitecore/system/Modules/PowerShell/Script Library/SPE/Tools/Security Management

    Select delegated scripts

    What to include:

    • Scripts that should run with elevated permissions

    • Script libraries containing those scripts

    • Scripts with rules that check for delegated access

    Multilist Field: Select from available PowerShell scripts and script libraries.

    Step 5: Enable the Configuration

    Check the "Enabled" field to activate the delegated access configuration.

    Field: Enabled (checkbox)

    Important: Test thoroughly before enabling in production. Delegated access grants powerful permissions to lower-privileged users.

    Audit Logging

    All delegated access operations are logged to the SPE log file.

    Log Entry Format:

    Log Components:

    • Timestamp: When the script executed

    • Script ID: Unique identifier for the script

    • Context User: The actual logged-in user

    • Impersonated User: The elevated account used for execution

    Monitoring Delegated Access

    Regular log review should include:

    ✅ Monitor for:

    • Unexpected impersonation attempts

    • Scripts running as admin that shouldn't

    • Failed delegated access attempts

    • Unusual patterns (same user repeatedly, odd times)

    Example log analysis query:

    Best Practices

    Security Recommendations

    ✅ Do:

    • Use dedicated service accounts instead of sitecore\Admin when possible

    • Limit delegated scripts to specific, necessary operations

    • Regularly audit who has delegated access (review role membership)

    • Monitor SPE logs for delegated access usage

    • Test delegated access configurations in non-production first

    • Document why each delegated access configuration exists

    • Use confirmation dialogs in delegated scripts for destructive operations

    • Implement input validation in all delegated scripts

    • Set appropriate item-level security on delegated access items

    ❌ Don't:

    • Grant delegated access to broad roles like "Everyone"

    • Always impersonate sitecore\Admin - use least privilege

    • Allow arbitrary code execution in delegated scripts

    • Forget to enable logging in delegated scripts

    • Skip user confirmations for destructive operations

    • Create delegated access "just in case" - only when needed

    • Allow users to modify delegated access configurations

    • Delegate scripts that can modify security or create users

    Configuration Guidelines

    Aspect
    Recommendation
    Why

    Impersonated User

    Dedicated service account

    Easier to audit, limited permissions

    Requester Role

    Specific, narrow role

    Limits who can use delegation

    Script Scope

    Single, focused operation

    Reduces risk of abuse

    Logging

    Always log delegated actions

    Audit trail for compliance

    Script Security

    When writing scripts for delegated access:

    1. Validate All Input:

    2. Limit Scope:

    3. Confirm Destructive Operations:

    4. Log Actions:

    Troubleshooting

    Delegated access doesn't work

    Possible causes:

    1. Delegated access item is not enabled

    2. User is not in the requester role

    3. Script is not selected in the delegated scripts field

    4. Script library containing the script is not selected or enabled.

    Solution: Verify all configuration fields and ensure the user is in the correct role.

    Script runs with current user permissions instead of impersonated

    Cause: Script or script library not included in delegated scripts selection.

    Solution: Add both the script AND its parent library to the delegated scripts field.

    Can't see delegated access insert option

    Cause: Insert options not configured or user lacks permissions.

    Solution: Verify insert options are configured on the parent item and user has write access.

    Impersonated user doesn't have expected permissions

    Cause: Impersonated user account lacks necessary Sitecore permissions.

    Solution: Grant the impersonated user account the required Sitecore roles and item permissions.

    Security Considerations

    Risks

    Risk
    Mitigation

    Privilege Escalation Abuse

    Limit scripts to specific operations, validate input

    Over-Privileged Impersonation

    Use dedicated accounts with minimal required permissions

    Broad Role Assignment

    Only grant delegated access to specific, trusted roles

    Script Modification

    Protect script items with item-level security

    Logging Gaps

    Ensure all delegated operations are logged

    Defense in Depth

    Layer multiple security controls:

    1. Role Membership - Only trusted users in requester role

    2. Script Security - Item-level security on delegated scripts

    3. Input Validation - Scripts validate and limit operations

    4. Confirmations - User must confirm destructive actions

    5. Logging - All operations logged

    6. Auditing - Regular log review

    7. Least Privilege - Impersonated users have minimum permissions

    Related Topics

    • Security Policies - Understand SPE security model

    • Session Elevation - Additional authentication layer

    • User and Role Management - Managing Sitecore roles

    • Logging and Monitoring - Audit delegated access usage

    References

    • GitHub Issue #1283 - Feature introduction

    Item Security

    This page covers how to manage item-level security using SPE, including access control lists (ACLs), item locking, and protection.

    Overview

    Sitecore's security model controls who can access items through Access Control Lists (ACLs). SPE provides cmdlets to programmatically manage these security settings, enabling bulk security operations and automated security configuration.

    Security Concepts

    The Sitecore API utilizes a combination of parameters to represent an AccessRule. The following tables outline possible values for each parameter.

    Access Rights

    Common access rights you can grant or deny:

    Access Right
    Description

    Propagation Types

    Control how access rules propagate through the content tree:

    Propagation Type
    Description

    Security Permissions

    Permission Type
    Description

    Raw Serialized Security Field

    Text
    Description

    Example: The sitecore\Author role allowed access to read the item.

    Example: The sitecore\Author role denied access to read the item descendants.

    Example: Security rights for the parent item are not passed to the child items. Inheritance to descendants are denied for the sitecore\Author role.

    Example: The sitecore\Developer role is allowed access to read the item and descendants.

    Security Commands

    Use Get-Command to discover all security-related commands:

    Access Control Lists (ACLs)

    ACLs define which users and roles have what permissions on items. SPE provides commands to create, read, and modify ACLs programmatically.

    Reading Item Security

    Example: View current security settings on an item.

    Output:

    Example: Get detailed ACL information.

    Output:

    Creating Access Rules

    Use New-ItemAcl to create new access rules that can be applied to items.

    Example: Create an ACL granting read access to Developers.

    Example: Create an ACL denying inheritance.

    Applying Access Rules

    Use Add-ItemAcl to apply access rules to items.

    Example: Apply an ACL to an item.

    Example: Grant role-specific access.

    Output:

    Modifying Access Rules

    Use Set-ItemAcl to replace existing access rules.

    Example: Replace all access rules on an item.

    Removing Access Rules

    Use Clear-ItemAcl to remove access rules from items.

    Example: Clear all custom access rules.

    Testing Access Rights

    Use Test-ItemAcl to check if a user has specific rights on an item.

    Example: Test if a role can read an item.

    Bulk Security Operations

    Pattern: Apply Security to Content Item

    Pattern: Apply Security to Content Tree

    Pattern: Security Audit Report

    Pattern: Clone Security Settings

    Item Locking

    Prevent other users from editing items by locking them.

    Locking Items

    Example: Lock an item for editing.

    Example: Lock items in bulk.

    Unlocking Items

    Example: Unlock an item.

    Example: Unlock all items in a tree.

    Checking Lock Status

    Example: Check if an item is locked.

    Item Protection

    Protect items from accidental deletion or modification.

    Protecting Items

    Example: Protect an item from deletion.

    Example: Protect critical content.

    Unprotecting Items

    Example: Remove item protection.

    Example: Unprotect items in bulk.

    Security Best Practices

    1. Use roles over individual users - Assign permissions to roles, then add users to roles

    2. Apply security at parent level - Use propagation to apply security to entire trees

    3. Document security decisions - Keep records of why security was applied

    4. Regular security audits - Periodically review who has access to what

    See Also

    • - Managing users and roles

    • - Update item properties

    • - Performance and security patterns

    • - Full security cmdlet reference

    References

    Commands and Pipelines

    Learn PowerShell command syntax, pipelines, and essential commands.

    Learning PowerShell begins with running your first command. In this section we learn about the basic command syntax, pipelines, and some common commands you should know.

    Command Syntax

    Example: The following provides an example syntax for a fake command.

    foreach($item in $selectedData){
    # Run Sheer application on Desktop
    Show-Application `
        -Application "Content Editor" `
        -Parameter @{id ="$($item.ID)"; fo="$($item.ID)"; 
                     la="$($item.Language.Name)"; vs="$($item.Version.Number)";
                     sc_content="$($item.Database.Name)"}
    }
    Get-ChildItem master:\ | Show-ListView -ViewName ListChildren
    Get-ChildItem master:\ | Show-ListView -ViewName ListChildren -Property Name, ProviderPath
    Get-ChildItem master:\ | Show-ListView -Property Name, ProviderPath
    for($i = 0; $i -le 10; $i++){
      Write-Progress -Activity "I need to do something important for 5 seconds" `
        -Status "I'm quite on track..." `
        -PercentComplete ($i*10) -SecondsRemaining (5-$i/2) `
        -CurrentOperation "Trying to look busy.";
      Start-Sleep -m 500
    }
    
    Write-Progress -Activity "Now I'm doing something else..." `
        -Status "Should take me about 3 seconds but I'm not quite sure...";
    Start-Sleep -s 3;
    
    for($i = 0; $i -le 10; $i++){
      Write-Progress -Activity "Ok let me revisit one more thing..." `
        -Status "Just 5 more seconds" `
        -PercentComplete ($i*10) -SecondsRemaining (5-$i/2) `
        -CurrentOperation "Just making sure.";
      Start-Sleep -m 500;
    }
    
    Write-Progress -Completed -Activity "Done."
    Get-ChildItem master:\ | 
        Show-ListView `
            -Hide AllActions, AllExport, Filter, PagingWhenNotNeeded, StatusBar `
            -Property Name, DisplayName, ProviderPath, __Updated, "__Updated By"
    Get-PSProvider
    
    Name        Capabilities                           Drives
    ----        ------------                           ------
    Registry    ShouldProcess, Transactions            {HKLM, HKCU}
    Alias       ShouldProcess                          {Alias}
    Environment ShouldProcess                          {Env}
    FileSystem  Filter, ShouldProcess, Credentials     {C}
    Function    ShouldProcess                          {Function}
    Variable    ShouldProcess                          {Variable}
    Certificate ShouldProcess                          {Cert}
    WSMan       Credentials                            {WSMan}
    Sitecore    Filter, ExpandWildcards, ShouldProcess {master, web, core}
    Get-PSProvider -PSProvider Sitecore
    
    Name     Capabilities                           Drives
    ----     ------------                           ------
    Sitecore Filter, ExpandWildcards, ShouldProcess {master, web, core}
    # List files in the Data folder
    Get-ChildItem -Path "$SitecoreDataFolder\logs"
    
    # Read a log file
    Get-Content -Path "$SitecoreLogFolder\log.txt" -Tail 50
    
    # Create a temp file
    New-Item -Path "$SitecoreTempFolder\myfile.txt" -ItemType File -Value "Content"
    Get-PSDrive
    
    ame     Used (GB) Free (GB) Provider    Root                        CurrentLocation
    ----     --------- --------- --------    ----                        ---------------
    Alias                        Alias
    C             0.42    126.46 FileSystem  C:\                windows\system32\inetsrv
    Cert                         Certificate \
    core                         Sitecore    core:
    Env                          Environment
    Function                     Function
    HKCU                         Registry    HKEY_CURRENT_USER
    HKLM                         Registry    HKEY_LOCAL_MACHINE
    master                       Sitecore    master:                        content\Home
    Variable                     Variable
    web                          Sitecore    web:
    WSMan                        WSMan
    master:\
    ├── content\
    ├── layout\
    ├── media library\
    ├── system\
    └── templates\
    # Start in master
    PS master:\>
    
    # Switch to core database
    PS master:\> cd core:
    PS core:\>
    
    # Switch to web database
    PS core:\> cd web:
    PS web:\>
    
    # Return to master
    PS web:\> Set-Location -Path master:
    PS master:\>
    # Switch to file system
    PS master:\> cd C:\
    PS C:\>
    
    # Return to master database
    PS C:\> cd master:
    PS master:\>
    Get-Item -Path "master:\content\home"
    Get-Item -Path "master:/sitecore/content/home"
    Get-Item -Path "master:\content/home"
    Get-Item -Path "master:/content\home"
    PS master:\content> Get-Item -Path ".\home"
    PS master:\content> cd home
    PS master:\content\home> Get-Item -Path ".."  # Returns parent (\content)
    # Language parameter (only available with Sitecore provider)
    Get-Item -Path "master:\content\home" -Language "da"
    
    # ID parameter (only available with Sitecore provider)
    Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    
    # Query parameter (only available with Sitecore provider)
    Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']"
    $item = Get-Item -Path "master:\content\home"
    
    # Standard properties
    $item.Name
    $item.ID
    $item.TemplateName
    $item.ItemPath
    $item.Language
    $item.Version
    
    # Field values
    $item.Title
    $item.Text
    $item.__Created
    $item.__Updated
    $databases = @("master", "core", "web")
    
    foreach($db in $databases) {
        $itemCount = (Get-ChildItem -Path "$($db):\content" -Recurse).Count
        Write-Host "$db database: $itemCount items"
    }
    $masterItem = Get-Item -Path "master:\content\home"
    $webItem = Get-Item -Path "web:\content\home"
    
    if ($masterItem.__Updated -gt $webItem.__Updated) {
        Write-Host "Master is newer than Web"
    } else {
        Write-Host "Web is up to date"
    }
    # Export items to file system
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    $report = $items | Select-Object Name, Template Name, ItemPath
    
    $report | Export-Csv -Path "C:\reports\items.csv" -NoTypeInformation
    
    # Read configuration files
    $configPath = Join-Path $SitecoreDataFolder "serialization\config"
    Get-ChildItem -Path $configPath -Filter "*.yml"
    # Save current location
    Push-Location
    
    # Do work in another location
    cd "master:\templates"
    # ... perform operations ...
    
    # Return to previous location
    Pop-Location
    # Export Sitecore items to JSON files
    $items = Get-ChildItem -Path "master:\content\data" -Recurse
    
    foreach($item in $items) {
        $data = [PSCustomObject]@{
            Name = $item.Name
            ID = $item.ID
            Template = $item.TemplateName
            Title = $item.Title
            Text = $item.Text
        }
    
        $fileName = "$($item.ID).json"
        $filePath = Join-Path $SitecoreTempFolder $fileName
    
        $data | ConvertTo-Json | Set-Content -Path $filePath
        Write-Host "Exported: $fileName"
    }
    if (Test-Path "master:\content\home") {
        Write-Host "Item exists"
        $item = Get-Item -Path "master:\content\home"
    } else {
        Write-Host "Item not found"
    }
    $targetPath = "master:\content\import"
    
    if (-not (Test-Path $targetPath)) {
        New-Item -Path "master:\content" -Name "import" -ItemType "Common/Folder"
        Write-Host "Created import folder"
    }
    
    # Now safe to use
    $importFolder = Get-Item -Path $targetPath
    $item = Get-Item -Path "master:\content\home"
    $item.ProviderPath
    
    # master:\content\home
    New-PSDrive -Name "content" -PSProvider Sitecore -Root "master:\content"
    
    # Now you can use:
    Get-Item -Path "content:\home"
    (Get-PSProvider -PSProvider Sitecore).Capabilities
    
    # Filter, ExpandWildcards, ShouldProcess
    # WRONG - no database specified
    Get-Item -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    
    # CORRECT - database specified
    Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    # WRONG
    cd C:
    
    # CORRECT
    cd C:\
    # Check if path exists
    if (Test-Path "master:\content\home") {
        $item = Get-Item -Path "master:\content\home"
    } else {
        Write-Host "Path not found. Check spelling and database."
    }
    # Provider-based (convenient)
    $items = Get-ChildItem -Path "master:\content" -Recurse
    
    # Direct API (faster for large datasets)
    $db = Get-Database -Name "master"
    $root = $db.GetItem("/sitecore/content")
    $items = $root.Axes.GetDescendants() | Initialize-Item
    # Clear caches
    $db = Get-Database -Name "master"
    $db.Caches.ItemCache.Clear()
    $db.Caches.DataCache.Clear()
    $item = Get-Item -Path "master:\content\home"
    $item.Title = "New Title"
    $item = Get-Item -Path "master:\content\home"
    $item."Closing Date" = [datetime]::Today
    $item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    $item."__Display name" = "Custom Display Name"
    $item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    $fieldName = "Title"
    
    # All variations work
    Write-Host ($item.$fieldName)
    Write-Host ($item."$fieldName")
    Write-Host ($item."$($fieldName)")
    
    # To update (all variations work)
    $item.$fieldName = "New Value"
    Set-ItemProperty -Path "master:\content\home" -Name "Title" -Value "New Title"
    $item = Get-Item -Path "master:\content\home"
    $item.Editing.BeginEdit()
    $item["Title"] = "New Title"
    $item["Text"] = "New text content"
    $item.BranchId = [Guid]::Empty
    $item.Editing.EndEdit()
    $item = Get-Item -Path "master:\content\home"
    $item.Editing.BeginEdit()
    try {
        $item["Title"] = "New Title"
        $item["Text"] = "New text content"
        $item.Editing.EndEdit()
    } catch {
        $item.Editing.CancelEdit()
        throw
    }
    $item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    
    # Read returns System.DateTime
    $item.__Created
    # Monday, April 07, 2008 1:59:00 PM
    
    # Write accepts System.DateTime
    $item.__Created = [DateTime]::Now
    $item.__Created
    # Tuesday, March 17, 2020 12:00:00 PM
    $homeItem = Get-Item -Path "master:\content\home"
    $homeItem.Image = Get-Item -Path "master:\media library\logo"
    $homeItem = Get-Item -Path "master:\content\home"
    $homeItem.GeneralLink = Get-Item -Path "master:\content\home\about-us"
    $homeItem = Get-Item -Path "master:\content\home"
    $homeItem.ItemList = Get-ChildItem -Path "master:\content\home"
    $item = Get-Item -Path "master:\content\home"
    $item._.Image.Alt          # Access Alt property
    $item._.Image.Width        # Access Width property
    $item._.Image.Height       # Access Height property
    $currentItem = Get-Item -Path "master:\content\home\sample-item"
    $linkField = $currentItem.PSFields."LinkFieldName"
    
    # Access all LinkField properties
    $linkField.Anchor
    $linkField.IsInternal
    $linkField.LinkType
    $linkField.TargetID
    $linkField.TargetItem
    $linkField.Text
    $linkField.Url
    Anchor       :
    Class        :
    InternalPath : /sitecore/content/home/sample-item/
    IsInternal   : True
    IsMediaLink  : False
    LinkType     : internal
    MediaPath    :
    QueryString  :
    Target       :
    TargetID     : {263293D3-B1B3-4C2C-9A75-6BD418F376BC}
    TargetItem   : Sitecore.Data.Items.Item
    Text         : CLICK HERE
    Title        :
    Url          :
    $item = Get-Item -Path "master:\content\home"
    foreach($field in $item.Fields) {
        $typedField = $item.PSFields."$($field.Name)"
        if ($typedField -is [Sitecore.Data.Fields.TextField]) {
            Write-Host "$($field.Name): $($typedField.Value)"
        }
    }
    Get-ChildItem -Path "master:\content\home" |
        ForEach-Object {
            $_.Title = "Updated: $($_.Name)"
        }
    $item = Get-Item -Path "master:\content\home"
    $item.Editing.BeginEdit()
    $item["Title"] = "Sample Item"
    $item["Text"] = "Sample Text"
    $item["Date"] = [datetime]::Now.ToString("yyyyMMddTHHmmss")
    $item.BranchId = [Guid]::Empty
    $item.Editing.EndEdit()
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        foreach($item in Get-ChildItem -Path "master:\content\home" -Recurse) {
            $item.Editing.BeginEdit()
            $item["Title"] = "Sample Item"
            $item["Text"] = "Sample Item"
            $item.Editing.EndEdit() > $null
        }
    }
    $items = Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" }
    
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        foreach($item in $items) {
            $item.Editing.BeginEdit()
            $item["Title"] = "Updated Title"
            $item["Text"] = "Updated Text"
            $item.Editing.EndEdit() > $null
        }
    }
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    $total = $items.Count
    $current = 0
    
    foreach($item in $items) {
        $current++
        Write-Progress -Activity "Updating items" -Status "Processing $($item.Name)" `
            -PercentComplete (($current / $total) * 100)
    
        $item.Title = "Updated: $($item.Name)"
    }
    Write-Progress -Activity "Updating items" -Completed
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" -and [string]::IsNullOrEmpty($_.Title) } |
        ForEach-Object {
            $_.Title = $_.Name  # Use item name as title if title is empty
        }
    $data = Import-Csv "$($SitecoreDataFolder)\import\updates.csv"
    
    foreach($row in $data) {
        $item = Get-Item -Path "master:" -ID $row.ItemId
        if ($item) {
            $item.Title = $row.Title
            $item.Text = $row.Text
        }
    }
    $site = [Sitecore.Sites.SiteContextFactory]::GetSiteContext("usa")
    $relativeUrl = New-UsingBlock (New-Object Sitecore.Sites.SiteContextSwitcher $site) {
        $pageItem = Get-Item -Path "master:" -Id "{50BE527C-7241-4613-A7A9-20D0217B264B}"
        [Sitecore.Links.LinkManager]::GetItemUrl($pageItem)
    }
    New-UsingBlock (New-Object Sitecore.SecurityModel.SecurityDisabler) {
        $items = Get-ChildItem -Path "master:\content" -Recurse
        # Process items without security checks
    }
    New-UsingBlock (New-Object Sitecore.Data.Events.EventDisabler) {
        foreach($item in $itemsToUpdate) {
            $item.Title = "Updated"
        }
    }
    $item = Get-Item -Path "master:\content\home" -Language "en-US"
    $item.Title = "English Title"
    
    $itemDanish = Get-Item -Path "master:\content\home" -Language "da"
    $itemDanish.Title = "Danish Title"
    $item = Get-Item -Path "master:\content\home" -Language "en-US" -Version 2
    $item.Title = "Updated Version 2"
    $sourceItem = Get-Item -Path "master:\content\source"
    $targetItem = Get-Item -Path "master:\content\target"
    
    $targetItem.Editing.BeginEdit()
    foreach($field in $sourceItem.Fields) {
        if (-not $field.Name.StartsWith("__")) {  # Skip system fields
            $targetItem[$field.Name] = $sourceItem[$field.Name]
        }
    }
    $targetItem.Editing.EndEdit()
    $template = Get-Item -Path "master:\templates\Sample\Sample Item"
    $standardValues = Get-Item -Path "$($template.ProviderPath)\__Standard Values"
    $standardValues.Title = "Default Title"
    # Inefficient - calls BeginEdit/EndEdit for each field
    foreach($item in $items) {
        $item.Title = "Title"        # BeginEdit/EndEdit
        $item.Text = "Text"          # BeginEdit/EndEdit
        $item.Date = [datetime]::Now # BeginEdit/EndEdit
    }
    # Efficient - single BeginEdit/EndEdit per item
    foreach($item in $items) {
        $item.Editing.BeginEdit()
        $item["Title"] = "Title"
        $item["Text"] = "Text"
        $item["Date"] = [Sitecore.DateUtil]::ToIsoDate([datetime]::Now)
        $item.Editing.EndEdit()
    }
    # Most efficient for bulk operations
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        foreach($item in $items) {
            $item.Editing.BeginEdit()
            $item["Title"] = "Title"
            $item["Text"] = "Text"
            $item.Editing.EndEdit() > $null
        }
    }
    # BAD - item remains locked if error occurs
    $item.Editing.BeginEdit()
    $item["Title"] = "New Title"  # If this throws, EndEdit never called
    $item.Editing.EndEdit()
    # GOOD - use try/finally
    $item.Editing.BeginEdit()
    try {
        $item["Title"] = "New Title"
        $item.Editing.EndEdit()
    } catch {
        $item.Editing.CancelEdit()
        throw
    }
    # Be careful with system fields - some should not be modified
    $item."__Updated" = [DateTime]::Now      # OK - updating audit field
    $item."__Updated by" = "sitecore\admin"  # OK - updating audit field
    
    # Avoid modifying these unless you know what you're doing:
    # $item."__Revision"
    # $item."__Created"
    # $item."__Created by"
    # BAD - throws error if item doesn't exist
    $item = Get-Item -Path "master:\content\missing"
    $item.Title = "New Title"
    # GOOD - check for existence
    $item = Get-Item -Path "master:\content\maybe-exists" -ErrorAction SilentlyContinue
    if ($item) {
        $item.Title = "New Title"
    }
    $itemPath = "master:\content\home\Sample Item 3"
    New-Item -Path $itemPath -ItemType "Sample/Sample Item"
    
    Name                             Children Language Version Id                                     TemplateName
    ----                             -------- -------- ------- --                                     ------------
    Sample Item 3                    False    en       1       {29A68114-5137-4A46-A87C-3789B8D898FB} Sample Item
    $itemPath = "master:\content\home\Sample Item 4"
    $templateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    New-Item -Path $itemPath -ItemType $templateId
    $itemPath = "master:\content\home\Sample Item 5"
    $templateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    $itemId = "{9459ADDD-4471-4ED3-A041-D33E559BD321}"
    New-Item -Path $itemPath -ItemType $templateId -ForceId $itemId
    
    Name                             Children Language Version Id                                     TemplateName
    ----                             -------- -------- ------- --                                     ------------
    Sample Item 5                    False    en       1       {9459ADDD-4471-4ED3-A041-D33E559BD321} Sample Item
    $templateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    $parentItem = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
    New-Item -Parent $parentItem -Name "Sample Item 6" -ItemType $templateId
    
    Name                             Children Language Version Id                                     TemplateName
    ----                             -------- -------- ------- --                                     ------------
    Sample Item 6                    False    en       1       {E7A73426-B9BB-4056-A15C-2E835796A4DD} Sample Item
    $itemPath = "master:\content\home\Sample Item 7"
    New-Item -Path $itemPath -ItemType "Sample/Sample Item" -Language "en-CA"
    
    Name                             Children Language Version Id                                     TemplateName
    ----                             -------- -------- ------- --                                     ------------
    Sample Item 7                    False    en-CA    1       {5303A55C-5853-409D-AFC8-0DF04F4C1065} Sample Item
    $itemPath = "master:\content\home\Sample Item 8"
    New-Item -Path $itemPath -ItemType "Sample/Sample Item" -StartWorkflow
    $item = New-Item -Path "master:\content\home\demo" -Name "New Page" -ItemType "Sample/Sample Item"
    $item.Title = "Welcome to Our Site"
    $item.Text = "This is the page content"
    $item."Meta Description" = "SEO description for this page"
    # Assumes you uploaded a file to a folder on the server hosting Sitecore
    $data = Import-Csv "$($SitecoreDataFolder)\import\pages.csv"
    $parentPath = "master:\content\home"
    $templateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
    
    foreach($row in $data) {
        $item = New-Item -Parent (Get-Item $parentPath) -Name $row.Name -ItemType $templateId
        $item.Title = $row.Title
        $item.Text = $row.Text
    }
    $itemsToCreate = @("Page 1", "Page 2", "Page 3", "Page 4", "Page 5")
    $total = $itemsToCreate.Count
    $current = 0
    
    foreach($name in $itemsToCreate) {
        $current++
        Write-Progress -Activity "Creating items" -Status "Creating $name" `
            -PercentComplete (($current / $total) * 100)
    
        New-Item -Path "master:\content\home" -Name $name -ItemType "Sample/Sample Item"
    }
    Write-Progress -Activity "Creating items" -Completed
    $structure = @{
        "Products" = @("Category A", "Category B", "Category C")
        "Services" = @("Consulting", "Training", "Support")
        "About" = @("Team", "History", "Contact")
    }
    
    foreach($section in $structure.Keys) {
        $sectionItem = New-Item -Path "master:\content\home" -Name $section -ItemType "Common/Folder"
    
        foreach($page in $structure[$section]) {
            New-Item -Parent $sectionItem -Name $page -ItemType "Sample/Sample Item"
        }
    }
    $json = Get-Content "$($SitecoreDataFolder)\import\structure.json" | ConvertFrom-Json
    
    foreach($item in $json.items) {
        $newItem = New-Item -Path "master:\content\home" -Name $item.name -ItemType $item.template
        $newItem.Title = $item.title
        $newItem.Text = $item.text
    }
    Remove-Item -Path "master:\content\home\Sample Item 3"
    Remove-Item -Path "master:\content\home\Sample Item 3" -Permanently
    Get-Item -Path "master:\content\home\delete-me" | Remove-Item
    Get-ChildItem -Path "master:\content\temp" -Recurse |
        Where-Object { $_.Name -like "Test*" } |
        Remove-Item
    $cutoffDate = (Get-Date).AddYears(-2)
    Get-ChildItem -Path "master:\content\archive" -Recurse |
        Where-Object { $_.__Created -lt $cutoffDate } |
        Remove-Item -Permanently
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Temporary Item" } |
        Remove-Item
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Folder" -and -not $_.HasChildren } |
        Remove-Item
    $itemsToRemove = Get-ChildItem -Path "master:\content\home\temp" -Recurse
    
    foreach($item in $itemsToRemove) {
        $response = Show-Confirm -Title "Remove $($item.ItemPath)?"
        if ($response -eq 'yes') {
            Remove-Item -Path $item.ProviderPath
            Write-Host "Removed: $($item.ItemPath)" -ForegroundColor Green
        }
    }
    $itemsToRemove = Get-ChildItem -Path "master:\content\temp" -Recurse
    $report = @()
    
    foreach($item in $itemsToRemove) {
        try {
            Remove-Item -Path $item.ProviderPath -Permanently
            $report += [PSCustomObject]@{
                ItemPath = $item.ItemPath
                Status = "Deleted"
                Error = ""
            }
        } catch {
            $report += [PSCustomObject]@{
                ItemPath = $item.ItemPath
                Status = "Failed"
                Error = $_.Exception.Message
            }
        }
    }
    
    New-Item -Path "$($SitecoreDataFolder)\export" -ItemType Directory -Force
    $report | Export-Csv "$($SitecoreDataFolder)\export\deletion-report.csv" -NoTypeInformation
    $name = [Sitecore.Data.Items.ItemUtil]::ProposeValidItemName('Page: About Us')
    
    # These names will be automatically cleaned
    New-Item -Path "master:\content\home" -Name $name -ItemType "Sample/Sample Item"
    # Results in item name: "Page About Us" or similar
    $name = [Sitecore.Data.Items.ItemUtil]::ProposeValidItemName('Page: About Us')
    # Use Display Name for formatted names
    $item = New-Item -Path "master:\content\home" -Name "page-about-us" -ItemType "Sample/Sample Item"
    $item."__Display name" = $name
    try {
        $item = New-Item -Path "master:\content\home\new-page" -Name "New Page" -ItemType "Sample/Sample Item" -ErrorAction Stop
        Write-Host "Created: $($item.ItemPath)" -ForegroundColor Green
    } catch {
        Write-Host "Error creating item: $($_.Exception.Message)" -ForegroundColor Red -BackgroundColor White
    }
    $results = @()
    
    foreach($name in $itemNames) {
        try {
            $item = New-Item -Path "master:\content\home" -Name $name -ItemType "Sample/Sample Item" -ErrorAction Stop
            $results += [PSCustomObject]@{
                Name = $name
                Status = "Success"
                ItemId = $item.ID
                Error = ""
            }
        } catch {
            $results += [PSCustomObject]@{
                Name = $name
                Status = "Failed"
                ItemId = ""
                Error = $_.Exception.Message
            }
        }
    }
    
    New-Item -Path "$($SitecoreDataFolder)\export" -ItemType Directory -Force
    $results | Export-Csv "$($SitecoreDataFolder)\export\creation-results.csv" -NoTypeInformation
    $largeDataset = @(
        [PSCustomObject]@{"Name"="BulkItem1";"Template"="Sample/Sample Item";"Title"="BulkItem1 Title";"Text"="BulkItem1 Text";},
        [PSCustomObject]@{"Name"="BulkItem2";"Template"="Sample/Sample Item";"Title"="BulkItem2 Title";"Text"="BulkItem2 Text";},
        [PSCustomObject]@{"Name"="BulkItem3";"Template"="Sample/Sample Item";"Title"="BulkItem3 Title";"Text"="BulkItem3 Text";}
    )
    
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        New-UsingBlock (New-Object Sitecore.Data.Events.EventDisabler) {
            foreach($data in $largeDataset) {
                $item = New-Item -Path "master:\content\home" -Name $data.Name -ItemType $data.Template
                $item.Editing.BeginEdit()
                $item["Title"] = $data.Title
                $item["Text"] = $data.Text
                $item.Editing.EndEdit() > $null
            }
        }
    }
    
    # Clear all the caches may be required if working in the Content Editor
    # [Sitecore.Caching.CacheManager]::ClearAllCaches()
    <token name="Console">
      <patch:attribute name="elevationAction">Allow</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="elevationAction">Block</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="elevationAction">Password</patch:attribute>
      <patch:attribute name="expiration">00:05:00</patch:attribute>
    </token>
    <token name="Console">
      <patch:attribute name="elevationAction">Confirm</patch:attribute>
      <patch:attribute name="expiration">00:05:00</patch:attribute>
    </token>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="expiration">01:00:00</patch:attribute>
                <patch:attribute name="elevationAction">Allow</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="expiration">01:00:00</patch:attribute>
                <patch:attribute name="elevationAction">Allow</patch:attribute>
              </token>
              <token name="ItemSave">
                <patch:attribute name="expiration">01:00:00</patch:attribute>
                <patch:attribute name="elevationAction">Allow</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
              <token name="ItemSave">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Confirm</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Confirm</patch:attribute>
              </token>
              <token name="ItemSave">
                <patch:attribute name="expiration">00:05:00</patch:attribute>
                <patch:attribute name="elevationAction">Confirm</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="elevationAction">Block</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="expiration">00:10:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
              <token name="ItemSave">
                <patch:attribute name="expiration">00:10:00</patch:attribute>
                <patch:attribute name="elevationAction">Password</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
        </powershell>
      </sitecore>
    </configuration>
    <userAccountControl>
      <gates>
        <gate name="Console" token="SharedToken" />
        <gate name="ISE" token="SharedToken" />
        <gate name="ItemSave" token="SharedToken" />
      </gates>
      <tokens>
        <token name="SharedToken">
          <patch:attribute name="expiration">00:10:00</patch:attribute>
          <patch:attribute name="elevationAction">Password</patch:attribute>
        </token>
      </tokens>
    </userAccountControl>
    <userAccountControl>
      <gates>
        <gate name="Console" token="ConsoleToken" />
        <gate name="ISE" token="ISEToken" />
        <gate name="ItemSave" token="ItemSaveToken" />
      </gates>
      <tokens>
        <token name="ConsoleToken">
          <patch:attribute name="expiration">00:03:00</patch:attribute>
          <patch:attribute name="elevationAction">Password</patch:attribute>
        </token>
        <token name="ISEToken">
          <patch:attribute name="expiration">00:15:00</patch:attribute>
          <patch:attribute name="elevationAction">Password</patch:attribute>
        </token>
        <token name="ItemSaveToken">
          <patch:attribute name="expiration">00:05:00</patch:attribute>
          <patch:attribute name="elevationAction">Confirm</patch:attribute>
        </token>
      </tokens>
    </userAccountControl>
    if ([string]::IsNullOrWhiteSpace($itemPath)) {
        Show-Alert "Invalid item path"
        return
    }
    # Only allow operations under /sitecore/content/Home
    if (-not $item.Paths.FullPath.StartsWith("/sitecore/content/Home")) {
        Show-Alert "Operation not allowed for this item"
        return
    }
    $result = Show-Confirm "This will delete $($items.Count) items. Continue?"
    if ($result -ne "yes") { return }
    Write-Log "Delegated access: $([Sitecore.Context]::User.Name) published $($item.Paths.FullPath)"
    1. Content Author (limited permissions) clicks report
    2. SPE checks for delegated access configuration
    3. If found, script executes as Administrator
    4. Script can access/modify content beyond author's permissions
    5. Actions are logged showing both identities
    2304 14:02:32 INFO [Gutter] Executing script {CFE81AF6-2468-4E62-8BF2-588B7CC60F80} for Context User sitecore\contentauthor as sitecore\Admin.
    # Find all delegated access operations
    $logfiles = Get-ChildItem -Path $SitecoreLogFolder -Filter "SPE.log.*"
    foreach($logfile in $logfiles) {
        $logEntries = Get-Content -Path $logfile.FullName | Where-Object {
            $_ -match "Executing script .* for Context User .* as .*"
        }
    
        $logEntries | ForEach-Object {
            if ($_ -match "Context User (?<context>\S+) as (?<impersonated>\S+)") {
                [PSCustomObject]@{
                    ContextUser = $matches['context']
                    ImpersonatedUser = $matches['impersonated']
                    LogLine = $_
                }
            }
        }
    }

    Get-Item

    Get item at path

    Get-Item -Path "master:\content\home"

    Get-ChildItem / ls

    List children

    Get-ChildItem -Path "master:\content"

    Test-Path

    Check if path exists

    Test-Path "master:\content\home"

    -Parent $parentItem

    StartWorkflow

    New-Item

    Initiates default workflow

    -StartWorkflow

    Permanently

    Remove-Item

    Bypasses Recycle Bin

    -Permanently

    FailSilently

    Remove-Item

    Suppresses errors

    -FailSilently

    Appendix - Common Commands
    [2]
    [1]
    [2]

    Require reauthentication

    Production (SSO/Azure AD)

    Confirm

    Provide confirmation step

    field:read

    Read specific fields

    field:write

    Write specific fields

    *

    Rights may be inherited by decendants

    !

    Deny inheritance

    +

    Allow access

    -

    Deny access

    Test before production - Always test security changes in development first

  • Use SecurityDisabler cautiously - Only in controlled, administrative scripts

  • Principle of least privilege - Grant minimum permissions necessary

  • item:read

    Read item content and properties

    item:write

    Modify item fields

    item:rename

    Rename items

    item:create

    Create child items

    item:delete

    Delete items

    item:admin

    Administer item security

    Any

    Applies to item and descendants

    Descendants

    Applies only to descendants, not the item itself

    Entity

    Applies only to this specific item

    AllowAccess

    Allow access to item/descendants

    DenyAccess

    Deny access to item/descendants

    AllowInheritance

    Allow inheritance of access to item/descendants

    DenyInheritance

    Deny inheritance of access to item/descendants

    ar

    Role account type

    au

    User account type

    pd

    Propagate descendants

    pe

    Propagate entity (item)

    p*

    Propagate any

    ^

    Allow inheritance

    Security - Users and Roles
    Editing Items
    Best Practices
    Appendix - Security Commands
    Sitecore Security Guide
    Principle of Least Privilege
    Assign Security Rights Dialog
    ar|sitecore\Author|pe|+item:read|
    ar|sitecore\Author|pd|-item:read|
    ar|sitecore\Author|pd|^*|
    ar|sitecore\Developer|pd|+item:read|pe|+item:read|
    Get-Command -Noun Role*,User,ItemAcl* | Select-Object -Property Name | Sort-Object -Property Name
    Get-Item -Path "master:\content\home" | Select-Object -Property PSSecurity
    Name ID                                     __Owner        __Security
    ---- --                                     -------        ----------
    Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} sitecore\Admin ar|sitecore\Developer|pd|+item:read|pe|+item:read|
    $item = Get-Item -Path "master:\content\home"
    Get-ItemAcl -Item $item
    Account            AccessRight PermissionType PropagationType SecurityPermission
    -------            ----------- -------------- --------------- ------------------
    sitecore\Developer item:read   Access         Descendants     AllowAccess
    sitecore\Developer item:read   Access         Entity          AllowAccess
    $devRead = @{
        "Identity" = "sitecore\Developer"
        "PropagationType" = "Any"
        "SecurityPermission" = "AllowInheritance"
        "AccessRight" = "item:read"
    }
    
    $acl = New-ItemAcl @devRead
    $everyoneDeny = @{
        "Identity" = "\Everyone"
        "PropagationType" = "Any"
        "SecurityPermission" = "DenyInheritance"
        "AccessRight" = "*"
    }
    
    $acl = New-ItemAcl @everyoneDeny
    $aclForEveryone = @{
        "Identity" = "\Everyone"
        "PropagationType" = "Any"
        "SecurityPermission" = "DenyInheritance"
        "AccessRight" = "*"
    }
    
    $acl = New-ItemAcl @aclForEveryone
    
    Get-Item -Path "master:\content\home" |
        Add-ItemAcl -AccessRules $acl -PassThru
    $authorAclRead = @{
        "Identity" = "sitecore\Author"
        "PropagationType" = "Any"
        "SecurityPermission" = "AllowAccess"
        "AccessRight" = "item:read"
    }
    $authorAclInherit = @{
        "Identity" = "sitecore\Author"
        "PropagationType" = "Any"
        "SecurityPermission" = "AllowInheritance"
        "AccessRight" = "*"
    }
    
    $acl1 = New-ItemAcl @authorAclRead
    $acl2 = New-ItemAcl @authorAclInherit
    
    Get-Item -Path "master:\content\home\sample2" |
        Add-ItemAcl -AccessRules $acl1,$acl2 -PassThru
    
    Get-ItemAcl -Path "master:\content\home\sample2" | Format-Table
    Name                             Children Language Version Id                                     TemplateName
    ----                             -------- -------- ------- --                                     ------------
    Sample2                          True     en       1       {91E814D3-78C8-44FA-B78B-E0A1B2374D8F} Sample Item
    
    
    
    Account                          AccessRight          PermissionType   PropagationType  SecurityPermission
    -------                          -----------          --------------   ---------------  ------------------
    sitecore\Author                  item:read            Access           Descendants      AllowAccess
    sitecore\Author                  *                    Inheritance      Descendants      AllowInheritance
    sitecore\Author                  item:read            Access           Entity           AllowAccess
    sitecore\Author                  *                    Inheritance      Entity           AllowInheritance
    $authorAccessRights = @(
        "item:read",
        "item:write",
        "item:delete"
    )
    
    $authorAcl = @{
        "Identity" = "sitecore\Author"
        "PropagationType" = "Any"
        "SecurityPermission" = "AllowAccess"
    }
    
    $accessRules = @()
    foreach($accessRight in $authorAccessRights) {
        $accessRules += @(New-ItemAcl @authorAcl -AccessRight $accessRight)
    }
    
    Set-ItemAcl -Item (Get-Item "master:\content\home") -AccessRules $accessRules -PassThru
    Get-Item -Path "master:\content\home" | Clear-ItemAcl
    $item = Get-Item -Path "master:\content\home"
    $user = Get-Role -Identity "sitecore\Author"
    Test-ItemAcl -Item $item -User $user -AccessRight "item:read"
    $authorAccessRights = @(
        "item:read",
        "item:write",
        "item:rename",
        "item:create",
        "item:delete"
    )
    
    $authorAcl = @{
        "Identity" = "sitecore\Author"
        "PropagationType" = "Descendants"
        "SecurityPermission" = "AllowAccess"
    }
    
    $accessRules = @()
    foreach($accessRight in $authorAccessRights) {
        $accessRules += @(New-ItemAcl @authorAcl -AccessRight $accessRight)
    }
    
    Get-Item -Path "master:\content\home\sample2" |
        Add-ItemAcl -AccessRules $accessRules -PassThru
    $authorAccessRights = @(
        "item:read",
        "item:write",
        "item:rename",
        "item:create",
        "item:delete"
    )
    
    $authorAcl = @{
        "Identity" = "sitecore\Author"
        "PropagationType" = "Entity"
        "SecurityPermission" = "AllowAccess"
    }
    
    $accessRules = @()
    foreach($accessRight in $authorAccessRights) {
        $accessRules += @(New-ItemAcl @authorAcl -AccessRight $accessRight)
    }
    
    
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    
    foreach($item in $items) {
        Add-ItemAcl -Item $item -AccessRules $accessRules
        Write-Host "Applied security to: $($item.ItemPath)"
    }
    $items = Get-ChildItem -Path "master:\content\home" -Recurse
    $report = @()
    
    foreach($item in $items) {
        $acls = Get-ItemAcl -Item $item
    
        foreach($acl in $acls) {
            $report += [PSCustomObject]@{
                ItemPath = $item.ItemPath
                Identity = $acl.Account.Name
                AccessRights = $acl.AccessRight -join ", "
                PropagationType = $acl.PropagationType
                SecurityPermission = $acl.SecurityPermission
            }
        }
    }
    
    $report | Show-ListView -Property ItemPath, Identity, AccessRights, PropagationType
    # Copy security from one item to another
    $sourceItem = Get-Item -Path "master:\content\home"
    $targetItem = Get-Item -Path "master:\content\home\sample1"
    
    # A combinination of Clear, Add, and Set may be used to alter item security
    Write-Host "Cleared security for: $($sourceItem.ItemPath)"
    Clear-ItemAcl -Item $targetItem
    
    $sourceAcls = Get-ItemAcl -Item $sourceItem
    if($sourceAcls) {
        # Use Set-ItemAcl if you wish to replace the rules
        Add-ItemAcl -Item $targetItem -AccessRules $sourceAcls
        Write-Host "Cloned security to: $($targetItem.ItemPath)"
    } else {
        Write-Host "Cloned security to: $($targetItem.ItemPath)"
    }
    $item = Get-Item -Path "master:\content\home"
    Lock-Item -Item $item
    Get-ChildItem -Path "master:\content\protected" -Recurse |
        ForEach-Object {
            Lock-Item -Item $_
            Write-Host "Locked: $($_.ItemPath)"
        }
    $item = Get-Item -Path "master:\content\home"
    Unlock-Item -Item $item
    Get-ChildItem -Path "master:\content\protected" -Recurse |
        Where-Object { $_.Locking.IsLocked() } |
        ForEach-Object {
            Unlock-Item -Item $_
            Write-Host "Unlocked: $($_.ItemPath)"
        }
    $item = Get-Item -Path "master:\content\home"
    if ($item.Locking.IsLocked()) {
        Write-Host "Item is locked by: $($item.Locking.GetOwner())"
    } else {
        Write-Host "Item is not locked"
    }
    $item = Get-Item -Path "master:\content\protected"
    Protect-Item -Item $item
    $criticalItems = Get-ChildItem -Path "master:\content\critical" -Recurse
    
    foreach($item in $criticalItems) {
        Protect-Item -Item $item
        Write-Host "Protected: $($item.ItemPath)"
    }
    $item = Get-Item -Path "master:\content\home"
    Unprotect-Item -Item $item
    Get-ChildItem -Path "master:\content\temp" -Recurse |
        ForEach-Object {
            Unprotect-Item -Item $_
        }
    Verb-Noun Pattern

    PowerShell commands follow a Verb-Noun syntax. Notice that all properly named commands start with a verb such as Get, Set, or Remove and end with a noun such as Item, User, or Role.

    The noun in the command should be singular even if the command returns more than one object.

    Examples:

    • Get-Item - Retrieves an item

    • Set-Item - Modifies an item

    • Remove-Item - Deletes an item

    • New-Item - Creates an item

    • Move-Item - Moves an item

    The verbs are considered "approved" if they align with those that Microsoft recommends. See the following URL https://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx for a list of approved verbs and a brief explanation on why they were chosen. They are intended to be pretty generic so they apply for multiple contexts like the filesystem, registry, and even Sitecore!

    Parameters and Arguments

    The parameters follow the command and usually require arguments. In our example above we have a parameter called SomeParameter followed by an argument of type SomeType. The final parameter SomeSwitch is called a switch.

    Parameter types:

    • Required parameters - Must be provided

    • Optional parameters - May be omitted (shown in [square brackets])

    • Positional parameters - Can be provided without the parameter name (shown with [[double brackets]])

    • Switch parameters - Boolean flags that enable/disable behavior

    The brackets surrounding the parameter and the brackets immediately following a type have different meanings. The former has to do with optional usage whereas the latter indicates the data can be an array of objects.

    Parameter Examples

    Example: The following provides possible permutations for the fake command.

    Splatting Parameters

    Instead of passing parameters inline, you can "splat" them using a hashtable:

    When to use splatting:

    • Commands with many parameters

    • Reusable parameter sets

    • Conditional parameters

    • Improved readability

    Best Practices for Scripts

    Allow scripts to be written with the full command and parameter names:

    • ✅ Do use full command names (not aliases)

    • ✅ Do use full parameter names (not abbreviations)

    • ✅ Do specify parameter names explicitly

    • ❌ Avoid relying on positional parameters in scripts

    • ❌ Avoid abbreviating parameter names

    • ❌ Avoid using command aliases (e.g. dir, cd) in scripts

    Example:

    Aliases and abbreviations are fine for interactive use in the Console, but always use full names in saved scripts!

    Essential Commands

    Some of the most useful commands to learn can be seen in the table below. These come with vanilla PowerShell.

    Command
    Description
    Example

    Get-Item

    Returns an object at the specified path

    Get-Item -Path "master:\content\home"

    Get-ChildItem

    Returns children at the specified path. Supports recursion

    Get-ChildItem -Path "master:\content" -Recurse

    Get-Help

    Returns the help documentation for the specified command or document

    Get-Help Get-Item

    Get-Command

    Returns a list of commands

    Get-Command *Item*

    PowerShell was designed so that after learning a few concepts you can get up and running. Once you get past the basics you should be able to understand most scripts included with SPE.

    Pipelines

    PowerShell supports chaining of commands through a feature called "Pipelines" using the pipe "|". Similar to Sitecore in that you can short circuit the processing of objects using Where-Object.

    The Pipeline Concept

    The pipeline passes objects from one command to the next:

    • Command1 produces output

    • Command2 receives that output, processes it, and produces new output

    • Command3 receives Command2's output and produces final output

    Current Object Variables

    The characters $_ and $PSItem represent the current object getting processed in the pipeline.

    Simple Pipeline Examples

    Example: The following queries a Sitecore item and removes it.

    Example: The following gets children and displays specific properties.

    Complex Pipeline Example

    PowerShell also comes with a set of useful commands for filtering and sorting. Let's see those in action.

    Example: The following queries a tree of Sitecore items and returns only those that meet the criteria. The item properties are reduced and then sorted.

    A best practice in PowerShell is to reduce the number of objects passed through the pipeline as far left as possible. While the example would work if the Sort-Object command came before Where-Object, we will see a performance improvement because the sorting has fewer objects to evaluate. Some commands such as Get-ChildItem support additional options for filtering which further improve performance.

    Common Pipeline Patterns

    Filtering

    Transforming

    Grouping and Aggregating

    Sorting

    ForEach Processing

    Getting Help

    Windows PowerShell is bundled with a ton of documentation that could not possibly be included with this book; we can however show you how to access it.

    Help Commands

    Example: The following examples demonstrate ways to get help…with PowerShell.

    Finding Commands

    Discovering Properties and Methods

    PowerShell does not include the complete help documentation by default on Windows. Run the command Update-Help from an elevated prompt to update the help files to the latest available version. See help update-help for more information on the command syntax and details of its use. All of the SPE help documentation is available regardless of running Update-Help.

    Readable vs Abbreviated Commands

    Example: The following demonstrates how commands can be written clearly with little confusion on the intent, then how aliases and abbreviations can get in the way. Always think about the developer that comes after you to maintain the code.

    Why use the longhand?

    • Easier to read

    • Self-documenting

    • No ambiguity

    • Works even if aliases change

    • Better for team collaboration

    Common Aliases

    While you shouldn't use aliases in scripts, it's helpful to recognize them:

    Alias
    Command
    Description

    ?

    Where-Object

    Filter objects

    %

    ForEach-Object

    Process each object

    select

    Select-Object

    Choose properties

    sort

    Sort-Object

    Sort objects

    View all aliases:

    Next Steps

    Now that you understand commands and pipelines:

    1. Learn about providers: Providers

    2. Practice with examples: Your First Scripts

    3. Avoid common mistakes: Common Pitfalls

    4. Deepen your knowledge: Working with Items

    The pipeline is PowerShell's superpower! Master it and you'll be able to accomplish complex tasks with surprisingly little code.

    Testing

    Test in QA first

    Catch security issues before production

    Review

    Quarterly access review

    Remove unused delegations

    Interactive Dialogs

    We've provided a few commands to interact with the user through dialogs.

    Simple Dialogs

    Simple in the sense that the dialogs present the user with a short message and one or two buttons.

    Alert

    The Alert dialog is a way to notify the user of important information with an "OK" button.

    Example: The following display a modal dialog.

    No return value.

    Confirmation

    The Confirmation dialog is a way to verify with the user before proceeding.

    Example: The following displays a modal dialog with an OK or Cancel confirmation.

    Button Name
    Return Value

    User Input

    Example: The following displays an input dialog for text.

    Button Name
    Return Value

    Example: The following displays an input dialog with a error validation message.

    Advanced Dialogs

    Variable Settings

    The Read-Variable command provides a way to prompt the user for information and then generate variables with those values.

    Example: The following displays a dialog with a dropdown.

    Note: The name selectedOption will result in a variable that contains the selected option.

    Button Name
    Return Value

    Supported Parameter Values

    Key
    Type
    Description
    Example

    Editor Types

    • bool

    • check

    • date

    • date time

    Confirmation Choice

    The Confirmation Choice dialog allows for multiple combinations like that seen with a "Yes, Yes to all, No, No to all" scenario.

    Example: The following displays a modal dialog with choices.

    Note: The hashtable keys should be incremented like btn_0, btn_1, and so on. The return value is the key name.

    Button Name
    Return Value

    Upload

    The Upload dialog provides a way to upload files from a local filesystem to the media library or server filesystem.

    Example: The following displays an advanced upload dialog.

    No return value.

    Download

    The Download dialog provides a way to download files from the server to a local filesystem.

    Example: The following displays a download dialog.

    Field Editor

    The Field Editor dialog offers a convenient way to present the user with fields to edit.

    Example: The following displays a field editor dialog.

    Button Name
    Return Value

    File Browser

    The File Browser is an obvious choice when you need to upload, download, or delete files.

    Example: The following displays a file browser dialog for installation packages.

    Button Name
    Return Value

    Example: The following displays a simple file browser dialog.

    Button Name
    Return Value

    Example: The following displays a Sheer UI control without any additional parameters.

    Data List

    The "Data List" is essentially a report viewer which supports custom actions, exporting, and filtering.

    Example: The following displays a list view dialog with the child items under the Sitecore tree.

    Results

    The Results dialog resembles the Console but does not provide a prompt to the user. This is useful for when logging messages.

    Example: The following displays a dialog with the all the information written to the ScriptSession output buffer.

    Add-ItemVersion

    Creates a version of the item in a new language based on an existing language version.

    Syntax

    Detailed Description

    Creates a new version of the item in a specified language based on an existing language/version. Based on parameters you can make the command bahave differently when a version in the target language already exists and define which fields if any should be copied over from the original language.

    © 2010-2020 Adam Najmanowicz, Michael West. All rights reserved. Sitecore PowerShell Extensions

    Aliases

    The following abbreviations are aliases for this cmdlet:

    • Add-ItemLanguage

    Parameters

    -Recurse <SwitchParameter>

    Process the item and all of its children.

    Aliases

    -IfExist <ActionIfExists>

    Default value is Append. Accepts one of 3 values:

    • Append - [Default] if language version exists create a new version with values copied from the original language

    • Skip - if language version exists don't do anything

    • OverwriteLatest - if language version exists overwrite the last version with values copied from the original language

    Aliases

    -IfNoSourceVersion <ActionIfNoVersion>

    Default value is Skip. Accepts one of 2 values:

    • Skip - [Default] if the source item has no versions don't do anything

    • Add - if the source item has no versions create a version without any copied values

    Aliases

    -TargetLanguage <String[]>

    Language or a list of languages that should be created

    Aliases

    -DoNotCopyFields <SwitchParameter>

    Creates a new version in the target language but does not copy field values from the original language

    Aliases

    -IgnoredFields <String[]>

    List of fields that should not be copied over from original item. As an example, use "__Security" if you don't want the new version to have the same restrictions as the original version.

    In addition to the fields in -IgnoredFields the following fields are ignored as configured in Spe.config file in the following location: configuration/sitecore/powershell/translation/ignoredFields.

    Fields ignored out of the box include:

    • __Archive date

    • __Archive Version date

    • __Lock

    • __Owner

    Aliases

    -Language <String[]>

    Language that will be used as source language. If not specified the current user language will be used.

    Aliases

    -Item <Item>

    The item / version to be processed.

    Aliases

    -Path <String>

    Path to the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Id <String>

    Id of the item to be processed - additionally specify Language parameter to fetch different item language than the current user language.

    Aliases

    -Database <String>

    Database containing the item to be processed - can work with Language parameter to narrow the publication scope.

    Aliases

    Inputs

    The input type is the type of the objects that you can pipe to the cmdlet.

    • Sitecore.Data.Items.Item

    Outputs

    The output type is the type of the objects that the cmdlet emits.

    • Sitecore.Data.Items.Item

    Notes

    Help Author: Adam Najmanowicz, Michael West

    Examples

    EXAMPLE 1

    Translate the Home Item from English to US and Polish leaving the "Title" field blank. If a version exists don't do anything

    EXAMPLE 2

    EXAMPLE 3

    Translate the children of Home item (but only those of Template Name "Sample Item") from English to US and Polish. If a version exists create a new version for that language. Display results in a table listing item name, language and created version number.

    Related Topics

    • New-Item

    Language Basics

    Learn PowerShell syntax by comparing it to C#.

    PowerShell is built on the Microsoft .NET technology; you will find that most APIs in your libraries can be accessed from within the PowerShell runtime. In this section we will see similarities between the C# and PowerShell syntax.

    If you're not familiar with C#, don't worry! The examples below show both languages side-by-side so you can see the patterns.

    Variables

    Note: Variables in PowerShell are denoted by the $ character followed by the name. You will see this through the examples below.

    Best Practices

    This page provides guidance on writing efficient, maintainable, and performant SPE scripts for working with Sitecore items.

    Performance Optimization

    Query Method Selection

    Get-Something [[-SomeParameter] <sometype[]>] [-AnotherParameter <anothertype>] [-SomeSwitch]
    <#
        All of the parameters in the command are surrounded by square brackets
        indicating they are optional.
    #>
    Get-Something
    <#
        SomeParameter has double brackets around the parameter name and argument
        indicating the name is optional and when an argument is passed the name
        can be skipped.
    #>
    Get-Something "data"
    <#
        AnotherParameter has single brackets indicating that the parameter is
        optional. If the argument is used so must the name. The same reasoning
        can be applied to the switch.
    #>
    Get-Something "data","data2" -AnotherParameter 100 –SomeSwitch
    # Define parameters in a hashtable
    $props = @{
        "SomeParameter" = @("data","data2")
        "AnotherParameter" = 100
        "SomeSwitch" = $true
    }
    
    # Splat with @props instead of $props
    Get-Something @props
    # GOOD - explicit and clear
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Where-Object { $_.TemplateName -eq "Article" } |
        Select-Object -Property Name, ID
    
    # BAD - abbreviated and unclear
    gci "master:\content\home" -r |
        ? { $_.TemplateName -eq "Article" } |
        select Name, ID
    Command1 | Command2 | Command3
    Get-ChildItem -Path "master:\content\home" |
        Where-Object { $_.TemplateName -eq "Article" }
        # $_ represents each item as it flows through
    # The remove command accepts pipeline input
    Get-Item -Path "master:\content\home\sample item" | Remove-Item
    
    # If multiple items are passed through the pipeline each are removed individually
    $items | Remove-Item
    Get-ChildItem -Path "master:\content\home" |
        Select-Object -Property Name, TemplateName, ID
    # Use variables for parameters such as paths to make scripts easier to read
    $path = "master:\content\home\"
    
    Get-ChildItem -Path $path -Recurse |
        Where-Object { $_.Name -like "*Sample*" } |
        Select-Object -Property ID, Name, ItemPath |
        Sort-Object -Property Name
    # Filter by property value
    Get-ChildItem -Path "master:\content\home" |
        Where-Object { $_.TemplateName -eq "Sample Item" }
    # Filter by multiple conditions
    Get-ChildItem -Path "master:\content\home" |
        Where-Object {
            $_.TemplateName -eq "Sample Item" -and
            $_.PSFields."__Updated".DateTime -gt (Get-Date).AddDays(-7)
        }
    # Filter and negate
    Get-ChildItem -Path "master:\content\home" |
        Where-Object { $_.Name -notlike "*Test*" }
    # Select specific properties
    Get-ChildItem -Path "master:\content\home" |
        Select-Object Name, TemplateName, ID
    # Create calculated properties
    Get-ChildItem -Path "master:\content\home" |
        Select-Object Name,
            @{Name="Updated";Expression={$_.PSFields."__Updated".DateTime}},
            @{Name="Age";Expression={(Get-Date) - $_.PSFields."__Updated".DateTime}}
    $items = Get-ChildItem -Path "master:\content\home"
    # Expand single property to array of values
    $items | Select-Object -ExpandProperty Name
    # Returns: @("Name1", "Name2", "Name3")
    # Count items by template
    Get-ChildItem -Path "master:\content\home" -Recurse |
        Group-Object TemplateName |
        Select-Object Name, Count |
        Sort-Object Count -Descending
    # Sort by name
    $items | Sort-Object Name
    
    # Sort descending
    $items | Sort-Object Name -Descending
    
    # Sort by multiple properties
    $items | Sort-Object TemplateName, Name
    
    # Sort by custom expression
    $items | Sort-Object { $_.Name.Length }
    # Process each item
    Get-ChildItem -Path "master:\content\home" |
        ForEach-Object {
            Write-Host "Processing: $($_.Name)"
            # Do something with $_
        }
    
    # Transform each item
    Get-ChildItem -Path "master:\content\home" |
        ForEach-Object { $_.Name.ToUpper() }
    # Displays all of the about help documents
    help about_*
    
    # Displays help documentation on the topic of Splatting
    help about_Splatting
    
    # Displays help documentation on the specified command
    help Get-Member
    
    # Get detailed help with examples
    Get-Help Get-Item -Detailed
    
    # Get just the examples
    Get-Help Get-Item -Examples
    
    # Get help online (opens in browser)
    Get-Help Get-Item -Online
    # List all commands
    Get-Command
    
    # Search for commands by name
    Get-Command *Item*
    
    # Search for SPE commands
    Get-Command | Where-Object { $_.ImplementingType -and $_.ImplementingType.Assembly.GetName().Name -eq "Spe" }
    
    # Get command details
    Get-Command Get-Item | Select-Object *
    # See what properties and methods an object has
    $item = Get-Item -Path "master:\content\home"
    $item | Get-Member
    
    # Filter to just properties
    $item | Get-Member -MemberType Property
    
    # Filter to just methods
    $item | Get-Member -MemberType Method
    # Longhand - recommended for scripts
    Get-Command -Name ForEach-Object –Type cmdlet |
        Select-Object -ExpandProperty ParameterSets
    
    # Shorthand - OK for interactive use, NOT recommended for scripts
    gcm -na foreach-object -ty cmdlet | select -exp parametersets
    Get-Alias
    Add-ItemVersion [-Item] <Item> [-Recurse] [-IfExist <Append | Skip | OverwriteLatest>] [-TargetLanguage <String[]>] [-DoNotCopyFields] [-IgnoredFields <String[]>] [-Language <String[]>]
    
    Add-ItemVersion [-Path] <String> [-Recurse] [-IfExist <Append | Skip | OverwriteLatest>] [-TargetLanguage <String[]>] [-DoNotCopyFields] [-IgnoredFields <String[]>] [-Language <String[]>]
    
    Add-ItemVersion -Id <String> [-Database <String>] [-Recurse] [-IfExist <Append | Skip | OverwriteLatest>] [-TargetLanguage <String[]>] [-DoNotCopyFields] [-IgnoredFields <String[]>] [-Language <String[]>]

    ForEach-Object

    Enumerates over the objects passed through the pipeline

    $items | ForEach-Object { $_.Name }

    Where-Object

    Enumerates over the objects passed through the pipeline and filters objects

    $items | Where-Object { $_.Name -like "*Test*" }

    Select-Object

    Returns objects from the pipeline with the specified properties and filters objects

    $items | Select-Object Name, ID

    Sort-Object

    Sorts the pipeline objects with the specified criteria; usually a property name

    $items | Sort-Object Name

    Get-Member

    Returns the methods and properties for the specified object

    $item | Get-Member

    Measure-Object

    Calculates statistics on objects

    $items | Measure-Object

    Group-Object

    Groups objects by property value

    $items | Group-Object TemplateName

    group

    Group-Object

    Group by property

    measure

    Measure-Object

    Calculate statistics

    gci

    Get-ChildItem

    Get children

    gi

    Get-Item

    Get item

    cd

    Set-Location

    Change directory

    dir

    Get-ChildItem

    List directory

    ls

    Get-ChildItem

    List directory

    Tooltip (optional)

    string

    Short description or tooltip

    "Check to run quietly

    Tab (optional)

    string

    Tab title

    "Simple"

    Placeholder (optional)

    string

    Textbox placeholder

    "Search text..."

    Lines (optional)

    int

    Line count

    3

    Editor (optional)

    string

    Control type

    "date time"

    Domain (optional)

    string

    Domain name for security editor

    "sitecore"

    Options (optional)

    string OrderedDictionary Hashtable

    Data for checklist or dropdown

    @{"Monday"=1;"Tuesday"=2}

    Columns

    int string

    Number between 1 and 12 and string 'first' or 'last'

    6 first

    droplist

  • droptree

  • email

  • groupeddroplink

  • groupeddroplist

  • info

  • item

  • link

  • marquee

  • multilist

  • multilist search

  • multiple user

  • multiple user role

  • multiple role

  • multitext

  • number

  • pass

  • radio

  • rule

  • rule action

  • tree

  • treelist

  • tristate

  • time

  • OK

    yes

    Cancel

    no

    OK

    < user input >

    Cancel

    $null

    OK

    ok

    Cancel

    cancel

    < variables >

    < selection >

    Name

    string

    Variable name

    isSilent

    Value

    bool string int float datetime Item

    Default value

    $true

    Title

    string

    Header or Label

    < first button >

    btn_0

    < second button >

    btn_1

    < third button >

    btn_2

    OK

    ok

    Cancel

    cancel

    OK

    < selected file >

    Cancel

    undetermined

    OK

    < selected file >

    Cancel

    undetermined

    Show Alert
    Show Confirm
    Show Input
    Show Input
    Read Variable
    Show Confirm Choice
    Receive File
    Download
    Show Field Editor
    Show File Browser
    Show File Browser
    Show List View
    Show Result Text

    "Proceed Silently

    __Page Level Test Set Definition

  • __Reminder date

  • __Reminder recipients

  • __Reminder text

  • Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    true (ByValue, ByPropertyName)

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    1

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    true

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    Required?

    false

    Position?

    named

    Default Value

    Accept Pipeline Input?

    false

    Accept Wildcard Characters?

    false

    https://github.com/SitecorePowerShell/Console/
    Remove-ItemVersion
    https://gist.github.com/AdamNaj/b36ea095e3668c22c07e
    Show-Alert -Title "SPE is great!"
    Show-Confirm -Title "Click OK to acknowledge SPE is great!"
    Show-Input "Please provide 5 characters at most" -MaxLength 5
    $inputProps = @{
        Prompt = "Enter a new name for the item:"
        Validation = [Sitecore.Configuration.Settings]::ItemNameValidation
        ErrorMessage = "'`$Input' is not a valid name."
        MaxLength = [Sitecore.Configuration.Settings]::MaxItemNameLength
    }
    
    Show-Input @inputProps
    $options = @{
        "A"="a"
        "B"="b"
    }
    
    $props = @{
        Parameters = @(
            @{Name="selectedOption"; Title="Choose an option"; Options=$options; Tooltip="Choose one."}
        )
        Title = "Option selector"
        Description = "Choose the right option."
        Width = 300
        Height = 300
        ShowHints = $true
    }
    
    Read-Variable @props
    Show-ModalDialog -Control "ConfirmChoice" -Parameters @{btn_0="Yes - returns btn_0"; btn_1="No - returns btn_1"; btn_2="returns btn_2"; te="Have you downloaded SPE?"; cp="Important Questions"} -Height 120 -Width 650
    Receive-File (Get-Item "master:\media library\Files") -AdvancedDialog
    Get-Item -Path "master:\media library\Files\readme" | Send-File
    Get-Item "master:\content\home" | Show-FieldEditor -Name "*" -PreserveSections
    Show-ModalDialog -HandleParameters @{
        "h"="Create an Anti-Package";
        "t" = "Select a package that needs an anti-package";
        "ic"="People/16x16/box.png";
        "ok"="Pick";
        "ask"="";
        "path"= "packPath:$SitecorePackageFolder";
        "mask"="*.zip";
    } -Control "Installer.Browse"
    Show-ModalDialog -HandleParameters @{
        "h"="FileBrowser";
    } -Control "FileBrowser" -Width 500
    Show-ModalDialog -Control "SetIcon"
    Get-Item -Path master:\* | Show-ListView -Property Name, DisplayName, ProviderPath, TemplateName, Language
    for($i = 0; $i -lt 10; $i++) {
        Write-Verbose "Index = $($i)" -Verbose
    }
    
    Show-Result -Text
    PS master:\> Add-ItemVersion -Path "master:\content\home" -Language "en" -TargetLanguage "pl-pl", "en-us" -IfExist Skip -IgnoredFields "Title"
    Add a Japanese version to /sitecore/content/home item in the master database based on itself
    PS master:\> Add-ItemVersion -Path "master:\content\home" -Language ja-JP -IfExist Append
    Get-ChildItem "master:\content\home" -Language "en" -Recurse | `
        Where-Object { $_.TemplateName -eq "Sample Item" } | `
        Add-ItemVersion -TargetLanguage "pl-pl" -IfExist Append | `
        Format-Table Name, Language, Version -auto
    C# to PowerShell Translation

    Use the tables below to aid in translating from C# to PowerShell. Some of the examples below are not "exact" translations, but should give you a good idea on what it would look like.

    Operators are the same:

    • Addition: +

    • Subtraction: -

    • Multiplication: *

    • Division: /

    • Modulus: %

    Arrays

    Working with Dynamic and Fixed dimensional arrays.

    Using += with arrays in PowerShell is slow because it creates a new array each time. See Performance Considerations for better alternatives.

    Hashtables

    Working with hashtables (dictionaries).

    Ordered Dictionaries

    Working with dictionaries that preserve insertion order.

    Switch statements:

    Important: PowerShell uses different comparison operators than C#!

    Comparison Operators

    C#
    PowerShell
    Description

    ==

    -eq

    Equal to

    !=

    -ne

    Not equal to

    <

    -lt

    Less than

    >

    -gt

    Greater than

    Logical Operators

    C#
    PowerShell
    Description

    &&

    -and

    Logical AND

    ||

    -or

    Logical OR

    !

    -not or !

    Logical NOT

    Pattern Matching

    Most comparisons in PowerShell are case-insensitive by default. Use operators starting with c (like -ceq) for case-sensitive comparisons.

    Both work the same:

    • !$value - Shorter syntax

    • -not $value - More explicit

    String Interpolation

    Use $() for expressions: "Result: $(2 + 2)" → "Result: 4"

    Escape Characters

    Escape double quotes in string. Alternatively you can use a single quote.

    Escape character: PowerShell uses backtick ` instead of backslash \

    Multi-line Strings

    String Operations

    For Loop

    ForEach Loop

    While Loop

    Accessing .NET Types

    Common .NET Types

    Creating .NET Objects

    Comments

    Functions and Methods

    Calling Methods

    Defining Functions

    Error Handling

    Performance Considerations

    Better Collections

    Creating arrays with += is slow. Use these instead:

    Suppressing Output

    Different methods have different performance:

    Key Differences Summary

    Concept
    C#
    PowerShell

    Variables

    var name

    $name

    Equals

    ==

    -eq

    Not equals

    !=

    -ne

    And

    &&

    -and

    Next Steps

    Now that you understand the syntax:

    1. Learn commands: Commands and Pipelines

    2. Understand providers: Providers

    3. Practice with examples: Your First Scripts

    4. Avoid mistakes: Common Pitfalls

    As you can see, the language syntax is not all that different between C# and PowerShell. Within a few minutes you might even be able to translate code from your library classes into SPE scripts!

    Choose the right query method based on your use case:
    Method
    Best For
    Performance
    Security
    Full Item Data

    Get-Item by path

    Single known item

    ⭐⭐⭐

    ✓

    ✓

    Get-ChildItem

    Small trees (<500 items)

    ⭐⭐

    ✓

    ✓

    Example: Performance comparison for finding items by template.

    Bulk Update Performance

    When updating many items, use appropriate context objects to improve performance:

    Example: Performance tiers for bulk updates.

    Memory Management

    For large datasets, process items in batches to avoid memory issues. Use Find-Item with pagination to retrieve items server-side rather than loading everything into memory:

    Example: Efficient batch processing with search index pagination.

    Caching Considerations

    //TODO

    Security Best Practices

    //TODO

    Validating Access

    //TODO

    Code Organization

    Function Structure

    Create reusable functions with proper error handling:

    Example: Well-structured function.

    Error Handling

    Implement comprehensive error handling:

    Example: Robust error handling pattern.

    Progress Reporting

    Always provide feedback for long-running operations:

    Example: Comprehensive progress reporting.

    Note: Use the Bulk Data Generator found under the Toolbox to create test items.

    Language and Version Handling

    Working with Multiple Languages

    Be explicit about language handling:

    Example: Multi-language update pattern.

    Version Management

    Handle versions carefully to avoid unintended consequences:

    Example: Safe version operations.

    Field Type Handling

    Type-Safe Field Access

    Use typed field access when working with complex fields:

    Example: Safe field type handling.

    Date Handling

    Always use ISO format for date fields:

    Example: Proper date handling.

    Testing and Validation

    Dry Run Support

    Implement dry-run mode for destructive operations:

    Example: Dry-run pattern.

    Validation Before Operations

    Validate data before making changes:

    //TODO

    Logging and Auditing

    Comprehensive Logging

    Log operations for audit trails:

    Example: Logging pattern.

    Common Anti-Patterns

    ❌ Anti-Pattern: Not Checking Item Existence

    ❌ Anti-Pattern: Inefficient Queries

    //TODO

    ❌ Anti-Pattern: Swallowing Errors

    Performance Benchmarking

    Use Measure-Command to identify bottlenecks:

    Example: Performance comparison.

    See Also

    • Retrieving Items - Query optimization techniques

    • Editing Items - Update performance patterns

    • Item Security - Security best practices

    • Appendix - Common Commands - Cmdlet reference

    References

    • Sitecore Query Performance

    • PowerShell Best Practices

    Logging and Monitoring

    Comprehensive logging and monitoring are essential for detecting security incidents, troubleshooting issues, and maintaining compliance. This guide covers how to configure and use SPE logging for security purposes.

    Overview

    SPE provides logging capabilities that record:

    • Script execution

    • User authentication and authorization

    • Session elevation events

    • Delegated access usage

    • Web service calls

    • Errors and exceptions

    Security Best Practice: Enable comprehensive logging in all non-development environments to create an audit trail.

    SPE Log Files

    Default Log Location

    SPE logs are written to:

    Typically resolves to:

    Log Levels

    SPE supports standard log4net levels:

    Level
    Description
    Use Case

    Configuring Log Level

    Edit your log4net configuration (typically in App_Config\Sitecore.config or a patch file):

    Recommended Settings:

    Environment
    Log Level
    Rationale

    What Gets Logged

    Script Execution

    Format:

    Session Elevation

    Format:

    Delegated Access

    Format:

    Includes:

    • Script ID

    • Context user (actual logged-in user)

    • Impersonated user (elevated account)

    This is critical for audit trails showing privilege escalation.

    Web Service Calls

    Format:

    Logged Events:

    • Remoting connections

    • File uploads/downloads

    • RESTful API calls

    • Authorization failures

    Authentication Events

    Format:

    Logged Events:

    • Successful authentication

    • Failed authentication

    • Authorization denials

    Errors and Exceptions

    Format:

    Includes:

    • Exception details

    • Stack traces

    • User context

    • Operation being performed

    Monitoring Strategies

    Real-Time Monitoring

    Using PowerShell to Tail Logs

    Monitor for Specific Events

    Log Analysis

    Find Failed Authentication Attempts

    Track Delegated Access Usage

    Find Unauthorized Access Attempts

    Analyze Web Service Usage

    Scheduled Log Review

    Create a scheduled task to analyze logs daily:

    IIS Log Integration

    IIS Logs for Web Services

    IIS logs provide additional context for web service access:

    Location:

    Useful IIS Log Fields

    Field
    Description
    Security Value

    Analyzing IIS Logs for SPE

    Find SPE web service requests:

    Find failed authentication (401) to SPE services:

    Alerting

    Simple Email Alerts

    Create alerts for critical security events:

    Run this script via Task Scheduler every 5 minutes.

    Integration with SIEM

    For enterprise environments, integrate SPE logs with your Security Information and Event Management (SIEM) system.

    Common SIEM Solutions:

    • Splunk

    • ELK Stack (Elasticsearch, Logstash, Kibana)

    • Azure Sentinel

    • ArcSight

    Log Retention

    Regulatory Requirements

    Different compliance frameworks have different retention requirements:

    Framework
    Typical Requirement

    Note: The requirements may have changed since the publishing of this document. Please confirm with your organization and legal team as to the requirements you must meet.

    Configuration

    The configuration of log retention will be dependent on your solution.

    Archival Strategy

    The archival strategy implementation will be dependent on your solution.

    Security Metrics

    Key Performance Indicators (KPIs)

    Track these metrics for security monitoring:

    Metric
    Description
    Threshold

    Best Practices

    Security Recommendations

    ✅ Do:

    • Enable INFO level logging in production

    • Monitor logs daily for suspicious activity

    • Set up alerts for critical security events

    • Retain logs per compliance requirements

    ❌ Don't:

    • Disable logging in production

    • Ignore failed authentication attempts

    • Delete logs prematurely

    • Log sensitive data (passwords, tokens)

    Monitoring Frequency

    Activity
    Frequency
    Method

    Troubleshooting

    Logs not being written

    Possible causes:

    1. log4net configuration incorrect

    2. File permissions prevent writing

    3. Disk space full

    4. SPE logger disabled

    Solution: Check log4net config, verify permissions, ensure disk space.

    Too much log data

    Cause: DEBUG level in production or high activity.

    Solution: Change to INFO or WARN level, implement log rotation.

    Can't find specific events

    Cause: Log rotation moved old logs or logs were deleted.

    Solution: Check archived logs, adjust retention period.

    Related Topics

    • - Includes logging validation

    • - Monitoring delegated access usage

    • - Monitoring web service security

    • - IIS log integration

    References

      • Your Sitecore implementation may require vendor-specific documentation as log4net is bundled/compiled in the Sitecore libraries.

    Security

    Sitecore PowerShell Extensions (SPE) is a powerful administrative tool that requires proper security configuration. This guide provides comprehensive security documentation to help you secure your SPE installation.

    Critical Warning: SPE is a powerful tool that should NEVER be installed on Content Delivery (CD) instances or internet-facing servers. Always implement security best practices and follow the principle of least privilege.

    IIS Security

    Adding security at the IIS (Internet Information Services) level provides an additional layer of protection for SPE web services. This creates defense in depth by blocking unauthorized access before requests even reach the Sitecore application.

    Overview

    IIS-level security complements Sitecore-level security by:

    • Denying anonymous access to SPE services

    Web Services

    SPE provides several web services for external access and automation. By default, most services are disabled to minimize the attack surface. This guide explains each service and how to secure them when enabled.

    Overview

    Web services enable powerful capabilities like:

    • Remote script execution (SPE Remoting)

    // C# - declare and assign
    var name = "Michael";
    string title = "Developer";
    int count = 5;
    # PowerShell - assign (type is inferred)
    $name = "Michael"
    $title = "Developer"
    $count = 5
    
    # Optionally specify type
    [string]$title = "Developer"
    [int]$count = 5
    // Perform simple math in C#
    var total = 1 + 1;
    total += 2;
    var result = total * 3 / 2;
    # Perform simple math in PowerShell
    $total = 1 + 1
    $total += 2
    $result = $total * 3 / 2
    /*
      Create a new dynamic list of strings in C#
    */
    var names = new List<string>();
    names.Add("Michael");
    names.Add("Adam");
    <#
      Create a new fixed list of strings in PowerShell
    #>
    [string[]]$names = @()
    $names += "Michael"
    $names += "Adam"
    // Create a hashtable of data in C#
    var table = new Hashtable();
    table["Name"] = "Michael";
    table["Age"] = 33;
    # Create a new hashtable of data in PowerShell
    $table = @{}
    $table["Name"] = "Michael"
    $table["Age"] = 33
    
    # Or create inline
    $table = @{
        Name = "Michael"
        Age = 33
    }
    // Ordered Dictionary in C#
    var od = new OrderedDictionary();
    od.Add("z","Last Letter");
    od.Add("a","First Letter");
    # Ordered Dictionary in PowerShell
    $od = [ordered]@{}
    $od.Add("z","Last Letter")
    $od.Add("a","First Letter")
    // Check if the string is null or empty using a static method in C#
    if(string.IsNullOrEmpty(name)) {
      ...
    }
    else {
      ...
    }
    # Check if the string is null or empty using a static method in PowerShell
    if([string]::IsNullOrEmpty($name)) {
      ...
    } else {
      ...
    }
    // C# switch
    switch(value) {
        case "A":
            DoSomething();
            break;
        case "B":
            DoSomethingElse();
            break;
        default:
            DoDefault();
            break;
    }
    # PowerShell switch
    switch($value) {
        "A" {
            Do-Something
        }
        "B" {
            Do-SomethingElse
        }
        default {
            Do-Default
        }
    }
    // Compare values in C#
    name == "Michael"
    total <= 3
    names.Count() > 2 && name[0] != "Adam"
    # Compare values in PowerShell
    $name -eq "Michael"
    $total -le 3
    $names.Count -gt 2 -and $name[0] -ne "Adam"
    # Case-insensitive (default)
    $name -eq "Michael"      # Matches "michael", "MICHAEL", "Michael"
    
    # Case-sensitive
    $name -ceq "Michael"     # Only matches exact case
    
    # Wildcard matching
    $name -like "*Smith"     # Matches "John Smith", "Jane Smith"
    $name -notlike "*Test*"  # Excludes items with "Test"
    
    # Regular expressions
    $name -match "^\d{3}"    # Matches names starting with 3 digits
    // Negate value in C#
    var isTrue = !false;
    var isNotEmpty = !string.IsNullOrEmpty(value);
    # Negate value in PowerShell
    $isTrue = !$false
    $isTrue = -not $false
    
    $isNotEmpty = ![string]::IsNullOrEmpty($value)
    $isNotEmpty = -not [string]::IsNullOrEmpty($value)
    // String interpolation in C#
    var message = $"Hello, {name}";
    var result = $"Total: {count * 2}";
    # String interpolation in PowerShell
    $message = "Hello, $name"
    $result = "Total: $($count * 2)"
    // Escape characters in C#
    string message = "They said, \"SPE is the greatest!\".";
    message = 'I said, "Thanks!"';
    message = "We celebrated together, 'Go SPE!'";
    # Escape characters in PowerShell
    $message = "They said, `"SPE is the greatest!`"."
    $message = 'I said, "Thanks!".'
    $message = "We celebrated together, 'Go SPE!'."
    // C# multi-line
    var text = @"
    Line 1
    Line 2
    Line 3
    ";
    # PowerShell here-string
    $text = @"
    Line 1
    Line 2
    Line 3
    "@
    # Concatenation
    $fullName = $firstName + " " + $lastName
    $fullName = "$firstName $lastName"
    
    # Length
    $length = $name.Length
    
    # Substring
    $sub = $name.Substring(0, 5)
    
    # Replace
    $updated = $name.Replace("old", "new")
    
    # Split
    $parts = $name.Split(" ")
    
    # Join
    $joined = $parts -join ", "
    
    # To upper/lower
    $upper = $name.ToUpper()
    $lower = $name.ToLower()
    // C# for loop
    for(int i = 0; i < 10; i++) {
        Console.WriteLine(i);
    }
    # PowerShell for loop
    for($i = 0; $i -lt 10; $i++) {
        Write-Host $i
    }
    // C# foreach
    foreach(var item in items) {
        ProcessItem(item);
    }
    # PowerShell foreach
    foreach($item in $items) {
        Process-Item $item
    }
    // C# while
    while(count < 100) {
        count++;
    }
    # PowerShell while
    while($count -lt 100) {
        $count++
    }
    // Access static property in C#
    var today = DateTime.Today;
    var guid = Guid.NewGuid();
    # Access static property in PowerShell
    $today = [datetime]::Today
    $guid = [guid]::NewGuid()
    # DateTime
    $now = [datetime]::Now
    $today = [datetime]::Today
    $parsed = [datetime]::Parse("2024-01-15")
    $custom = Get-Date -Year 2024 -Month 1 -Day 15
    
    # String
    $empty = [string]::Empty
    $isNullOrEmpty = [string]::IsNullOrEmpty($value)
    $joined = [string]::Join(", ", $array)
    
    # Math
    $max = [math]::Max(5, 10)
    $min = [math]::Min(5, 10)
    $rounded = [math]::Round(3.7)
    
    # Guid
    $newGuid = [guid]::NewGuid()
    $parsed = [guid]::Parse("{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}")
    
    # Path
    $combined = [System.IO.Path]::Combine("C:\temp", "file.txt")
    $extension = [System.IO.Path]::GetExtension("file.txt")
    // C# - create object
    var list = new List<string>();
    var dict = new Dictionary<string, int>();
    # PowerShell - create object
    $list = New-Object System.Collections.Generic.List[string]
    $dict = New-Object 'System.Collections.Generic.Dictionary[string,int]'
    
    # Alternative syntax
    $list = [System.Collections.Generic.List[string]]::new()
    // C# - Single line comment
    
    /*
      C# - Multi-line comment
      More text here
    */
    # PowerShell - Single line comment
    
    <#
      PowerShell - Multi-line comment
      More text here
    #>
    // C# - call method
    string upper = name.ToUpper();
    items.Add("new item");
    # PowerShell - call method
    $upper = $name.ToUpper()
    $items.Add("new item")
    
    # Note: Some methods return values you may want to suppress
    $items.Add("new item") > $null
    // C# - define function
    public string GetFullName(string first, string last) {
        return first + " " + last;
    }
    
    var name = GetFullName("John", "Smith");
    # PowerShell - define function
    function Get-FullName {
        param(
            [string]$First,
            [string]$Last
        )
    
        return "$First $Last"
    }
    
    $name = Get-FullName -First "John" -Last "Smith"
    // C# - try/catch
    try {
        DoSomething();
    }
    catch(Exception ex) {
        Console.WriteLine(ex.Message);
    }
    finally {
        Cleanup();
    }
    # PowerShell - try/catch
    try {
        Do-Something
    }
    catch {
        Write-Host $_.Exception.Message
    }
    finally {
        Clean-up
    }
    # SLOW - creates new array each time
    $names = @()
    $names += "Michael"
    $names += "Adam"
    
    # FAST - use ArrayList
    $names = [System.Collections.ArrayList]@()
    $names.Add("Michael") > $null
    $names.Add("Adam") > $null
    
    # FAST - use List<T>
    $names = [System.Collections.Generic.List[string]]@()
    $names.Add("Michael") > $null
    $names.Add("Adam") > $null
    
    # FAST - use HashSet for distinct values
    $names = New-Object System.Collections.Generic.HashSet[string]
    $names.Add("Michael") > $null
    # SLOW - Out-Null is a cmdlet
    $list.Add($item) | Out-Null
    
    # FAST - redirect to $null
    $list.Add($item) > $null
    # SLOW - Retrieves all items then filters
    $items = Get-ChildItem -Path "master:\content" -Recurse |
        Where-Object { $_.TemplateName -eq "Sample Item" }
    
    # FASTER - Uses Sitecore query to filter server-side
    $items = Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']"
    
    # FASTEST - Uses the search index
    # See Find-Item
    # SLOWEST - Automated properties call BeginEdit/EndEdit each time
    foreach($item in $items) {
        $item.Title = "Title"        # BeginEdit/EndEdit
        $item.Text = "Text"          # BeginEdit/EndEdit
        $item.Date = [datetime]::Now # BeginEdit/EndEdit
    }
    
    # BETTER - Manual BeginEdit/EndEdit once per item
    foreach($item in $items) {
        $item.Editing.BeginEdit()
        $item["Title"] = "Title"
        $item["Text"] = "Text"
        $item["Date"] = [Sitecore.DateUtil]::ToIsoDate([datetime]::Now)
        $item.Editing.EndEdit() > $null
    }
    
    # BEST - BulkUpdateContext for large datasets
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        foreach($item in $items) {
            $item.Editing.BeginEdit()
            $item["Title"] = "Title"
            $item["Text"] = "Text"
            $item.Editing.EndEdit() > $null
        }
    }
    
    # OPTIMAL - Combine with EventDisabler when events aren't needed
    New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
        New-UsingBlock (New-Object Sitecore.Data.Events.EventDisabler) {
            foreach($item in $items) {
                $item.Editing.BeginEdit()
                $item["Title"] = "Title"
                $item["Text"] = "Text"
                $item.Editing.EndEdit() > $null
            }
        }
    }
    $batchSize = 250
    $offset = 0
    $totalProcessed = 0
    
    # Define search criteria
    $criteria = @(
        @{Filter = "Equals"; Field = "_templatename"; Value = "Sample Item"},
        @{Filter = "DescendantOf"; Value = (Get-Item "master:\content").ID}
    )
    
    $props = @{
        Index = "sitecore_master_index"
        Criteria = $criteria
    }
    
    do {
        # Query batch from search index (server-side pagination)
        $searchItems = @(Find-Item @props -Skip $offset -First $batchSize)
    
        if ($searchItems.Count -eq 0) { break }
    
        # Process batch with bulk update context
        New-UsingBlock (New-Object Sitecore.Data.BulkUpdateContext) {
            foreach($searchItem in $searchItems) {
                # Convert search result to full Sitecore item
                # Pipe items to Initialize-Item or call Get-Item with the ID
    
                # The prefix `$script is required because of the ScriptBlock closure created by New-UsingBlock
                $script:totalProcessed++
            }
        }
    
        $offset += $searchItems.Count
        Write-Host "Processed: $totalProcessed items"
    } while ($searchItems.Count -eq $batchSize)
    
    Write-Host "Completed processing $totalProcessed items"
    
    # Processed: 1 items
    # Completed processing 1 items
    function Update-ItemTitle {
        [CmdletBinding(SupportsShouldProcess)]
        param(
            [Parameter(Mandatory, ValueFromPipeline)]
            [Sitecore.Data.Items.Item]$Item,
    
            [Parameter(Mandatory)]
            [string]$Title
        )
    
        process {
            try {
                # Validation
                if (-not $Item) {
                    Write-Error "Item is null"
                    return
                }
    
                # WhatIf support
                if ($PSCmdlet.ShouldProcess($Item.ItemPath, "Update title to '$Title'")) {
                    $Item.Editing.BeginEdit()
                    try {
                        $Item["Title"] = $Title
                        $Item.Editing.EndEdit()
                        Write-Verbose "Updated: $($Item.ItemPath)"
                    } catch {
                        $Item.Editing.CancelEdit()
                        throw
                    }
                }
            } catch {
                Write-Error "Failed to update $($Item.ItemPath): $($_.Exception.Message)"
            }
        }
    }
    
    # Usage
    Get-ChildItem -Path "master:\content\" |
        Update-ItemTitle -Title "New Title" -Verbose -WhatIf
    $itemPaths = @(
        "master:/content/Home"
    )
    
    $results = @()
    $errors = @()
    
    foreach($itemPath in $itemPaths) {
        try {
            $item = Get-Item -Path $itemPath -ErrorAction Stop
    
            $item.Editing.BeginEdit()
            try {
                $item["Title"] = "Updated"
                $item.Editing.EndEdit()
    
                $results += [PSCustomObject]@{
                    ItemPath = $item.ItemPath
                    Status = "Success"
                    Error = ""
                }
            } catch {
                $item.Editing.CancelEdit()
                throw
            }
        } catch {
            $errors += [PSCustomObject]@{
                ItemPath = $itemPath
                Status = "Failed"
                Error = $_.Exception.Message
            }
        }
    }
    
    # Report results
    $results | Show-ListView
    function Update-ItemsWithProgress {
        param(
            [Sitecore.Data.Items.Item[]]$Items,
            [scriptblock]$UpdateAction
        )
    
        $total = $Items.Count
        $current = 0
        $sw = [System.Diagnostics.Stopwatch]::StartNew()
    
        foreach($item in $Items) {
            $current++
    
            # Calculate ETA
            $percentComplete = ($current / $total) * 100
            $elapsedSeconds = $sw.Elapsed.TotalSeconds
            $estimatedTotalSeconds = ($elapsedSeconds / $current) * $total
            $remainingSeconds = $estimatedTotalSeconds - $elapsedSeconds
    
            Write-Progress -Activity "Processing items" `
                           -Status "Processing $($item.Name) ($current of $total)" `
                           -PercentComplete $percentComplete `
                           -SecondsRemaining $remainingSeconds
    
            & $UpdateAction $item
        }
    
        $sw.Stop()
        Write-Progress -Activity "Processing items" -Completed
        Write-Host "Completed $total items in $($sw.Elapsed.TotalSeconds.ToString('F2')) seconds"
    }
    
    # Usage
    $items = Get-ChildItem -Path "master:\content\" -Recurse
    Update-ItemsWithProgress -Items $items -UpdateAction {
        param($item)
        $item.Title = "Updated: $($item.Name)"
    }
    $languages = @("en", "de-DE", "da", "es-ES")
    
    foreach($lang in $languages) {
        $item = Get-Item -Path "master:\content\home" -Language $lang -ErrorAction SilentlyContinue
    
        if ($item) {
            $item.Title = "Localized Title for $lang"
            Write-Host "Updated $lang version"
        } else {
            Write-Warning "No $lang version exists"
        }
    }
    # Get latest version
    $item = Get-Item -Path "master:\content\home" -Language "en"
    
    # Create new version before updating
    $newVersion = $item.Versions.AddVersion()
    $newVersion.Editing.BeginEdit()
    $newVersion["Title"] = "Updated in new version"
    $newVersion.Editing.EndEdit()
    
    Write-Host "Created version $($newVersion.Version)"
    $item = Get-Item -Path "master:\content\home"
    
    # Use the Automatic Properties
    Write-Host "Title: $($item.Title)"
    
    # Use Typed Fields
    $textField = $item.PSFields.Text
    if($textField.Value) {
        Write-Host "Text: $($item.PSFields.Text.Value)"
    }
    
    # Use typed fields for complex types
    $linkField = [Sitecore.Data.Fields.LinkField]$item.Fields["Link"]
    if ($linkField -and $linkField.LinkType -eq "internal") {
        $targetItem = $linkField.TargetItem
        Write-Host "Links to: $($targetItem.ItemPath)"
    }
    
    # Use typed fields for images
    $imageField = [Sitecore.Data.Fields.ImageField]$item.Fields["Image"]
    if ($imageField -and $imageField.MediaItem) {
        Write-Host "Image: $($imageField.MediaItem.Name)"
        Write-Host "Alt: $($imageField.Alt)"
        Write-Host "Size: $($imageField.Width)x$($imageField.Height)"
    }
    $item = Get-Item -Path "master:\content\home"
    
    # CORRECT - Use ISO format for manual field assignment
    $item.Editing.BeginEdit()
    $item["MyDateField"] = [Sitecore.DateUtil]::ToIsoDate([datetime]::Now)
    $item.Editing.EndEdit()
    
    # ALSO CORRECT - Automatic properties handle conversion
    $item.MyDateField = [datetime]::Now
    
    # Reading dates
    $createdDate = [Sitecore.DateUtil]::IsoDateToDateTime($item["__Created"])
    # Or using automated properties
    $createdDate = $item.__Created  # Returns System.DateTime
    function Remove-TestContent {
        param(
            [switch]$WhatIf
        )
        
        $itemsToDelete = Get-ChildItem -Path "master:\content\" -Recurse
        
        foreach($item in $itemsToDelete) {
            if ($WhatIf) {
                Write-Host "WHATIF: Would delete $($item.ItemPath)" -ForegroundColor Yellow
            } else {
                #Remove-Item -Path $item.ProviderPath -Permanently
                Write-Host "Deleted: $($item.ItemPath)" -ForegroundColor Red -BackgroundColor White
            }
        }
    }
    Remove-TestContent -WhatIf
    Write-Log "Starting item updates"
    $items = Get-ChildItem -Path "master:\content"
    foreach($item in $items) {
        try {
            $item.Title = "Updated"
            Write-Log "Updated: $($item.ItemPath)"
        } catch {
            Write-Log "Failed: $($item.ItemPath) - $($_.Exception.Message)" -Log Error
        }
    }
    
    Write-Log "Completed item updates"
    # BAD
    $item = Get-Item -Path "master:\content\maybe-exists"
    $item.Title = "New Title"  # Throws if item doesn't exist
    # GOOD
    $item = Get-Item -Path "master:\content\maybe-exists" -ErrorAction SilentlyContinue
    if ($item) {
        $item.Title = "New Title"
    } else {
        Write-Warning "Item not found"
    }
    # BAD
    foreach($item in $items) {
        try {
            $item.Title = "Updated"
        } catch {
            # Silent failure
        }
    }
    # GOOD
    $items = Get-ChildItem -Path "master:\content"
    
    $errors = @()
    foreach($item in $items) {
        try {
            $item.Title = "Updated"
        } catch {
            $errors += [PSCustomObject]@{
                Item = $item.ItemPath
                Error = $_.Exception.Message
            }
        }
    }
    
    if ($errors.Count -gt 0) {
        $errors | Show-ListView
    }
    # Method 1
    $time1 = Measure-Command {
        $items = Get-ChildItem -Path "master:\content" -Recurse |
            Where-Object { $_.TemplateName -eq "Sample Item" }
    }
    
    # Method 2
    $time2 = Measure-Command {
        $items = Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']"
    }
    
    Write-Host "Method 1: $($time1.TotalSeconds)s"
    Write-Host "Method 2: $($time2.TotalSeconds)s"
    Write-Host "Improvement: $(($time1.TotalSeconds / $time2.TotalSeconds).ToString('P0'))"

    <=

    -le

    Less than or equal

    >=

    -ge

    Greater than or equal

    Or

    ||

    -or

    Not

    !

    -not or !

    Escape char

    \

    `

    String interpolation

    $"text {var}"

    "text $var"

    Static access

    DateTime.Today

    [datetime]::Today

    Comments

    // or /* */

    # or <# #>

    Sitecore Query

    Specific criteria, medium trees

    ⭐⭐

    ✓

    ✓

    Find-Item

    Large trees (>500 items)

    ⭐⭐⭐⭐

    ✓

    Partial

    FATAL

    Critical errors

    Always enabled

    cs-User-Agent

    User agent string

    Identify automation vs browsers

    File Upload Attempts

    File upload failures

    Monitor for patterns

    Script Errors

    Script execution errors

    Monitor trends

    Archive old logs securely
  • Integrate with SIEM if available

  • Document your monitoring procedures

  • Review delegated access usage regularly

  • Track failed authentication patterns

  • Monitor web service usage for anomalies

  • Rely solely on manual log review
  • Forget to monitor IIS logs too

  • Ignore ERROR and WARN messages

  • Let log files consume all disk space

  • Quarterly Report

    Quarterly

    Executive summary

    DEBUG

    Detailed diagnostic information

    Development and troubleshooting

    INFO

    Informational messages

    Production (recommended)

    WARN

    Warning messages

    Production (recommended)

    ERROR

    Error messages

    Always enabled

    Development

    DEBUG

    Maximum detail for troubleshooting

    QA/Staging

    INFO

    Balance detail and volume

    Production

    INFO or WARN

    Important events without excessive detail

    c-ip

    Client IP address

    Identify source of requests

    cs-username

    Authenticated username

    Track who accessed services

    cs-uri-stem

    Requested URI

    Identify which services were called

    sc-status

    HTTP status code

    PCI-DSS

    1 year (3 months online)

    HIPAA

    6 years

    SOC 2

    1+ years

    GDPR

    Varies by data type

    Failed Auth Rate

    Failed authentications per hour

    Alert if > 10

    Elevation Denials

    Session elevation denials

    Alert if > 5

    Delegated Access

    Delegated access usage

    Monitor trends

    Web Service 401/403

    Unauthorized web service calls

    Alert if > 20

    Real-time Alerts

    Continuous

    Automated scripts/SIEM

    Daily Review

    Daily

    Automated summary email

    Weekly Analysis

    Weekly

    Manual review of trends

    Monthly Audit

    Monthly

    Comprehensive security review

    Security Checklist
    Delegated Access
    Web Services
    IIS Security
    log4net Documentation
    Sitecore Logging Documentation
    IIS Log File Formats

    Find authorization failures (401, 403)

    Requiring Windows Authentication

  • Blocking access at the web server level

  • Protecting against attacks before they reach Sitecore

  • Defense in Depth: Even if Sitecore security is bypassed, IIS security provides a second barrier.

    SPE Web Services Directory

    SPE web services are located in:

    Key Files:

    • web.config - IIS configuration for the services directory

    • RemoteAutomation.asmx - Remoting service

    • RemoteScriptCall.ashx - RESTful and file services

    • PowerShellWebService.asmx - Client service (Console/ISE)

    Deny Anonymous Access

    The most basic IIS security is denying anonymous users.

    Configuration

    Edit sitecore modules\PowerShell\Services\web.config:

    How It Works

    User Type
    Symbol
    Access

    Anonymous

    ?

    Denied

    Authenticated

    *

    Allowed (by default)

    Effect:

    • All anonymous requests are blocked with 401 Unauthorized

    • Users must authenticate with Sitecore credentials

    • Protects web services from unauthenticated access

    When to Use

    ✅ Always use this configuration unless you have a specific reason not to.

    Scenarios where you might not:

    • Public API endpoints (rare and dangerous)

    • Authentication handled by a different layer

    Windows Authentication

    For environments using Windows/Active Directory authentication, you can require Windows credentials at the IIS level.

    Configuration Steps

    1. Disable Anonymous Authentication in IIS

    1. Open IIS Manager

    2. Navigate to sitecore modules\PowerShell\Services\

    3. Open "Authentication" feature

    4. Disable "Anonymous Authentication"

    5. Enable "Windows Authentication"

    2. Update web.config

    Optionally add explicit deny rule:

    3. Configure Remoting Clients

    When using Windows Authentication, SPE Remoting commands require the Credential parameter:

    When to Use

    Best for:

    • Internal corporate networks

    • Environments with Active Directory

    • Servers requiring domain authentication

    • High-security environments

    Not suitable for:

    • Internet-facing servers (which shouldn't have SPE anyway)

    • Environments without Active Directory

    • Mixed authentication scenarios

    Allow Specific Users

    Restrict access to specific Windows users or roles.

    Allow Specific Users

    Allow Specific Roles

    Order Matters

    Rules are evaluated top to bottom. First match wins.

    Example:

    IP Address Restrictions

    Limit access to specific IP addresses or ranges using IIS IP Address and Domain Restrictions.

    Configuration via IIS Manager

    1. Open IIS Manager

    2. Navigate to sitecore modules\PowerShell\Services\

    3. Open "IP Address and Domain Restrictions"

    4. Click "Add Allow Entry..." or "Add Deny Entry..."

    5. Enter IP address or range

    Configuration via web.config

    Allow specific IPs:

    Deny specific IPs:

    When to Use

    Best for:

    • Limiting access to build servers

    • Allowing only internal network ranges

    • Blocking known malicious IPs

    • CI/CD automation from specific servers

    Example Use Case: Only allow remoting from build server at 10.0.0.100:

    SSL/TLS Requirements

    Require HTTPS for all SPE web service access.

    Configuration via web.config

    SSL Flags:

    Flag
    Description

    Ssl

    Require SSL/TLS connection

    SslNegotiateCert

    Negotiate client certificate

    SslRequireCert

    Require client certificate

    Ssl128

    Require 128-bit SSL

    Basic HTTPS Requirement

    Require Client Certificates

    For maximum security, require client certificates:

    Note: SPE also has a requireSecureConnection setting at the application level. Using both provides defense in depth.

    URL Rewrite Rules

    Use IIS URL Rewrite module to block or redirect requests.

    Block Suspicious Patterns

    Redirect HTTP to HTTPS

    Request Filtering

    Use IIS Request Filtering to block dangerous requests.

    Block Specific File Extensions

    Limit Request Size

    Block HTTP Verbs

    Complete Configuration Examples

    Production Environment (Standard Auth)

    Strict security with deny anonymous:

    CI/CD Environment

    Allow only build server, require HTTPS:

    Windows Authentication Environment

    Require Windows auth with specific roles:

    High Security Environment

    Multiple layers of protection:

    Best Practices

    Security Recommendations

    ✅ Do:

    • Always deny anonymous access (minimum requirement)

    • Require HTTPS for all external access

    • Use IP restrictions for CI/CD scenarios

    • Implement request filtering to block dangerous patterns

    • Layer multiple security controls (defense in depth)

    • Test authentication requirements before deploying

    • Document your IIS security configuration

    • Review IIS logs for unauthorized access attempts

    ❌ Don't:

    • Allow anonymous access unless absolutely necessary

    • Use HTTP for sensitive operations

    • Open access to all IPs without restriction

    • Forget to configure both IIS and Sitecore security

    • Assume IIS security alone is sufficient

    • Deploy without testing authentication workflows

    Configuration Strategy

    Environment
    Recommended IIS Security

    Local Dev

    Minimal (allow anonymous for convenience)

    Shared Dev

    Deny anonymous

    QA/Staging

    Deny anonymous + HTTPS

    Production

    Deny anonymous + HTTPS + IP restrictions + request filtering

    CI/CD

    IP restrictions + HTTPS + specific user/role

    Defense in Depth Layers

    Combine multiple security layers:

    1. Network - Firewall rules, VPN requirements

    2. IIS - Authentication, IP restrictions, HTTPS

    3. Sitecore - Role-based authorization, web service controls

    4. SPE - Session elevation, file upload restrictions

    5. Monitoring - Log analysis, alerting

    Troubleshooting

    401 Unauthorized after configuration

    Possible causes:

    1. Denied anonymous but using anonymous access

    2. Windows Authentication not configured correctly

    3. User not in allowed users/roles list

    Solution: Verify authentication method and user permissions.

    403 Forbidden when accessing services

    Possible causes:

    1. IP address not in allowed list

    2. SSL required but using HTTP

    3. Client certificate required but not provided

    Solution: Check IP restrictions, URL protocol, and certificate configuration.

    Windows Authentication doesn't prompt

    Possible causes:

    1. Windows Authentication not enabled in IIS

    2. Browser not configured for Windows Auth

    3. User in same domain (auto-authentication)

    Solution: Check IIS authentication settings and browser configuration.

    Works locally but not from remote machine

    Possible causes:

    1. IP restrictions blocking remote IP

    2. Firewall blocking access

    3. Authentication failing for remote user

    Solution: Check IP restrictions and firewall rules.

    Related Topics

    • Web Services Security - Sitecore-level web service configuration

    • Security Policies - Understanding SPE security model

    • Security Checklist - Validate your complete security configuration

    • Logging and Monitoring - Monitor for unauthorized access attempts

    References

    • ASP.NET Authorization

    • IIS IP Security

    • IIS Request Filtering

    • IIS URL Rewrite

    $SitecoreLogFolder\SPE.log.{date}.txt
    C:\inetpub\wwwroot\App_Data\logs\SPE.log.20260101.txt
    <configuration>
      <log4net>
          <appender name="PowerShellExtensionsFileAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
            <file value="$(dataFolder)/logs/SPE.log.{date}.txt"/>
            <appendToFile value="true"/>
            <layout type="log4net.Layout.PatternLayout">
              <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n"/>
            </layout>
            <encoding value="utf-8"/>
          </appender>
          <logger name="Spe" additivity="false">
            <level value="INFO"/>
            <appender-ref ref="PowerShellExtensionsFileAppender"/>
          </logger>
        </log4net>
    </configuration>
    INFO Arbitrary script execution in ISE by user: 'sitecore\Admin'
    WARN Session state elevated for 'ISE' by user: sitecore\Admin
    INFO [Gutter] Executing script {CFE81AF6-2468-4E62-8BF2-588B7CC60F80} for Context User sitecore\test as sitecore\Admin.
    INFO A request to the remoting service was made from IP 10.0.0.27
    INFO A request to the mediaUpload service was made from IP 10.0.0.27
    WARN A request to the mediaUpload service could not be completed because the provided credentials are invalid.
    INFO [Runner] Executing script {BD07C7D1-700D-450C-B79B-8526C6643BF3} for Context User sitecore\test2 as sitecore\Admin.
    # TODO
    # Tail the SPE log file
    # Note that the SPE Console doesn't exit when using -Wait
    Get-Content -Path "$($SitecoreLogFolder)\SPE.log.20251201.txt" -Tail 10
    # Tail the latest SPE log file dynamically
    Get-ChildItem -Path $SitecoreLogFolder -Filter "SPE.log.*.txt" | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1 | ForEach-Object { Get-Content -Path $_.FullName -Tail 10}
    # Watch for tasks
    Get-Content "$SitecoreLogFolder\SPE.log.20251201.txt" | Where-Object { $_ -match "\[Task\]" }
    # Watch for warnings
    Get-Content "$SitecoreLogFolder\SPE.log.20251201.txt" | Where-Object { $_ -match "WARN" }
    $logPath = "$SitecoreLogFolder\SPE.log.20251201.txt"
    $failedAuth = Get-Content $logPath |
        Where-Object { $_ -match "credentials are invalid" } |
        ForEach-Object {
            if ($_ -match "(\d{2}:\d{2}:\d{2}).*WARN\s*(\S+)") {
                [PSCustomObject]@{
                    Timestamp = $matches[1]
                    User = $matches[2]
                    LogLine = $_
                }
            }
        }
    
    $failedAuth
    
    # Timestamp User LogLine
    # --------- ---- -------
    # 11:20:23  A    1508 11:20:23 WARN  A request to the mediaUpload service could not be completed because the provided credentials are invalid.
    $logPath = "$SitecoreLogFolder\SPE.log.20251201.txt"
    $delegated = Get-Content $logPath |
        Where-Object { $_ -match "Executing script" } |
        ForEach-Object {
            if ($_ -match "(?<time>\d{2}:\d{2}:\d{2}).*Runner\s*.*Context User\s(?<user>[0-9a-zA-Z\\]*)\sas\s(?<impersonated>[0-9a-zA-Z\\]*).*") {
                [PSCustomObject]@{
                    Timestamp = $matches["time"]
                    ContextUser = $matches["user"]
                    ImpersonatedAs = $matches["impersonated"]
                    LogLine = $_
                }
            }
        }
    
    $delegated | Group-Object ContextUser |
        Select-Object Name, Count |
        Sort-Object Count -Descending
    
    # Name           Count
    # ----           -----
    # sitecore\test2     1
    $logPath = "$SitecoreLogFolder\SPE.log.20251201.txt"
    $unauthorized = Get-Content $logPath |
        Where-Object { $_ -match "credentials are invalid" }
    
    $unauthorized | ForEach-Object {
        Write-Host $_ -ForegroundColor Red -BackgroundColor White
    }
    
    # 1508 11:20:23 WARN  A request to the mediaUpload service could not be completed because the provided credentials are invalid.
    $logPath = "$SitecoreLogFolder\SPE.log.20251201.txt"
    $webServiceCalls = Get-Content $logPath |
        Where-Object { $_ -match "remoting" }
    
    # Group by IP address
    $webServiceCalls | ForEach-Object {
        if ($_ -match "IP\s*(?<ip>[\d\.]+)") {
            [PSCustomObject]@{
                IP = $matches['ip']
                LogLine = $_
            }
        }
    } | Group-Object IP |
        Select-Object Name, Count |
        Sort-Object Count -Descending
    
    # Name      Count
    # ----      -----
    # 10.0.0.27   105
    # TODO: Example using Send-MailMessage
    C:\inetpub\logs\LogFiles\W3SVC1\
    # TODO Inspect IIS Logs
    # TODO Inspect IIS Logs
    # TODO Example with Send-MailMessage
    sitecore modules\PowerShell\Services\
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </configuration>
    # Create credential object
    $credential = Get-Credential
    
    # Create session with Windows credentials
    $session = New-ScriptSession `
        -Username "sitecore\sitecore-user" `
        -Password "password" `
        -ConnectionUri "https://sitecore.local" `
        -Credential $credential
    
    # Or use credential parameter directly
    $session = New-ScriptSession `
        -ConnectionUri "https://sitecore.local" `
        -Credential (Get-Credential)
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
          <allow users="DOMAIN\username1, DOMAIN\username2" />
          <deny users="*" />
        </authorization>
      </system.web>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
          <allow roles="DOMAIN\Sitecore Administrators" />
          <deny users="*" />
        </authorization>
      </system.web>
    </configuration>
    <authorization>
      <!-- 1. Deny anonymous -->
      <deny users="?" />
    
      <!-- 2. Allow specific users -->
      <allow users="DOMAIN\username1" />
    
      <!-- 3. Allow specific roles -->
      <allow roles="DOMAIN\Sitecore Administrators" />
    
      <!-- 4. Deny everyone else -->
      <deny users="*" />
    </authorization>
    <configuration>
      <system.webServer>
        <security>
          <ipSecurity allowUnlisted="false">
            <add ipAddress="10.0.0.1" allowed="true" />
            <add ipAddress="10.0.0.2" allowed="true" />
            <add ipAddress="192.168.1.0" subnetMask="255.255.255.0" allowed="true" />
          </ipSecurity>
        </security>
      </system.webServer>
    </configuration>
    <configuration>
      <system.webServer>
        <security>
          <ipSecurity allowUnlisted="true">
            <add ipAddress="203.0.113.1" allowed="false" />
            <add ipAddress="198.51.100.0" subnetMask="255.255.255.0" allowed="false" />
          </ipSecurity>
        </security>
      </system.webServer>
    </configuration>
    <system.webServer>
      <security>
        <ipSecurity allowUnlisted="false">
          <add ipAddress="10.0.0.100" allowed="true" />
        </ipSecurity>
      </security>
    </system.webServer>
    <configuration>
      <system.webServer>
        <security>
          <access sslFlags="Ssl, SslNegotiateCert" />
        </security>
      </system.webServer>
    </configuration>
    <system.webServer>
      <security>
        <access sslFlags="Ssl" />
      </security>
    </system.webServer>
    <system.webServer>
      <security>
        <access sslFlags="Ssl, SslRequireCert" />
      </security>
    </system.webServer>
    <configuration>
      <system.webServer>
        <rewrite>
          <rules>
            <!-- Block requests with suspicious query strings -->
            <rule name="Block Malicious Query Strings" stopProcessing="true">
              <match url=".*" />
              <conditions>
                <add input="{QUERY_STRING}" pattern="(eval|exec|system|cmd\.exe)" />
              </conditions>
              <action type="CustomResponse" statusCode="403" statusReason="Forbidden" />
            </rule>
          </rules>
        </rewrite>
      </system.webServer>
    </configuration>
    <rewrite>
      <rules>
        <rule name="Force HTTPS" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
    <configuration>
      <system.webServer>
        <security>
          <requestFiltering>
            <fileExtensions>
              <add fileExtension=".exe" allowed="false" />
              <add fileExtension=".dll" allowed="false" />
              <add fileExtension=".bat" allowed="false" />
              <add fileExtension=".cmd" allowed="false" />
            </fileExtensions>
          </requestFiltering>
        </security>
      </system.webServer>
    </configuration>
    <system.webServer>
      <security>
        <requestFiltering>
          <!-- Max 10MB requests -->
          <requestLimits maxAllowedContentLength="10485760" />
        </requestFiltering>
      </security>
    </system.webServer>
    <system.webServer>
      <security>
        <requestFiltering>
          <verbs>
            <add verb="TRACE" allowed="false" />
            <add verb="TRACK" allowed="false" />
            <add verb="OPTIONS" allowed="false" />
          </verbs>
        </requestFiltering>
      </security>
    </system.webServer>
    <configuration>
      <system.web>
        <authorization>
          <!-- Deny anonymous access -->
          <deny users="?" />
        </authorization>
      </system.web>
    
      <system.webServer>
        <security>
          <!-- Require HTTPS -->
          <access sslFlags="Ssl" />
    
          <!-- Request filtering -->
          <requestFiltering>
            <requestLimits maxAllowedContentLength="10485760" />
            <fileExtensions>
              <add fileExtension=".exe" allowed="false" />
              <add fileExtension=".dll" allowed="false" />
            </fileExtensions>
          </requestFiltering>
        </security>
      </system.webServer>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    
      <system.webServer>
        <security>
          <!-- Require HTTPS -->
          <access sslFlags="Ssl" />
    
          <!-- Only allow build server -->
          <ipSecurity allowUnlisted="false">
            <add ipAddress="10.0.0.100" allowed="true" />
          </ipSecurity>
        </security>
      </system.webServer>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
          <allow roles="DOMAIN\Sitecore Administrators, DOMAIN\Sitecore Developers" />
          <deny users="*" />
        </authorization>
      </system.web>
    
      <system.webServer>
        <security>
          <access sslFlags="Ssl" />
        </security>
      </system.webServer>
    </configuration>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
          <allow users="DOMAIN\sitecore-admin" />
          <deny users="*" />
        </authorization>
      </system.web>
    
      <system.webServer>
        <security>
          <!-- Require HTTPS and client certificate -->
          <access sslFlags="Ssl, SslRequireCert" />
    
          <!-- IP restriction to internal network -->
          <ipSecurity allowUnlisted="false">
            <add ipAddress="10.0.0.0" subnetMask="255.0.0.0" allowed="true" />
          </ipSecurity>
    
          <!-- Request filtering -->
          <requestFiltering>
            <requestLimits maxAllowedContentLength="5242880" />
            <verbs>
              <add verb="TRACE" allowed="false" />
              <add verb="OPTIONS" allowed="false" />
            </verbs>
          </requestFiltering>
        </security>
    
        <!-- URL rewrite to block patterns -->
        <rewrite>
          <rules>
            <rule name="Block Suspicious Patterns" stopProcessing="true">
              <match url=".*" />
              <conditions>
                <add input="{QUERY_STRING}" pattern="(eval|exec|cmd)" />
              </conditions>
              <action type="CustomResponse" statusCode="403" />
            </rule>
          </rules>
        </rewrite>
      </system.webServer>
    </configuration>
    Quick Start

    New to SPE security? Start here:

    1. Getting Started - Essential security setup for new installations

    2. Security Policies - Understand the SPE security model

    3. Security Checklist - Validate your deployment before going live

    Security Documentation

    Core Security Topics

    Security Policies

    Understand the two-layer security model that governs SPE:

    • Application Pool Service Account (OS-level access)

    • Sitecore User Account (API-level access)

      • Application and menu item security

    • Best practices for both security contexts

    Session Elevation (UAC)

    Configure User Account Control to require reauthentication:

    • How Session Elevation works

    • Elevation actions (Allow, Block, Password, Confirm)

    • Token configuration and expiration

    • Environment-specific recommendations

    • Interface behaviors (Console, ISE, Content Editor)

    Web Services Security

    Control external access to SPE through web services:

    • Service descriptions and security implications

    • Enable/disable individual services

    • HTTPS and requireSecureConnection

    • Role-based authorization

    • Configuration examples for different scenarios

    Hardening and Protection

    File Upload Restrictions

    Prevent malicious file uploads:

    • File type restrictions (extensions and MIME types)

    • Upload location restrictions

    • Dangerous file types to never allow

    • Configuration examples

    • Testing upload restrictions

    Delegated Access

    Grant controlled privilege escalation:

    • How delegated access works

    • Configuration steps

    • Use cases (publishing, reports, bulk operations)

    • Script implementation patterns

    • Security best practices and monitoring

    IIS-Level Security

    Add defense in depth at the web server level:

    • Deny anonymous access

    • Windows Authentication

    • IP address restrictions

    • SSL/TLS requirements

    • Request filtering and URL rewrite rules

    User Management

    Users and Roles

    Manage Sitecore users and roles:

    • Bulk user operations

    • Role queries and management

    • Item Access Control Lists (ACL)

    • Active Directory integration

    • PowerShell examples for user management

    Deployment and Operations

    Minimal Web Service Deployment

    Deploy only what's needed for CI/CD:

    • Required files for web services only

    • Disable UI components

    • Configuration for automation scenarios

    • Security best practices

    • Common deployment patterns

    Logging and Monitoring

    Track security events and detect incidents:

    • What gets logged

    • Log levels and configuration

    • Real-time monitoring strategies

    • Log analysis examples

    • Integration with SIEM systems

    • Security metrics and dashboards

    Validation and Compliance

    Security Checklist

    Comprehensive validation before deployment:

    • Pre-deployment validation

    • Configuration checklist

    • Testing procedures

    • Environment-specific checklists

    • Post-deployment monitoring

    • Emergency procedures

    Security by Environment

    Development Environment

    Priority: Productivity with basic security

    Recommendations:

    • Session Elevation: Relaxed (Allow or long timeouts)

    • Web Services: Enable as needed for testing

    • Logging: DEBUG level for troubleshooting

    • IP Restrictions: Not required

    Start here: Getting Started - Development

    QA/Staging Environment

    Priority: Match production security for testing

    Recommendations:

    • Session Elevation: Password or Confirm (5-15 minute timeout)

    • Web Services: Match production configuration

    • Logging: INFO level

    • IP Restrictions: Optional

    Start here: Getting Started - QA/Staging

    Production Environment

    Priority: Maximum security

    Recommendations:

    • Session Elevation: Password or Confirm (3-5 minute timeout)

    • Web Services: Only handleDownload, client, execution (disable remoting)

    • Logging: INFO or WARN level

    • IP Restrictions: Recommended

    • HTTPS: Required

    Start here: Security Checklist - Production

    CI/CD Environment

    Priority: Automation with strict access control

    Recommendations:

    • Minimal Deployment: Use minimal package

    • Remoting: Enabled with IP restrictions

    • Web Services: Only required services

    • Logging: INFO level with monitoring

    • HTTPS: Required

    Start here: Minimal Deployment

    Security Layers (Defense in Depth)

    SPE security uses multiple layers for comprehensive protection:

    Each layer provides additional protection. If one layer is compromised, others provide continued security.

    Common Security Scenarios

    Scenario 1: Locking Down Production CM

    Goal: Secure SPE for production content management server

    Steps:

    1. Review Security Policies to understand the model

    2. Configure Session Elevation with 5-minute Password timeout

    3. Disable unnecessary Web Services

    4. Configure IIS Security to deny anonymous access

    5. Enable

    6. Complete the

    Scenario 2: Setting Up CI/CD Automation

    Goal: Enable remote automation from build servers

    Steps:

    1. Use Minimal Deployment package

    2. Enable Remoting in Web Services with specific user

    3. Configure IIS Security with IP restrictions to build servers

    4. Configure File Upload Restrictions for packages only

    5. Set up for automation activity

    6. Test with

    Scenario 3: Delegating Report Access

    Goal: Allow content authors to run administrative reports

    Steps:

    1. Understand Delegated Access concepts

    2. Create delegated access configuration for reporting role

    3. Configure impersonated user with read-only administrative access

    4. Test report access as content author

    5. Monitor usage via

    Scenario 4: Identity Server Integration (Sitecore 9.1+)

    Goal: Configure SPE with Sitecore Identity Server

    Steps:

    1. Enable Spe.IdentityServer.config

    2. Configure Session Elevation with Confirm action (not Password)

    3. Test Console and ISE with federated authentication

    4. Configure Web Services if needed

    Security Best Practices Summary

    ✅ Do

    • Always deny anonymous access at IIS level

    • Always use Session Elevation (UAC) in production

    • Always require HTTPS for any enabled web services

    • Always follow principle of least privilege

    • Always monitor logs for suspicious activity

    • Only enable web services you specifically need

    • Use short session elevation timeouts in production (3-5 minutes)

    • Restrict SPE access to trusted administrators only

    • Configure file upload restrictions when upload service is enabled

    • Regular security audits and role membership reviews

    • Document your security configuration

    • Test security in non-production before deploying

    ❌ Don't

    • Never install SPE on Content Delivery (CD) servers

    • Never expose SPE to internet-facing servers

    • Never use elevationAction="Allow" in production

    • Never enable all web services "just in case"

    • Never grant broad role access (e.g., "Everyone")

    • Never allow dangerous file types (.exe, .dll, .ps1, .bat)

    • Don't skip Session Elevation configuration

    • Don't ignore failed authentication attempts in logs

    • Don't use administrator accounts for automation

    • Don't forget to configure authorization when enabling remoting

    Quick Reference

    Configuration Files

    File
    Purpose
    Documentation

    App_Config\Include\Spe\Spe.config

    Core SPE configuration

    App_Config\Include\Spe\Spe.IdentityServer.config

    Identity Server integration

    App_Config\Include\Spe\Custom\*.config

    Your security patches

    All topics

    sitecore modules\PowerShell\Services\web.config

    IIS-level security

    Security Policies Location

    Policy
    Location
    Documentation

    Application Visibility

    core:\content\Applications\PowerShell

    Menu Item Security

    core:\content\Applications\Content Editor\Context Menues\Default\

    Script Library Security

    Item-level security on scripts

    Delegated Access

    SPE configuration items

    Default Roles

    Role
    Default Access
    Recommendation

    sitecore\Developer

    Console, ISE

    Keep restricted to developers only

    sitecore\Sitecore Client Users

    ListView, Runner

    Appropriate for content authors

    sitecore\Sitecore Client Authoring

    Reports

    Appropriate for content authors

    sitecore\PowerShell Extensions Remoting

    Remoting (when enabled)

    Getting Help

    Documentation Navigation

    • New to SPE Security? Start with Getting Started

    • Deploying to production? Use the Security Checklist

    • Setting up automation? See Minimal Deployment

    • Need to debug? Check Logging and Monitoring

    • Configuring a specific feature? See topic-specific guides below

    Support Resources

    • GitHub Issues: SitecorePowerShell/Console

    • Slack: #module-spe on Sitecore Community Slack

    • Documentation: Full SPE Documentation

    Security Incident Response

    If you suspect a security breach:

    1. Immediately lock down SPE using Emergency Procedures

    2. Review logs using Logging and Monitoring guidance

    3. Document the incident

    4. Contact your security team

    5. Report to SPE maintainers if it's a product vulnerability

    Additional Resources

    Related Documentation

    • Installation - Initial SPE installation

    • Interfaces - Console, ISE, and Interactive Dialogs

    • Remoting - Using SPE Remoting for automation

    • Modules - Integration points and features

    • - PowerShell security commands

    External References

    • Sitecore Security Best Practices

    • OWASP Top 10

    • Principle of Least Privilege

    Version-Specific Notes

    Sitecore 9.1+ with Identity Server

    Enable the Identity Server configuration:

    • File: App_Config\Include\Spe\Spe.IdentityServer.config

    • Purpose: Prevents infinite loop in SPE Console

    • Use elevationAction="Confirm" instead of "Password"

    Sitecore XM Cloud

    Consult the latest SPE documentation for XM Cloud-specific security configurations.


    Remember: Security is not a one-time configuration. Regular reviews, monitoring, and updates are essential to maintaining a secure SPE installation.

    Last Updated: 2025 Maintained By: SPE Community

    RESTful API access

  • File and media uploads/downloads

  • Report exports

  • Security Warning: Only enable web services you specifically need. Each enabled service increases your attack surface. Never enable services on internet-facing servers.

    Service Configuration

    Services are configured in App_Config\Include\Spe\Spe.config:

    Service Descriptions

    Client Service (enabled by default)

    Service File: PowerShellWebService.asmx

    Purpose: Powers the SPE Console and ISE user interfaces.

    Required For:

    • PowerShell Console

    • PowerShell ISE (Integrated Scripting Environment)

    Security Considerations:

    • Required for basic SPE functionality

    • Access controlled by Sitecore user permissions

    • Protected by Session Elevation (UAC)

    Should you disable it? No - this breaks the Console and ISE.

    Execution Service (enabled by default)

    Service File: Various pipeline integrations

    Purpose: Checks if users have permission to run SPE applications.

    Required For:

    • Download File dialogs

    • PowerShell Script Runner

    • Content Editor integrations (Context Menu, Insert Options, Ribbon)

    Security Considerations:

    • Authorization check service

    • Does not execute arbitrary code

    • Validates permissions before allowing access

    Should you disable it? No - this breaks SPE integration points.

    Handle Download Service (enabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Enables file downloads through the Sitecore interface.

    Required For:

    • Out-Download command

    • Report exports (CSV, Excel, etc.)

    • ISE script exports

    Security Considerations:

    • Only works for authenticated users

    • Requires active Sitecore session

    • Downloads are temporary and time-limited

    Should you disable it? Only if you never need to download files from SPE (rare).

    Remoting Service (disabled by default)

    Service File: RemoteAutomation.asmx

    Purpose: Allows external clients to execute PowerShell scripts remotely.

    Required For:

    • SPE Remoting module

    • Automated CI/CD scripts

    • External automation tools

    Security Considerations:

    • ⚠️ HIGH RISK - enables remote code execution

    • Must be protected with role-based authorization

    • Should require HTTPS

    • Ideal for CI/CD environments with proper security

    Example Use Case: Automated content deployment from build servers.

    Securing Remoting Service

    Enable with HTTPS requirement:

    Restrict to specific users:

    Load Balancer Note: When using requireSecureConnection behind a load balancer that handles TLS termination, you may receive 403 errors. The backend server receives HTTP traffic and .NET doesn't recognize it as secure. Consider network-level security instead.

    RESTful v2 Service (disabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Execute scripts via RESTful URLs with all parameters in the URL.

    Required For:

    • PowerShell Web API

    • RESTful script endpoints

    • External integrations

    Security Considerations:

    • ⚠️ MEDIUM-HIGH RISK - exposes script execution via HTTP

    • URL-based parameters may be logged

    • Should require HTTPS

    • Should use POST instead of GET when possible

    Example Use Case: Providing a web API for external systems to query Sitecore content.

    Enabling RESTful v2

    File Download Service (disabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Download files from the server file system via URL.

    Required For:

    • SPE Remoting file downloads

    • External file retrieval

    Security Considerations:

    • ⚠️ MEDIUM RISK - exposes file system

    • Restricted by file type and location configuration

    • Only works with allowed paths

    Should you enable it? Only if using SPE Remoting and need file downloads.

    File Upload Service (disabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Upload files to the server file system via URL.

    Required For:

    • SPE Remoting file uploads

    • External file deployment

    Security Considerations:

    • ⚠️ HIGH RISK - allows writing to file system

    • Restricted by file type and location configuration

    • Can be used to deploy malicious files if misconfigured

    • Must be carefully controlled

    Should you enable it? Only if absolutely necessary, with strict restrictions.

    Securing File Upload

    See File Upload Restrictions for detailed configuration.

    Media Download Service (disabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Download media library items via URL.

    Required For:

    • SPE Remoting media downloads

    • External media retrieval

    Security Considerations:

    • ⚠️ LOW-MEDIUM RISK - exposes media library

    • Respects Sitecore security

    • May expose sensitive media items

    Should you enable it? Only if using SPE Remoting and need media downloads.

    Media Upload Service (disabled by default)

    Service File: RemoteScriptCall.ashx

    Purpose: Upload files as media library items via URL.

    Required For:

    • SPE Remoting media uploads

    • External media deployment

    Security Considerations:

    • ⚠️ MEDIUM RISK - allows media library uploads

    • Restricted by file type configuration

    • Can bloat media library if misused

    Should you enable it? Only if using SPE Remoting and need media uploads.

    RESTful v1 Service (disabled by default - DEPRECATED)

    Service File: RemoteScriptCall.ashx

    Purpose: Legacy RESTful API from early SPE versions.

    Security Considerations:

    • ⚠️ DEPRECATED - avoid using

    • Use RESTful v2 instead

    Should you enable it? No - migrate to v2.

    Configuration Examples

    Minimal Configuration (UI Only)

    Default configuration - only services needed for Console and ISE:

    CI/CD Configuration

    Enable remoting for build automation, with strict security:

    Web API Configuration

    Enable RESTful v2 for web API endpoints:

    Full SPE Remoting

    Enable all remoting capabilities (use with caution):

    Role-Based Authorization

    Restrict remoting access to specific roles or users.

    Default Authorization

    By default, these roles can use remoting (when enabled):

    Replace Default Roles

    Remove default roles and add your own:

    Add Specific Users

    Grant access to individual users:

    Combine Roles and Users

    IIS-Level Protection

    Add an additional security layer by configuring IIS authentication.

    Deny Anonymous Access

    Edit sitecore modules\PowerShell\Services\web.config:

    This denies all anonymous users from accessing SPE web services.

    Windows Authentication

    For environments with Windows Authentication:

    1. Disable Anonymous Authentication in IIS for sitecore modules\PowerShell\Services\

    2. Enable Windows Authentication

    3. Use the Credential parameter in remoting commands:

    Best Practices

    Security Recommendations

    ✅ Do:

    • Only enable services you specifically need

    • Require HTTPS for all external services (requireSecureConnection="true")

    • Use role-based authorization to limit access

    • Deny anonymous access at the IIS level

    • Regularly audit which services are enabled

    • Use dedicated service accounts for automation

    • Monitor web service access logs

    • Disable services in Content Delivery (CD) environments

    ❌ Don't:

    • Enable all services "just in case"

    • Allow HTTP for remoting or file upload

    • Grant broad role access (e.g., "Everyone")

    • Use administrator accounts for automation

    • Enable services on internet-facing servers

    • Forget to configure authorization when enabling remoting

    • Leave default passwords on service accounts

    Environment-Specific Configurations

    Environment
    Recommended Services
    Rationale

    Local Dev

    All enabled (if needed)

    Convenience for development and testing

    Shared Dev

    handleDownload, client, execution

    Only UI features

    QA/Staging

    Match production

    Test with production security

    Production CM

    handleDownload, client, execution

    Decision Matrix: Should You Enable This Service?

    Service
    Enable If...
    Security Requirements

    client

    Using Console/ISE (always)

    Sitecore user auth + Session Elevation

    execution

    Using SPE features (always)

    Sitecore user auth

    handleDownload

    Need to download reports/files (usually)

    Sitecore user auth

    remoting

    Need external automation

    Troubleshooting

    403 Forbidden when using requireSecureConnection

    Cause: Load balancer terminates TLS and forwards HTTP to backend.

    Solution:

    • Configure network-level security instead

    • Remove requireSecureConnection and secure at network/firewall level

    • Or configure load balancer to forward HTTPS

    Remoting returns "Access Denied"

    Possible causes:

    1. User/role not in authorization list

    2. IIS denies anonymous access but credentials not provided

    3. User doesn't exist or password is incorrect

    Solution: Check configuration and verify credentials.

    File upload fails even when enabled

    Cause: File type or location not allowed.

    Solution: Configure file upload restrictions (see File Upload Restrictions).

    Related Topics

    • File Upload Restrictions - Configure allowed file types and paths

    • IIS Security - Additional IIS-level hardening

    • Remoting - Using SPE Remoting features

    • Web API - Building RESTful APIs with SPE

    References

    • SPE Remoting Documentation

    • ASP.NET Authorization

    Security Checklist

    Use this checklist to validate your SPE security configuration before deploying to any environment. Each section corresponds to a security layer that should be properly configured.

    Pre-Deployment Checklist

    Environment Validation

    1. Network Security
       - Firewall rules
       - VPN/private network
       - Not internet-facing
    2. IIS-Level Security
       - Deny anonymous access
       - IP restrictions
       - HTTPS requirements
       - Request filtering
    3. Sitecore User Security
       - Role-based access control
       - Application-level permissions
       - Item-level security
    4. SPE Security Hardening
       - Session Elevation (UAC)
       - Web service controls
       - File upload restrictions
       - Delegated access controls
    5. Logging and Monitoring
       - Comprehensive logging
       - Real-time alerting
       - Regular audit reviews
       - SIEM integration
    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:security="http://www.sitecore.net/xmlconfig/security/">
      <sitecore role:require="Standalone or ContentManagement or XMCloud" security:require="Sitecore">
        <pipelines>
          <owin.cookieAuthentication.validateIdentity>
            <processor type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.ValidateSiteNeutralPaths, Sitecore.Owin.Authentication">
              <siteNeutralPaths hint="list">
                <!-- This entry corrects the infinite loop of ExecuteCommand in the SPE Console -->
                <path hint="spe">/sitecore%20modules/PowerShell</path>
              </siteNeutralPaths>
            </processor>
          </owin.cookieAuthentication.validateIdentity>
        </pipelines>
      </sitecore>
    </configuration>
    <sitecore>
      <powershell>
        <services>
          <restfulv1 enabled="false" />
          <restfulv2 enabled="false" />
          <remoting enabled="false" />
          <fileDownload enabled="false" />
          <fileUpload enabled="false" />
          <mediaDownload enabled="false" />
          <mediaUpload enabled="false" />
          <handleDownload enabled="true" />
          <client enabled="true" />
          <execution enabled="true" />
        </services>
      </powershell>
    </sitecore>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <remoting>
              <patch:attribute name="enabled">true</patch:attribute>
              <patch:attribute name="requireSecureConnection">true</patch:attribute>
              <authorization>
                <add Permission="Allow" IdentityType="Role" Identity="sitecore\PowerShell Extensions Remoting" />
              </authorization>
            </remoting>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <remoting>
      <patch:attribute name="enabled">true</patch:attribute>
      <patch:attribute name="requireSecureConnection">true</patch:attribute>
      <authorization>
        <add Permission="Allow" IdentityType="User" Identity="sitecore\automation-user" />
      </authorization>
    </remoting>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <restfulv2>
              <patch:attribute name="enabled">true</patch:attribute>
            </restfulv2>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <services>
      <restfulv1 enabled="false" />
      <restfulv2 enabled="false" />
      <remoting enabled="false" />
      <fileDownload enabled="false" />
      <fileUpload enabled="false" />
      <mediaDownload enabled="false" />
      <mediaUpload enabled="false" />
      <handleDownload enabled="true" />
      <client enabled="true" />
      <execution enabled="true" />
    </services>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <remoting>
              <patch:attribute name="enabled">true</patch:attribute>
              <patch:attribute name="requireSecureConnection">true</patch:attribute>
              <authorization>
                <patch:delete />
              </authorization>
              <authorization>
                <add Permission="Allow" IdentityType="User" Identity="sitecore\build-automation" />
              </authorization>
            </remoting>
            <fileDownload>
              <patch:attribute name="enabled">true</patch:attribute>
            </fileDownload>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <restfulv2>
              <patch:attribute name="enabled">true</patch:attribute>
            </restfulv2>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <remoting>
              <patch:attribute name="enabled">true</patch:attribute>
              <patch:attribute name="requireSecureConnection">true</patch:attribute>
            </remoting>
            <fileDownload>
              <patch:attribute name="enabled">true</patch:attribute>
            </fileDownload>
            <fileUpload>
              <patch:attribute name="enabled">true</patch:attribute>
            </fileUpload>
            <mediaDownload>
              <patch:attribute name="enabled">true</patch:attribute>
            </mediaDownload>
            <mediaUpload>
              <patch:attribute name="enabled">true</patch:attribute>
            </mediaUpload>
          </services>
        </powershell>
      </sitecore>
    </configuration>
    <authorization>
      <add Permission="Allow" IdentityType="Role" Identity="sitecore\PowerShell Extensions Remoting" />
    </authorization>
    <authorization>
      <patch:delete />
    </authorization>
    <authorization>
      <add Permission="Allow" IdentityType="Role" Identity="sitecore\Automation" />
      <add Permission="Allow" IdentityType="Role" Identity="sitecore\Developers" />
    </authorization>
    <authorization>
      <add Permission="Allow" IdentityType="User" Identity="sitecore\ci-user" />
      <add Permission="Allow" IdentityType="User" Identity="sitecore\deployment-user" />
    </authorization>
    <authorization>
      <add Permission="Allow" IdentityType="Role" Identity="sitecore\PowerShell Extensions Remoting" />
      <add Permission="Allow" IdentityType="User" Identity="sitecore\admin" />
      <add Permission="Allow" IdentityType="User" Identity="sitecore\build-agent" />
    </authorization>
    <configuration>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
      </system.web>
    </configuration>
    $session = New-ScriptSession -Username "domain\user" -Password "password" -ConnectionUri "https://sitecore.local"

    Only UI features unless remoting needed

    Production CD

    None - don't install SPE

    CD servers should not have SPE

    HTTPS + role auth + IIS deny anonymous

    restfulv2

    Building web APIs

    HTTPS + script-level security

    fileDownload

    Using SPE Remoting file operations

    HTTPS + role auth + path restrictions

    fileUpload

    Using SPE Remoting file operations

    HTTPS + role auth + strict file/path restrictions

    mediaDownload

    Using SPE Remoting media operations

    HTTPS + role auth

    mediaUpload

    Using SPE Remoting media operations

    HTTPS + role auth + file type restrictions

    restfulv1

    Never (deprecated)

    N/A - don't use

    IIS Security

    Delegated Access

    Use custom role instead

    Logging and Monitoring
    Security Checklist
    Logging and Monitoring
    Security Checklist - CI/CD
    Logging and Monitoring
    Appendix - Security Cmdlets
    Web Services
    Getting Started
    Security Policies
    Security Policies
    Users and Roles
  • STOP: If any of the above are not true, DO NOT proceed with SPE installation.

    Configuration Checklist

    1. Web Services Security

    Review App_Config\Include\Spe\Spe.config (via patch file):

    Services Status:

    If Remoting is Enabled:

    Documentation: Web Services Security

    2. Session Elevation (UAC)

    Token Configuration:

    Quick Test:

    Documentation: Session Elevation

    3. User and Role Access

    Sitecore Security:

    Application Pool Account:

    Documentation: Security Policies, Users and Roles

    4. File Upload Restrictions

    Configuration:

    Quick Test:

    Documentation: File Upload Restrictions

    5. IIS-Level Security

    Web.config Configuration (sitecore modules\PowerShell\Services\web.config):

    Additional IIS Security:

    Quick Test:

    Documentation: IIS Security

    6. Delegated Access

    If Using Delegated Access:

    If NOT Using Delegated Access:

    Documentation: Delegated Access

    7. Identity Server (Sitecore 9.1+)

    For Sitecore 9.1+ with Identity Server:

    Documentation: Getting Started - Identity Server

    8. Minimal Web Service Deployment

    For CI/CD Environments:

    Documentation: Minimal Deployment

    Testing Checklist

    Functional Testing

    As Non-Administrator User:

    As Administrator User (without elevated session):

    As Administrator User (with elevated session):

    Web Services (if enabled):

    Security Testing

    Attack Surface:

    Privilege Escalation:

    Logging and Monitoring Checklist

    Logging Configuration:

    Monitoring:

    Documentation: Logging and Monitoring

    Documentation Checklist

    Required Documentation:

    Compliance Checklist

    Organizational Requirements:

    Regulatory Compliance (if applicable):

    Sign-Off

    Deployment Approval:

    Approved By:

    Post-Deployment Checklist

    Within 24 Hours:

    Within 1 Week:

    Monthly:

    Environment-Specific Checklists

    Development Environment

    Minimum Requirements:

    Optional:

    • IP restrictions

    • Strict session timeouts

    • HTTPS enforcement

    QA/Staging Environment

    Must Match Production:

    Production Environment

    Strictest Security:

    CI/CD Environment

    Automation-Focused:

    Quick Reference

    Security Layer
    Configuration File
    Critical Setting

    Web Services

    Spe.config (via patch)

    Services enabled/disabled

    Session Elevation

    Spe.config (via patch)

    Token expiration and action

    File Upload

    Spe.config (via patch)

    Allowed types and locations

    IIS Auth

    Services\web.config

    Related Documentation

    • Getting Started - Initial security setup

    • Security Policies - Understanding the security model

    • Session Elevation - UAC configuration

    • Web Services - Web service security

    • - IIS-level protection

    • - Upload security

    • - Controlled privilege escalation

    • - Audit and monitoring

    • - User management

    Emergency Procedures

    Security Incident Response

    If you suspect a security breach:

    1. Immediate Actions:

      • Disable all SPE web services

      • Block access at firewall level

      • Review recent logs for suspicious activity

      • Document the incident

    2. Investigation:

      • Check IIS logs for unauthorized access

      • Check SPE logs for unusual script execution

      • Review user activity

    3. Remediation:

      • Change service account passwords

      • Review and tighten security configuration

      • Apply security patches if needed

    4. Recovery:

      • Restore from backup if necessary

      • Re-enable services with enhanced security

      • Monitor closely for 48 hours

    Quick Lockdown

    To immediately lock down SPE:

    Add to Services\web.config:

    Version History

    Track when security reviews were completed:

    Date
    Reviewer
    Environment
    Status
    Notes

    YYYY-MM-DD

    Name

    Production

    ✓ Pass

    Initial deployment

    YYYY-MM-DD

    Name

    QA

    ✓ Pass

    Quarterly review


    Last Updated: {{DATE}} Next Review: {{DATE + 3 months}}

    <!-- Add to config patch to disable all external access -->
    <configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
      <sitecore>
        <powershell>
          <services>
            <remoting enabled="false" />
            <restfulv1 enabled="false" />
            <restfulv2 enabled="false" />
            <fileDownload enabled="false" />
            <fileUpload enabled="false" />
            <mediaDownload enabled="false" />
            <mediaUpload enabled="false" />
          </services>
          <userAccountControl>
            <tokens>
              <token name="Console">
                <patch:attribute name="elevationAction">Block</patch:attribute>
              </token>
              <token name="ISE">
                <patch:attribute name="elevationAction">Block</patch:attribute>
              </token>
            </tokens>
          </userAccountControl>
        </powershell>
      </sitecore>
    </configuration>
    <authorization>
      <deny users="*" />
    </authorization>
    Identify scope of incident
    Re-deploy with validated security
    Document lessons learned

    Deny anonymous

    Sitecore Security

    Core DB items

    Role permissions

    Remoting Auth

    Spe.config (via patch)

    Authorization roles/users

    IIS Security
    File Upload Restrictions
    Delegated Access
    Logging and Monitoring
    Users and Roles

    Dialogs

    Examples for managing complex interactive dialogs.

    Basic text controls

    Number controls

    Checkbox control

    Dropdown combo controls

    Checklist control

    Radio button control

    Date Time control

    Single item picker with a tree

    Treelist control

    Multilist controls

    Droplist contol

    Grouped dropdown controls

    User role pickers

    Rule editor controls

    Info display controls

    Variable binding

    Tabbed dialog

    Conditional visibility

    Column layout

    Mandatory fields

    Dialog customization

    Simple dialog

    Comprehensive example

    <#
        .SYNOPSIS
            Demonstrates basic text input controls in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to use single-line text, multi-line text, password fields,
            and placeholder text in SPE dialogs.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "Basic Text Controls"
        Description = "Examples of text input fields available in SPE dialogs."
        Width = 500
        Height = 400
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "singleLineText"
                Value = ""
                Title = "Single Line Text"
                Tooltip = "A simple single-line text input"
                Placeholder = "Enter text here..."
            },
            @{
                Name = "multiLineText"
                Value = ""
                Title = "Multi-Line Text"
                Lines = 3
                Tooltip = "A multi-line text area for longer content"
                Placeholder = "Enter multiple lines of text..."
            },
            @{
                Name = "passwordField"
                Value = ""
                Title = "Password"
                Editor = "password"
                Tooltip = "Password input - characters are masked"
                Placeholder = "Enter password..."
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Single Line Text: $singleLineText" -ForegroundColor Green
        Write-Host "Multi-Line Text: $multiLineText" -ForegroundColor Green
        Write-Host "Password: $passwordField" -ForegroundColor Green
    }
    <#
        .SYNOPSIS
            Demonstrates number input controls in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to use integer and floating-point number inputs in SPE dialogs.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "Number Input Controls"
        Description = "Examples of numeric input fields."
        Width = 400
        Height = 300
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "integerValue"
                Value = 100
                Editor = "number"
                Title = "Integer Value"
                Tooltip = "Enter a whole number"
                Columns = 6
            },
            @{
                Name = "floatValue"
                Value = 1.5
                Editor = "number"
                Title = "Decimal Value"
                Tooltip = "Enter a decimal number"
                Columns = 6
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Integer Value: $integerValue" -ForegroundColor Green
        Write-Host "Float Value: $floatValue" -ForegroundColor Green
    
        # Demonstrate the returned types
        Write-Host "`nReturned Types:" -ForegroundColor Cyan
        Write-Host "Integer Type: $($integerValue.GetType().Name)"
        Write-Host "Float Type: $($floatValue.GetType().Name)"
    }
    <#
        .SYNOPSIS
            Demonstrates checkbox control in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to use checkbox inputs that return boolean values.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize default value
    $enableFeature = $true
    
    $dialogParams = @{
        Title = "Checkbox Control"
        Description = "Example of checkbox input that returns a boolean value."
        Width = 400
        Height = 250
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "enableFeature"
                Value = $true
                Title = "Enable Feature"
                Tooltip = "Check to enable, uncheck to disable"
                Editor = "checkbox"
            },
            @{
                Name = "includeSubitems"
                Value = $false
                Title = "Include Subitems"
                Tooltip = "Process child items as well"
                Editor = "checkbox"
            },
            @{
                Name = "publishAfterSave"
                Value = $false
                Title = "Publish After Save"
                Tooltip = "Automatically publish changes"
                Editor = "checkbox"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Enable Feature: $enableFeature" -ForegroundColor Green
        Write-Host "Include Subitems: $includeSubitems" -ForegroundColor Green
        Write-Host "Publish After Save: $publishAfterSave" -ForegroundColor Green
    
        # Example conditional logic based on checkbox values
        if ($enableFeature) {
            Write-Host "`nFeature is enabled!" -ForegroundColor Cyan
        }
    }
    <#
        .SYNOPSIS
            Demonstrates dropdown (combo) controls in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to create dropdown lists with predefined options and tooltips.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Define options as an ordered hashtable
    # Format: @{ "Display Text" = "Value" }
    $priorityOptions = [ordered]@{
        "Low" = "1"
        "Medium" = "2"
        "High" = "3"
        "Critical" = "4"
    }
    
    # Options with tooltips
    $actionOptions = [ordered]@{
        "Create" = "create"
        "Update" = "update"
        "Delete" = "delete"
        "Archive" = "archive"
    }
    
    $actionTooltips = [ordered]@{
        "create" = "Create a new item in Sitecore"
        "update" = "Modify an existing item"
        "delete" = "Remove the item permanently"
        "archive" = "Move the item to archive"
    }
    
    $dialogParams = @{
        Title = "Dropdown Controls"
        Description = "Examples of combo/dropdown selection controls."
        Width = 450
        Height = 350
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedPriority"
                Value = "2"
                Title = "Priority Level"
                Options = $priorityOptions
                Tooltip = "Select the priority for this task"
                Editor = "combo"
            },
            @{
                Name = "selectedAction"
                Value = "update"
                Title = "Action Type"
                Options = $actionOptions
                OptionTooltips = $actionTooltips
                Tooltip = "Choose the action to perform"
                Editor = "combo"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Selected Priority: $selectedPriority" -ForegroundColor Green
        Write-Host "Selected Action: $selectedAction" -ForegroundColor Green
    }
    <#
        .SYNOPSIS
            Demonstrates checklist control for multiple selections in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to create a checklist that allows users to select multiple options.
            The checklist uses bitmask values for selections.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Define options with bitmask values
    # Each value should be a power of 2 for proper bitmask operations
    $daysOfWeek = [ordered]@{
        "Monday" = 1
        "Tuesday" = 2
        "Wednesday" = 4
        "Thursday" = 8
        "Friday" = 16
        "Saturday" = 32
        "Sunday" = 64
    }
    
    # Pre-select some items by providing an array of values
    $selectedDays = @(1, 4, 16)  # Monday, Wednesday, Friday
    
    $languageOptions = [ordered]@{
        "English" = 1
        "German" = 2
        "French" = 4
        "Spanish" = 8
        "Japanese" = 16
    }
    
    $selectedLanguages = @(1)  # English pre-selected
    
    $dialogParams = @{
        Title = "Checklist Controls"
        Description = "Select multiple options using checklists."
        Width = 450
        Height = 450
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedDays"
                Title = "Days of the Week"
                Options = $daysOfWeek
                Tooltip = "Select which days to run the scheduled task"
                Editor = "checklist"
            },
            @{
                Name = "selectedLanguages"
                Title = "Target Languages"
                Options = $languageOptions
                Tooltip = "Select languages for content translation"
                Editor = "checklist"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Selected Days (values): $($selectedDays -join ', ')" -ForegroundColor Green
        Write-Host "Selected Languages (values): $($selectedLanguages -join ', ')" -ForegroundColor Green
    
        # Map values back to display names
        Write-Host "`nSelected Day Names:" -ForegroundColor Cyan
        foreach ($day in $daysOfWeek.GetEnumerator()) {
            if ($selectedDays -contains $day.Value) {
                Write-Host "  - $($day.Key)"
            }
        }
    }
    <#
        .SYNOPSIS
            Demonstrates radio button control for single selection in Read-Variable dialogs.
    
        .DESCRIPTION
            Shows how to create radio button groups that allow users to select exactly one option.
    
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Define options for radio buttons
    $publishMode = [ordered]@{
        "Smart Publish" = 1
        "Incremental Publish" = 2
        "Full Republish" = 3
    }
    
    $targetDatabase = [ordered]@{
        "Web" = "web"
        "Preview" = "preview"
        "Staging" = "staging"
    }
    
    # Pre-select an option
    $selectedPublishMode = 1
    $selectedDatabase = "web"
    
    $dialogParams = @{
        Title = "Radio Button Controls"
        Description = "Select exactly one option from each group."
        Width = 450
        Height = 400
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedPublishMode"
                Title = "Publish Mode"
                Options = $publishMode
                Tooltip = "Choose how content should be published"
                Editor = "radio"
            },
            @{
                Name = "selectedDatabase"
                Title = "Target Database"
                Options = $targetDatabase
                Tooltip = "Select the destination database"
                Editor = "radio"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Selected Publish Mode: $selectedPublishMode" -ForegroundColor Green
        Write-Host "Selected Database: $selectedDatabase" -ForegroundColor Green
    
        # Use the selection in logic
        switch ($selectedPublishMode) {
            1 { Write-Host "`nPerforming Smart Publish..." -ForegroundColor Cyan }
            2 { Write-Host "`nPerforming Incremental Publish..." -ForegroundColor Cyan }
            3 { Write-Host "`nPerforming Full Republish..." -ForegroundColor Cyan }
        }
    }
    <#
        .SYNOPSIS
            Demonstrates date and time picker controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use date-only and date-time picker controls.
            Both return System.DateTime objects.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Set default values
    $startDateTime = [System.DateTime]::Now.AddDays(-7)
    $endDateTime = [System.DateTime]::Now
    $publishDate = [System.DateTime]::Now.AddDays(1)
    
    $dialogParams = @{
        Title = "Date and Time Controls"
        Description = "Select dates and times for your operation."
        Width = 500
        Height = 400
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "startDateTime"
                Value = [System.DateTime]::Now.AddDays(-7)
                Title = "Start Date/Time"
                Tooltip = "Select the starting date and time"
                Editor = "date time"
            },
            @{
                Name = "endDateTime"
                Value = [System.DateTime]::Now
                Title = "End Date/Time"
                Tooltip = "Select the ending date and time"
                Editor = "date time"
            },
            @{
                Name = "publishDate"
                Value = [System.DateTime]::Now.AddDays(1)
                Title = "Publish Date (Date Only)"
                Tooltip = "Select the date for publishing"
                Editor = "date"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Date/Time Controls return System.DateTime objects:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Start DateTime: $startDateTime" -ForegroundColor Green
        Write-Host "  Type: $($startDateTime.GetType().FullName)"
        Write-Host ""
        
        Write-Host "End DateTime: $endDateTime" -ForegroundColor Green
        Write-Host "  Type: $($endDateTime.GetType().FullName)"
        Write-Host ""
        
        Write-Host "Publish Date: $publishDate" -ForegroundColor Green
        Write-Host "  Type: $($publishDate.GetType().FullName)"
        Write-Host ""
        
        # Calculate duration
        $duration = $endDateTime - $startDateTime
        Write-Host "Duration: $($duration.Days) days, $($duration.Hours) hours" -ForegroundColor Yellow
    }
    <#
        .SYNOPSIS
            Demonstrates single item picker control in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use the item picker to select a single Sitecore item.
            Returns a Sitecore Item object.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variables with default Item objects
    # Read-Variable requires item variables to be pre-initialized
    $selectedItem = Get-Item -Path "master:\content\Home"
    $templateItem = Get-Item -Path "master:\templates\System\Templates\Template"
    
    $dialogParams = @{
        Title = "Single Item Picker"
        Description = "Select a single item from the content tree."
        Width = 500
        Height = 350
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedItem"
                Title = "Select Content Item"
                Root = "/sitecore/content/"
                Tooltip = "Browse and select an item from the content tree"
            },
            @{
                Name = "templateItem"
                Title = "Select Template"
                Root = "/sitecore/templates/"
                Tooltip = "Browse and select a template"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Item Picker returns Sitecore Item objects:" -ForegroundColor Cyan
        Write-Host ""
        
        if ($selectedItem) {
            Write-Host "Selected Content Item:" -ForegroundColor Green
            Write-Host "  Name: $($selectedItem.Name)"
            Write-Host "  Path: $($selectedItem.ItemPath)"
            Write-Host "  ID: $($selectedItem.ID)"
            Write-Host "  Template: $($selectedItem.TemplateName)"
        } else {
            Write-Host "No content item selected" -ForegroundColor Yellow
        }
        
        Write-Host ""
        
        if ($templateItem) {
            Write-Host "Selected Template:" -ForegroundColor Green
            Write-Host "  Name: $($templateItem.Name)"
            Write-Host "  Path: $($templateItem.ItemPath)"
            Write-Host "  ID: $($templateItem.ID)"
        } else {
            Write-Host "No template selected" -ForegroundColor Yellow
        }
    }
    <#
        .SYNOPSIS
            Demonstrates treelist control for multiple item selection in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use treelist to select multiple items with a tree-based interface.
            Returns an array of Sitecore Item objects.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize with an array of Item objects (can be empty array or pre-selected items)
    $selectedTemplates = @(Get-Item -Path "master:\templates\System\Templates\Template")
    
    $dialogParams = @{
        Title = "Treelist Control"
        Description = "Select multiple items using the treelist interface."
        Width = 600
        Height = 500
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedTemplates"
                Title = "Select Templates"
                Source = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template"
                Editor = "treelist"
                Tooltip = "Select one or more templates from the tree"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Treelist returns an array of Sitecore Item objects:" -ForegroundColor Cyan
        Write-Host ""
        
        if ($selectedTemplates -and $selectedTemplates.Count -gt 0) {
            Write-Host "Selected $($selectedTemplates.Count) template(s):" -ForegroundColor Green
            Write-Host ""
            
            foreach ($template in $selectedTemplates) {
                Write-Host "  - $($template.Name)" -ForegroundColor White
                Write-Host "    Path: $($template.ItemPath)"
                Write-Host "    ID: $($template.ID)"
                Write-Host ""
            }
        } else {
            Write-Host "No templates selected" -ForegroundColor Yellow
        }
    }
    
    <#
        TREELIST SOURCE PARAMETERS:
        
        The Source parameter uses a query string format with these options:
        
        - DataSource: Root path for the tree (e.g., /sitecore/templates)
        - DatabaseName: Target database (master, web, core)
        - IncludeTemplatesForDisplay: Templates to show in tree (comma-separated)
        - IncludeTemplatesForSelection: Templates that can be selected (comma-separated)
        - ExcludeTemplatesForDisplay: Templates to hide
        - ExcludeTemplatesForSelection: Templates that cannot be selected
        
        Example configurations:
        
        # Select pages under content
        Source = "DataSource=/sitecore/content&DatabaseName=master&IncludeTemplatesForSelection=Page,Article"
        
        # Select media items
        Source = "DataSource=/sitecore/media library&DatabaseName=master&IncludeTemplatesForSelection=Image,Jpeg,Png"
    #>
    <#
        .SYNOPSIS
            Demonstrates multilist control for multiple item selection in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use multilist and multilist search controls.
            Both return arrays of Sitecore Item objects.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $selectedItems = @(Get-Item -Path "master:\templates\System\Templates\Template")
    $searchableItems = @(Get-Item -Path "master:\templates\System\Templates\Standard template")
    
    $dialogParams = @{
        Title = "Multilist Controls"
        Description = "Select multiple items using multilist interfaces."
        Width = 650
        Height = 600
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedItems"
                Title = "Multilist (Standard)"
                Source = "DataSource=/sitecore/templates/System&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template"
                Editor = "multilist"
                Height = "200px"
                Tooltip = "Select items by moving them between lists"
            },
            @{
                Name = "searchableItems"
                Title = "Multilist with Search"
                Source = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template"
                Editor = "multilist search"
                Height = "200px"
                Tooltip = "Search and select items - great for large lists"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Multilist controls return arrays of Sitecore Item objects:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Standard Multilist Selection:" -ForegroundColor Green
        if ($selectedItems -and $selectedItems.Count -gt 0) {
            foreach ($item in $selectedItems) {
                Write-Host "  - $($item.Name) [$($item.ID)]"
            }
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
        
        Write-Host ""
        Write-Host "Multilist Search Selection:" -ForegroundColor Green
        if ($searchableItems -and $searchableItems.Count -gt 0) {
            foreach ($item in $searchableItems) {
                Write-Host "  - $($item.Name) [$($item.ID)]"
            }
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
    }
    
    <#
        MULTILIST vs MULTILIST SEARCH:
        
        Standard Multilist:
        - Shows all available items in a scrollable list
        - Best for smaller datasets (< 100 items)
        - Drag-and-drop interface
        
        Multilist Search:
        - Includes a search box to filter items
        - Best for larger datasets where browsing isn't practical
        - Same selection behavior as standard multilist
        
        Both use the same Source parameter format as treelist.
    #>
    <#
        .SYNOPSIS
            Demonstrates droplist control for single item selection in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use droplist to select a single item from a flat list.
            Returns a Sitecore Item object.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $selectedTemplate = Get-Item -Path "master:\templates\sample\sample item"
    
    $dialogParams = @{
        Title = "Droplist Control"
        Description = "Select a single item from a dropdown list."
        Width = 500
        Height = 300
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedTemplate"
                Title = "Select a Template"
                Source = "DataSource=/sitecore/templates/sample&DatabaseName=master&IncludeTemplatesForDisplay=Template Folder,Template&IncludeTemplatesForSelection=Template"
                Editor = "droplist"
                Tooltip = "Choose a single template from the dropdown"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Droplist returns a single Sitecore Item object:" -ForegroundColor Cyan
        Write-Host ""
        
        if ($selectedTemplate) {
            Write-Host "Selected Template:" -ForegroundColor Green
            Write-Host "  Name: $($selectedTemplate.Name)"
            Write-Host "  Path: $($selectedTemplate.ItemPath)"
            Write-Host "  ID: $($selectedTemplate.ID)"
            Write-Host "  Type: $($selectedTemplate.GetType().FullName)"
        } else {
            Write-Host "No template selected" -ForegroundColor Yellow
        }
    }
    
    <#
        DROPLIST vs COMBO:
        
        Droplist:
        - Displays Sitecore items from a data source
        - Returns a Sitecore Item object
        - Uses Source parameter with DataSource path
        
        Combo:
        - Displays key-value pairs defined in script
        - Returns the value (usually a string or number)
        - Uses Options parameter with hashtable
        
        Use Droplist when you need to select from Sitecore items.
        Use Combo when you need predefined options.
    #>
    <#
        .SYNOPSIS
            Demonstrates grouped dropdown controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use groupeddroplink and groupeddroplist controls.
            These display items grouped by their parent folders.
            - groupeddroplink: Returns the selected Item object
            - groupeddroplist: Returns the item's string value (path or ID)
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "Grouped Dropdown Controls"
        Description = "Select items from grouped dropdown lists."
        Width = 550
        Height = 350
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedGroupedDroplink"
                Title = "Grouped Droplink (Returns Item)"
                Source = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template"
                Editor = "groupeddroplink"
                Tooltip = "Items grouped by folder - returns Item object"
            },
            @{
                Name = "selectedGroupedDroplist"
                Title = "Grouped Droplist (Returns String)"
                Source = "DataSource=/sitecore/templates&DatabaseName=master&IncludeTemplatesForDisplay=Node,Folder,Template,Template Folder&IncludeTemplatesForSelection=Template"
                Editor = "groupeddroplist"
                Tooltip = "Items grouped by folder - returns string value"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Grouped Dropdown Controls:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Grouped Droplink (returns Item):" -ForegroundColor Green
        if ($selectedGroupedDroplink) {
            Write-Host "  Name: $($selectedGroupedDroplink.Name)"
            Write-Host "  Path: $($selectedGroupedDroplink.ItemPath)"
            Write-Host "  Type: $($selectedGroupedDroplink.GetType().Name)"
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
        
        Write-Host ""
        Write-Host "Grouped Droplist (returns String):" -ForegroundColor Green
        if ($selectedGroupedDroplist) {
            Write-Host "  Value: $selectedGroupedDroplist"
            Write-Host "  Type: $($selectedGroupedDroplist.GetType().Name)"
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
    }
    
    <#
        GROUPED DROPDOWNS:
        
        Both groupeddroplink and groupeddroplist display items organized
        by their parent folders, making it easier to navigate large item sets.
        
        Key Difference:
        - groupeddroplink: Returns the actual Sitecore Item object
        - groupeddroplist: Returns a string representation
        
        Use groupeddroplink when you need to work with the Item object.
        Use groupeddroplist when you only need the item's path or ID.
    #>
    <#
        .SYNOPSIS
            Demonstrates user and role picker controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use user, role, and combined user/role selection controls.
            These are essential for security and permission-related scripts.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "User and Role Pickers"
        Description = "Select users and roles for permission management."
        Width = 550
        Height = 450
        OkButtonName = "Select"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "selectedUser"
                Title = "Select User(s)"
                Editor = "user multiple"
                Tooltip = "Select one or more users"
            },
            @{
                Name = "selectedRole"
                Title = "Select Role(s)"
                Editor = "role multiple"
                Domain = "sitecore"
                Tooltip = "Select one or more roles from the sitecore domain"
            },
            @{
                Name = "selectedUserOrRole"
                Title = "Select User(s) or Role(s)"
                Editor = "user role multiple"
                Domain = "sitecore"
                Tooltip = "Select any combination of users and roles"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "User and Role Pickers return string values:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Selected Users:" -ForegroundColor Green
        if ($selectedUser) {
            $selectedUser | ForEach-Object { Write-Host "  - $_" }
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
        
        Write-Host ""
        Write-Host "Selected Roles:" -ForegroundColor Green
        if ($selectedRole) {
            $selectedRole | ForEach-Object { Write-Host "  - $_" }
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
        
        Write-Host ""
        Write-Host "Selected Users or Roles:" -ForegroundColor Green
        if ($selectedUserOrRole) {
            $selectedUserOrRole | ForEach-Object { Write-Host "  - $_" }
        } else {
            Write-Host "  (none selected)" -ForegroundColor Yellow
        }
    }
    
    <#
        USER AND ROLE EDITOR VARIANTS:
        
        Single Selection:
        - "user"      : Select one user
        - "role"      : Select one role
        - "user role" : Select one user or role
        
        Multiple Selection:
        - "user multiple"      : Select multiple users
        - "role multiple"      : Select multiple roles
        - "user role multiple" : Select multiple users and/or roles
        
        Domain Parameter:
        The Domain parameter filters roles to a specific security domain.
        Common domains: "sitecore", "extranet", custom domains
        
        Return Values:
        - Single selection returns a string
        - Multiple selection returns an array of strings
        - Format: "domain\username" or "domain\rolename"
    #>
    <#
        .SYNOPSIS
            Demonstrates rule editor controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use rule and rule action editors for creating 
            Sitecore rules with conditions and actions.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # You can pre-populate with an existing rule
    # Get a sample rule from an existing item
    $existingRule = $null
    $ruleItem = Get-Item -Path "master:" -ID "{D00BD134-EB15-41A7-BEF1-E6455C6BC9AC}" -ErrorAction SilentlyContinue
    if ($ruleItem) {
        $existingRule = $ruleItem | Select-Object -ExpandProperty ShowRule -ErrorAction SilentlyContinue
    }
    
    $dialogParams = @{
        Title = "Rule Editor Controls"
        Description = "Create rules with conditions and optional actions."
        Width = 700
        Height = 500
        OkButtonName = "Save Rules"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "conditionRule"
                Title = "Condition Rule"
                Editor = "rule"
                Tooltip = "Define conditions only (no actions)"
            },
            @{
                Name = "actionRule"
                Title = "Rule with Actions"
                Editor = "rule action"
                Tooltip = "Define conditions and actions to execute"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Rule Editors return XML string values:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Condition Rule:" -ForegroundColor Green
        if ($conditionRule) {
            Write-Host "  Length: $($conditionRule.Length) characters"
            Write-Host "  Preview: $($conditionRule.Substring(0, [Math]::Min(100, $conditionRule.Length)))..."
        } else {
            Write-Host "  (no rule defined)" -ForegroundColor Yellow
        }
        
        Write-Host ""
        Write-Host "Rule with Actions:" -ForegroundColor Green
        if ($actionRule) {
            Write-Host "  Length: $($actionRule.Length) characters"
            Write-Host "  Preview: $($actionRule.Substring(0, [Math]::Min(100, $actionRule.Length)))..."
        } else {
            Write-Host "  (no rule defined)" -ForegroundColor Yellow
        }
    }
    
    <#
        RULE EDITOR TYPES:
        
        "rule" Editor:
        - Conditions only (WHERE clauses)
        - Use for filtering, visibility rules, validation
        - Example: Show field when template is X
        
        "rule action" Editor:
        - Conditions AND actions
        - Use for automation, workflows, scheduled tasks
        - Example: When item is created, set default values
        
        Return Value:
        Both editors return an XML string representing the rule definition.
        This XML can be stored in a rule field or parsed for processing.
        
        Common Use Cases:
        - Content validation rules
        - Conditional rendering rules
        - Workflow state transitions
        - Scheduled task filters
        - Personalization conditions
    #>
    <#
        .SYNOPSIS
            Demonstrates information display controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to use info and marquee controls to display 
            read-only information and messages to users.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "Information Display Controls"
        Description = "Display important information to users."
        Width = 550
        Height = 400
        OkButtonName = "Continue"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "marqueeMessage"
                Title = "Marquee - Scrolling Message"
                Value = "This is an important scrolling message that catches attention!"
                Editor = "marquee"
            },
            @{
                Name = "infoMessage"
                Title = "Info - Static Information"
                Value = "This is static informational text that provides context or instructions to the user. It does not scroll and is easier to read for longer messages."
                Editor = "info"
            },
            @{
                Name = "userInput"
                Title = "Your Response"
                Value = ""
                Tooltip = "Enter your response after reading the information above"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "User acknowledged the information and provided:" -ForegroundColor Cyan
        Write-Host "Response: $userInput" -ForegroundColor Green
    }
    
    <#
        DISPLAY CONTROLS (Read-Only):
        
        "marquee" Editor:
        - Displays scrolling text
        - Good for alerts or important notices
        - Catches user attention with animation
        
        "info" Editor:
        - Displays static text
        - Good for instructions, context, or longer messages
        - No animation, easier to read
        
        Common Use Cases:
        - Display warnings before destructive operations
        - Show instructions for complex forms
        - Provide context about selected items
        - Display calculated values or status information
        
        Note: These are display-only controls. The Value is shown
        but not returned or modified by user interaction.
    #>
    <#
        .SYNOPSIS
            Demonstrates variable binding in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to bind existing PowerShell variables to dialog controls
            using the Variable parameter instead of Name/Value.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Get an existing item to use as a variable
    $parentItem = Get-Item -Path "master:\content\Home" -ErrorAction SilentlyContinue
    if (-not $parentItem) {
        $parentItem = Get-Item -Path "master:\content" -ErrorAction SilentlyContinue
    }
    
    # Define other variables
    $searchQuery = "sample query"
    $maxResults = 50
    
    $dialogParams = @{
        Title = "Variable Binding Example"
        Description = "Bind existing variables directly to dialog controls."
        Width = 500
        Height = 400
        OkButtonName = "Process"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                # Use Variable instead of Name to bind directly to existing variable
                Variable = Get-Variable "parentItem"
                Title = "Parent Item (Variable Binding)"
                Tooltip = "This control is bound to the `$parentItem variable"
            },
            @{
                Variable = Get-Variable "searchQuery"
                Title = "Search Query (Variable Binding)"
                Tooltip = "Bound to `$searchQuery variable"
            },
            @{
                Variable = Get-Variable "maxResults"
                Title = "Max Results (Variable Binding)"
                Editor = "number"
                Tooltip = "Bound to `$maxResults variable"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Variable Binding Results:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Parent Item:" -ForegroundColor Green
        if ($parentItem) {
            Write-Host "  Name: $($parentItem.Name)"
            Write-Host "  Path: $($parentItem.ItemPath)"
        }
        
        Write-Host ""
        Write-Host "Search Query: $searchQuery" -ForegroundColor Green
        Write-Host "Max Results: $maxResults" -ForegroundColor Green
    }
    
    <#
        VARIABLE BINDING vs NAME/VALUE:
        
        Name/Value Approach:
        - Creates a new variable with the specified Name
        - Initial value set with Value parameter
        @{ Name = "myVar"; Value = "initial" }
        
        Variable Binding:
        - Binds directly to an existing PowerShell variable
        - Use Get-Variable to reference the variable
        - Variable is updated in-place when dialog closes
        @{ Variable = Get-Variable "existingVar" }
        
        When to Use Variable Binding:
        - When you already have variables with values from previous operations
        - When you want to modify existing context variables
        - When working with items from the current context (like $item)
        
        Benefits:
        - Less boilerplate code
        - Variables retain their type information
        - Direct modification of existing state
    #>
    <#
        .SYNOPSIS
            Demonstrates tabbed dialogs in Read-Variable.
        
        .DESCRIPTION
            Shows how to organize controls into multiple tabs for complex dialogs.
            Use the Tab parameter to assign controls to specific tabs.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $template = Get-Item -Path "master:\templates\sample\sample item"
    
    $dialogParams = @{
        Title = "Tabbed Dialog Example"
        Description = "Controls organized into logical tabs."
        Width = 600
        Height = 500
        OkButtonName = "Save"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            # General Tab
            @{
                Name = "itemName"
                Title = "Item Name"
                Value = ""
                Tooltip = "Enter the name for the new item"
                Tab = "General"
                Placeholder = "Enter name..."
            },
            @{
                Name = "itemTitle"
                Title = "Display Title"
                Value = ""
                Tooltip = "The title shown to users"
                Tab = "General"
                Placeholder = "Enter title..."
            },
            @{
                Name = "description"
                Title = "Description"
                Value = ""
                Lines = 3
                Tooltip = "Describe this item"
                Tab = "General"
            },
            
            # Settings Tab
            @{
                Name = "isActive"
                Title = "Active"
                Value = $true
                Editor = "checkbox"
                Tooltip = "Enable or disable this item"
                Tab = "Settings"
            },
            @{
                Name = "priority"
                Title = "Priority"
                Value = 100
                Editor = "number"
                Tooltip = "Sort order priority"
                Tab = "Settings"
            },
            @{
                Name = "publishDate"
                Title = "Publish Date"
                Value = [DateTime]::Now
                Editor = "date time"
                Tooltip = "When to publish"
                Tab = "Settings"
            },
            
            # Advanced Tab
            @{
                Name = "template"
                Title = "Template"
                Root = "/sitecore/templates/"
                Tooltip = "Select a template"
                Tab = "Advanced"
            },
            @{
                Name = "targetUser"
                Title = "Owner"
                Editor = "user"
                Tooltip = "Select the owner"
                Tab = "Advanced"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Tabbed Dialog Results:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "General Tab:" -ForegroundColor Green
        Write-Host "  Item Name: $itemName"
        Write-Host "  Title: $itemTitle"
        Write-Host "  Description: $description"
        
        Write-Host ""
        Write-Host "Settings Tab:" -ForegroundColor Green
        Write-Host "  Active: $isActive"
        Write-Host "  Priority: $priority"
        Write-Host "  Publish Date: $publishDate"
        
        Write-Host ""
        Write-Host "Advanced Tab:" -ForegroundColor Green
        Write-Host "  Template: $($template.Name)"
        Write-Host "  Owner: $targetUser"
    }
    
    <#
        TAB ORGANIZATION:
        
        Use the Tab parameter to organize controls:
        @{ Name = "field"; Tab = "Tab Name" }
        
        Tips:
        - Tabs appear in the order of their first control
        - Group related controls on the same tab
        - Use clear, concise tab names
        - Limit to 4-5 tabs maximum for usability
        
        Common Tab Patterns:
        - "General" / "Settings" / "Advanced"
        - "Content" / "Metadata" / "Publishing"
        - "Source" / "Target" / "Options"
        - "Basic" / "Security" / "Workflow"
    #>
    <#
        .SYNOPSIS
            Demonstrates conditional visibility of controls in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to show/hide controls based on other control values using
            GroupId, ParentGroupId, and HideOnValue parameters.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Define options for the controlling dropdown
    $modeOptions = [ordered]@{
        "Simple Mode" = "simple"
        "Advanced Mode" = "advanced"
        "Expert Mode" = "expert"
    }
    
    $dialogParams = @{
        Title = "Conditional Visibility Example"
        Description = "Controls appear/disappear based on your selection."
        Width = 550
        Height = 450
        OkButtonName = "Continue"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            # Checkbox controlling visibility
            @{
                Name = "showAdvanced"
                Title = "Show Advanced Options"
                Value = $true
                Editor = "checkbox"
                Tooltip = "Toggle to show/hide advanced options"
                GroupId = 1  # This control is the "parent" group
            },
            @{
                Name = "advancedOption1"
                Title = "Advanced Option 1"
                Value = ""
                Tooltip = "This field shows when checkbox is checked"
                ParentGroupId = 1  # Linked to group 1
                HideOnValue = "0"  # Hide when checkbox value is 0 (unchecked)
            },
            @{
                Name = "advancedOption2"
                Title = "Advanced Option 2"
                Value = ""
                Tooltip = "This field also shows when checkbox is checked"
                ParentGroupId = 1
                HideOnValue = "0"
            },
            
            # Dropdown controlling visibility
            @{
                Name = "operationMode"
                Title = "Operation Mode"
                Value = "simple"
                Options = $modeOptions
                Editor = "combo"
                Tooltip = "Select mode to see different options"
                GroupId = 2  # This dropdown controls group 2
            },
            @{
                Name = "simpleField"
                Title = "Simple Mode Field"
                Value = ""
                Tooltip = "Visible only in Simple Mode"
                ParentGroupId = 2
                ShowOnValue = "simple"  # Hidden when advanced or expert selected
            },
            @{
                Name = "advancedField"
                Title = "Advanced Mode Field"
                Value = ""
                Tooltip = "Visible only in Advanced Mode"
                ParentGroupId = 2
                ShowOnValue = "advanced"  # Hidden when simple or expert selected
            },
            @{
                Name = "expertField"
                Title = "Expert Mode Field"
                Value = ""
                Tooltip = "Visible only in Expert Mode"
                ParentGroupId = 2
                ShowOnValue = "expert"  # Hidden when simple or advanced selected
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Conditional Visibility Results:" -ForegroundColor Cyan
        Write-Host ""
        
        Write-Host "Show Advanced: $showAdvanced" -ForegroundColor Green
        if ($showAdvanced) {
            Write-Host "  Advanced Option 1: $advancedOption1"
            Write-Host "  Advanced Option 2: $advancedOption2"
        }
        
        Write-Host ""
        Write-Host "Operation Mode: $operationMode" -ForegroundColor Green
        switch ($operationMode) {
            "simple" { Write-Host "  Simple Field: $simpleField" }
            "advanced" { Write-Host "  Advanced Field: $advancedField" }
            "expert" { Write-Host "  Expert Field: $expertField" }
        }
    }
    
    <#
        CONDITIONAL VISIBILITY PARAMETERS:
        
        GroupId:
        - Assigns a numeric ID to a "controlling" control
        - This control's value determines visibility of child controls
        
        ParentGroupId:
        - Links a control to a parent group
        - This control's visibility depends on the parent's value
        
        HideOnValue:
        - Specifies which parent values hide this control
        - For checkboxes: "0" = unchecked, "1" = checked
        - For combos/radios: Use the option values (not display text)
        - Multiple values: Comma-separated list
        
        Common Patterns:
        
        1. Checkbox Toggle:
           Parent: @{ Editor="checkbox"; GroupId=1 }
           Child:  @{ ParentGroupId=1; HideOnValue="0" }  # Show when checked
           Child:  @{ ParentGroupId=1; HideOnValue="1" }  # Show when unchecked
        
        2. Dropdown Selection:
           Parent: @{ Editor="combo"; Options=$opts; GroupId=2 }
           Child:  @{ ParentGroupId=2; HideOnValue="optionA,optionB" }
        
        3. Radio Selection:
           Parent: @{ Editor="radio"; Options=$opts; GroupId=3 }
           Child:  @{ ParentGroupId=3; HideOnValue="1,2" }  # Hide for values 1 and 2
    #>
    <#
        .SYNOPSIS
            Demonstrates column layout in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to arrange controls in columns using the Columns parameter.
            The dialog uses a 12-column grid system.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        Title = "Column Layout Example"
        Description = "Controls arranged in a responsive grid layout."
        Width = 650
        Height = 500
        OkButtonName = "Save"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            # Full width (12 columns - default)
            @{
                Name = "fullWidthField"
                Title = "Full Width Field (12 columns)"
                Value = ""
                Tooltip = "This field spans the full width"
                # Columns = 12 is the default
            },
            
            # Two columns side by side (6 + 6)
            @{
                Name = "firstName"
                Title = "First Name"
                Value = ""
                Tooltip = "Half width"
                Columns = 6
            },
            @{
                Name = "lastName"
                Title = "Last Name"
                Value = ""
                Tooltip = "Half width"
                Columns = 6
            },
            
            # Three columns (4 + 4 + 4)
            @{
                Name = "city"
                Title = "City"
                Value = ""
                Tooltip = "One third width"
                Columns = 4
            },
            @{
                Name = "state"
                Title = "State"
                Value = ""
                Tooltip = "One third width"
                Columns = 4
            },
            @{
                Name = "zip"
                Title = "ZIP Code"
                Value = ""
                Tooltip = "One third width"
                Columns = 4
            },
            
            # Unequal columns (8 + 4)
            @{
                Name = "email"
                Title = "Email Address"
                Value = ""
                Tooltip = "Two thirds width"
                Columns = 8
            },
            @{
                Name = "extension"
                Title = "Ext"
                Value = ""
                Tooltip = "One third width"
                Columns = 4
            },
            
            # Mixed with checkbox (small column)
            @{
                Name = "notes"
                Title = "Additional Notes"
                Value = ""
                Lines = 2
                Tooltip = "Main content area"
                Columns = 9
            },
            @{
                Name = "isUrgent"
                Title = "Urgent"
                Value = $false
                Editor = "checkbox"
                Tooltip = "Mark as urgent"
                Columns = 3
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Column Layout Results:" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "Full Width: $fullWidthField" -ForegroundColor Green
        Write-Host "Name: $firstName $lastName" -ForegroundColor Green
        Write-Host "Location: $city, $state $zip" -ForegroundColor Green
        Write-Host "Email: $email (ext: $extension)" -ForegroundColor Green
        Write-Host "Notes: $notes" -ForegroundColor Green
        Write-Host "Urgent: $isUrgent" -ForegroundColor Green
    }
    
    <#
        COLUMN LAYOUT (12-Column Grid):
        
        The Columns parameter uses a 12-column grid system:
        
        Full Width:    Columns = 12 (default)
        Half Width:    Columns = 6
        Third Width:   Columns = 4
        Quarter Width: Columns = 3
        Two-Thirds:    Columns = 8
        
        Common Patterns:
        
        Two Equal Columns:
        @{ Columns = 6 }, @{ Columns = 6 }
        
        Three Equal Columns:
        @{ Columns = 4 }, @{ Columns = 4 }, @{ Columns = 4 }
        
        Main + Sidebar:
        @{ Columns = 8 }, @{ Columns = 4 }
        
        Four Equal Columns:
        @{ Columns = 3 }, @{ Columns = 3 }, @{ Columns = 3 }, @{ Columns = 3 }
        
        Tips:
        - Column values should add up to 12 for a complete row
        - Controls wrap to next row automatically
        - Combine with tabs for complex layouts
        - Consider dialog width when using many columns
    #>
    <#
        .SYNOPSIS
            Demonstrates mandatory fields and validation in Read-Variable dialogs.
        
        .DESCRIPTION
            Shows how to mark fields as required using the Mandatory parameter.
            Required fields must have a value before the dialog can be submitted.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $requiredItem = Get-Item -Path "master:\content\home"
    
    $dialogParams = @{
        Title = "Required Fields Example"
        Description = "Fields marked with * are required."
        Width = 500
        Height = 400
        OkButtonName = "Submit"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            @{
                Name = "requiredField"
                Title = "Required Text Field"
                Value = ""
                Tooltip = "This field must be filled in"
                Placeholder = "This field is required..."
                Mandatory = $true
            },
            @{
                Name = "optionalField"
                Title = "Optional Text Field"
                Value = ""
                Tooltip = "This field is optional"
                Placeholder = "This field is optional..."
                Mandatory = $false
            },
            @{
                Name = "requiredNumber"
                Title = "Required Number"
                Value = $null
                Editor = "number"
                Tooltip = "A number must be entered"
                Mandatory = $true
            },
            @{
                Name = "requiredItem"
                Title = "Required Item Selection"
                Root = "/sitecore/content/"
                Tooltip = "An item must be selected"
                Mandatory = $true
            },
            @{
                Name = "optionalMultiline"
                Title = "Optional Notes"
                Value = ""
                Lines = 3
                Tooltip = "Additional notes (optional)"
                Mandatory = $false
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Form submitted successfully!" -ForegroundColor Cyan
        Write-Host ""
        Write-Host "Required Field: $requiredField" -ForegroundColor Green
        Write-Host "Optional Field: $optionalField" -ForegroundColor Green
        Write-Host "Required Number: $requiredNumber" -ForegroundColor Green
        
        if ($requiredItem) {
            Write-Host "Required Item: $($requiredItem.Name)" -ForegroundColor Green
        }
        
        Write-Host "Optional Notes: $optionalMultiline" -ForegroundColor Green
    } else {
        Write-Host "Dialog was cancelled" -ForegroundColor Yellow
    }
    
    <#
        MANDATORY FIELDS:
        
        The Mandatory parameter enforces that a field has a value:
        @{ Name = "field"; Mandatory = $true }
        
        Behavior:
        - Required fields show an asterisk (*) in the label
        - Dialog cannot be submitted until all required fields have values
        - An error message appears if user tries to submit with empty required fields
        - Default is Mandatory = $false
        
        Supported Field Types:
        - Text fields (single and multi-line)
        - Number fields
        - Item pickers
        - User/Role selectors
        - Dropdowns and lists
        - Date/time fields
        
        Notes:
        - Checkboxes don't support Mandatory (they always have a value)
        - For item pickers, the user must select an item
        - Empty strings "" are considered invalid for mandatory text fields
        - Consider using Placeholder text to guide users on required fields
    #>
    <#
        .SYNOPSIS
            Demonstrates dialog customization options in Read-Variable.
        
        .DESCRIPTION
            Shows how to customize dialog appearance including title, description,
            icon, dimensions, button labels, and hint display.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    $dialogParams = @{
        # Dialog Title - appears in the title bar
        Title = "Custom Dialog Example"
        
        # Description - appears below the title
        Description = "This dialog demonstrates all available customization options for Read-Variable dialogs."
        
        # Icon - Sitecore icon path (various icon sets available)
        Icon = "Office/32x32/coffee.png"
        
        # Dimensions
        Width = 550
        Height = 400
        
        # Button Labels
        OkButtonName = "Process Items"
        CancelButtonName = "Abort"
        
        # Show tooltips for controls
        ShowHints = $true
        
        # Controls
        Parameters = @(
            @{
                Name = "inputText"
                Title = "Sample Input"
                Value = ""
                Tooltip = "This tooltip appears when ShowHints is enabled"
                Placeholder = "Enter something..."
            },
            @{
                Name = "confirm"
                Title = "I understand the implications"
                Value = $false
                Editor = "checkbox"
                Tooltip = "Check to confirm"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -eq "ok") {
        Write-Host "Dialog completed with custom settings!" -ForegroundColor Green
        Write-Host "Input: $inputText"
        Write-Host "Confirmed: $confirm"
    } else {
        Write-Host "User clicked the custom cancel button" -ForegroundColor Yellow
    }
    
    <#
        DIALOG CUSTOMIZATION OPTIONS:
        
        Title (string):
        - Text shown in the dialog title bar
        - Keep concise but descriptive
        
        Description (string):
        - Explanatory text below the title
        - Use for instructions or context
        - Can span multiple lines
        
        Icon (string):
        - Sitecore icon path
        - Format: "IconSet/Size/iconname.png"
        - Common sets: Office, Business, Software, People, Officewhite
        - Sizes: 16x16, 24x24, 32x32, 48x48
        - Examples:
          - "Office/32x32/document.png"
          - "Business/32x32/users.png"
          - "Software/32x32/gear.png"
          - "Officewhite/32x32/knife_fork_spoon.png"
        
        Width / Height (integer):
        - Dialog dimensions in pixels
        - Minimum recommended: 400x300
        - Default: 500x500 approximately
        
        OkButtonName (string):
        - Custom label for the OK/Submit button
        - Examples: "Continue", "Process", "Save", "Apply"
        
        CancelButtonName (string):
        - Custom label for the Cancel button
        - Examples: "Abort", "Skip", "Close", "Back"
        
        ShowHints (boolean):
        - When true, tooltips appear for controls with Tooltip set
        - Recommended: $true for complex dialogs
        
        Return Values:
        - "ok" - User clicked the OK button
        - "cancel" - User clicked Cancel or closed the dialog
    #>
    <#
        .SYNOPSIS
            Demonstrates a simple dialog without tabs in Read-Variable.
        
        .DESCRIPTION
            Shows how to create a straightforward dialog for common operations
            without using tabs or complex layouts.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $targetItem = Get-Item -Path "master:\content\home"
    
    $dialogParams = @{
        Title = "Simple Dialog Example"
        Description = "A straightforward dialog for quick data collection."
        Width = 500
        Height = 450
        OkButtonName = "Finish"
        CancelButtonName = "Cancel"
        Parameters = @(
            @{ 
                Name = "inputText"
                Value = "Some Text"
                Title = "Single Line Text"
                Tooltip = "Enter a single line of text"
                Placeholder = "Enter text here..."
            },
            @{ 
                Name = "multiLineText"
                Value = "Multiple lines\nof text"
                Title = "Multi Line Text"
                Lines = 3
                Tooltip = "Enter multiple lines"
                Placeholder = "Enter detailed text..."
            },
            @{ 
                Name = "startDate"
                Value = [System.DateTime]::Now.AddDays(-5)
                Title = "Start Date"
                Tooltip = "Select a start date"
                Editor = "date time"
            },
            @{ 
                Name = "selectedUser"
                Value = ""
                Title = "Select User"
                Tooltip = "Choose a user for this operation"
                Editor = "user multiple"
            },
            @{ 
                Name = "targetItem"
                Title = "Target Item"
                Root = "/sitecore/content/"
                Tooltip = "Select the target location"
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -ne "ok") {
        Write-Host "Operation cancelled by user" -ForegroundColor Yellow
        Exit
    }
    
    # Process the collected data
    Write-Host "Dialog Results:" -ForegroundColor Cyan
    Write-Host ""
    Write-Host "Text: $inputText" -ForegroundColor Green
    Write-Host "Multi-line: $multiLineText" -ForegroundColor Green
    Write-Host "Start Date: $startDate" -ForegroundColor Green
    Write-Host "User: $selectedUser" -ForegroundColor Green
    
    if ($targetItem) {
        Write-Host "Target Item: $($targetItem.ItemPath)" -ForegroundColor Green
    }
    
    <#
        SIMPLE DIALOG PATTERN:
        
        For many scripts, a simple dialog without tabs is sufficient.
        This pattern is ideal when you have:
        - 5-8 related fields
        - A single, focused task
        - No need for complex organization
        
        Best Practices:
        1. Order fields logically (most important first)
        2. Use clear, descriptive titles
        3. Provide helpful tooltips
        4. Use placeholder text for text inputs
        5. Set sensible default values
        6. Keep the dialog focused on one task
        
        When to Use Tabs Instead:
        - More than 8-10 fields
        - Fields can be grouped into logical categories
        - Complex operations with multiple phases
        - Advanced options that most users won't need
    #>
    <#
        .SYNOPSIS
            Comprehensive example combining multiple dialog features.
        
        .DESCRIPTION
            Demonstrates how to combine tabs, columns, conditional visibility,
            and various control types in a real-world scenario.
        
        .NOTES
            Documentation: https://doc.sitecorepowershell.com
    #>
    
    # Initialize item variable - required for item picker
    $sourceItem = Get-Item -Path "master:\content\home"
    
    # Pre-define some default values
    $publishModes = [ordered]@{
        "Smart Publish" = "smart"
        "Republish" = "republish"
        "Incremental" = "incremental"
    }
    
    $targetDatabases = [ordered]@{
        "Web" = 1
        "Preview" = 2
    }
    
    $languageOptions = [ordered]@{
        "English" = 1
        "German" = 2
        "French" = 4
        "Spanish" = 8
    }
    
    $selectedLanguages = @(1)  # English pre-selected
    
    # Build the dialog parameters
    $dialogParams = @{
        Title = "Content Publishing Wizard"
        Description = "Configure and execute content publishing operations."
        Icon = "Office/32x32/document_up.png"
        Width = 650
        Height = 600
        OkButtonName = "Publish"
        CancelButtonName = "Cancel"
        ShowHints = $true
        Parameters = @(
            # === SOURCE TAB ===
            @{
                Name = "sourceItem"
                Title = "Source Item"
                Root = "/sitecore/content/"
                Tooltip = "Select the root item to publish"
                Tab = "Source"
                Mandatory = $true
            },
            @{
                Name = "includeSubitems"
                Title = "Include Subitems"
                Value = $true
                Editor = "checkbox"
                Tooltip = "Publish all descendant items"
                Tab = "Source"
                Columns = 6
            },
            @{
                Name = "includeRelated"
                Title = "Include Related Items"
                Value = $false
                Editor = "checkbox"
                Tooltip = "Also publish referenced items"
                Tab = "Source"
                Columns = 6
            },
            
            # === TARGETS TAB ===
            @{
                Name = "targetDbs"
                Title = "Target Databases"
                Options = $targetDatabases
                Editor = "checklist"
                Tooltip = "Select destination databases"
                Tab = "Targets"
            },
            @{
                Name = "selectedLanguages"
                Title = "Languages"
                Options = $languageOptions
                Editor = "checklist"
                Tooltip = "Select languages to publish"
                Tab = "Targets"
            },
            
            # === OPTIONS TAB ===
            @{
                Name = "publishMode"
                Title = "Publish Mode"
                Value = "smart"
                Options = $publishModes
                Editor = "radio"
                Tooltip = "Select publishing mode"
                Tab = "Options"
            },
            @{
                Name = "schedulePublish"
                Title = "Schedule for Later"
                Value = $false
                Editor = "checkbox"
                Tooltip = "Check to schedule publication"
                Tab = "Options"
                GroupId = 1
            },
            @{
                Name = "scheduledTime"
                Title = "Scheduled Time"
                Value = [DateTime]::Now.AddHours(1)
                Editor = "date time"
                Tooltip = "When to publish"
                Tab = "Options"
                ParentGroupId = 1
                HideOnValue = "0"
            },
            
            # === NOTIFICATIONS TAB ===
            @{
                Name = "sendNotification"
                Title = "Send Notification"
                Value = $false
                Editor = "checkbox"
                Tooltip = "Notify users when complete"
                Tab = "Notifications"
                GroupId = 2
            },
            @{
                Name = "notifyUsers"
                Title = "Notify Users"
                Editor = "user multiple"
                Tooltip = "Select users to notify"
                Tab = "Notifications"
                ParentGroupId = 2
                HideOnValue = "0"
            },
            @{
                Name = "notifyRoles"
                Title = "Notify Roles"
                Editor = "role multiple"
                Domain = "sitecore"
                Tooltip = "Select roles to notify"
                Tab = "Notifications"
                ParentGroupId = 2
                HideOnValue = "0"
            },
            @{
                Name = "notificationMessage"
                Title = "Custom Message"
                Value = ""
                Lines = 3
                Tooltip = "Add a custom message to the notification"
                Tab = "Notifications"
                ParentGroupId = 2
                HideOnValue = "0"
                Placeholder = "Optional message to include..."
            }
        )
    }
    
    $result = Read-Variable @dialogParams
    
    if ($result -ne "ok") {
        Write-Host "Publishing cancelled by user" -ForegroundColor Yellow
        Exit
    }
    
    # Display collected settings
    Write-Host ("=" * 50) -ForegroundColor Cyan
    Write-Host "PUBLISHING CONFIGURATION" -ForegroundColor Cyan
    Write-Host ("=" * 50) -ForegroundColor Cyan
    Write-Host ""
    
    Write-Host "SOURCE:" -ForegroundColor Green
    Write-Host "  Item: $($sourceItem.ItemPath)"
    Write-Host "  Include Subitems: $includeSubitems"
    Write-Host "  Include Related: $includeRelated"
    Write-Host ""
    
    Write-Host "TARGETS:" -ForegroundColor Green
    Write-Host "  Databases: $($targetDbs -join ', ')"
    Write-Host "  Languages: $($selectedLanguages -join ', ')"
    Write-Host ""
    
    Write-Host "OPTIONS:" -ForegroundColor Green
    Write-Host "  Mode: $publishMode"
    if ($schedulePublish) {
        Write-Host "  Scheduled: $scheduledTime"
    } else {
        Write-Host "  Scheduled: Immediate"
    }
    Write-Host ""
    
    if ($sendNotification) {
        Write-Host "NOTIFICATIONS:" -ForegroundColor Green
        Write-Host "  Users: $($notifyUsers -join ', ')"
        Write-Host "  Roles: $($notifyRoles -join ', ')"
        if ($notificationMessage) {
            Write-Host "  Message: $notificationMessage"
        }
    }
    
    Write-Host ""
    Write-Host "Ready to execute publishing operation!" -ForegroundColor Yellow