# Introduction

![Sitecore PowerShell Extensions](/files/-LA37UOkGpBBG-He5WQE)

## About the Module

The [Sitecore PowerShell Extensions](https://github.com/SitecorePowerShell/Console) (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.

{% hint style="info" %}
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](https://github.com/SitecorePowerShell/Book).
{% endhint %}

{% hint style="warning" %}
Support for Sitecore 7 has discontinued with SPE 5.0. Check the [appendix](/appendix) for version compatibility.
{% endhint %}

## Development Team

* [Adam Najmanowicz](https://blog.najmanowicz.com/) | [@adamnaj](https://twitter.com/adamnaj)
* [Michael West](https://michaellwest.blogspot.com/) | [@michaelwest101](https://twitter.com/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 [Pester](https://github.com/pester/Pester) to test your scripts
* **Extensions**
  * [Authorable Reports](/modules/integration-points/reports/authoring-reports) - reports based on the Sitecore Rules Engine.
    * [Index Viewer](/modules/integration-points/toolbox) - similar to the Luke tool
* **Maintenance**
  * Index On Demand
  * Media Library Maintenance
  * System Maintenance
  * Task Management
    * [Scheduled Task Manager](/modules/integration-points/toolbox)
* **Reporting**
  * [Content Reports](/modules/integration-points/reports) - variety of reports to help audit the Sitecore solution.
* **Samples**
  * Automatically show quick info section
  * Enforce user password expiration
  * Example Event Handlers
  * Getting Started - includes the Kitchen Sink Demo for `Read-Variable`.
  * License Expiration
  * Random desktop background
  * Training Modules
  * Unlock user items on logout
* **Tools**
  * Authoring Instrumentation
  * Copy Renderings
  * Data Management
    * 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
* **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](https://twitter.com/adeneys) - Sitecore Symposium 2012

> Recommended by [John West](https://twitter.com/sitecorejohn) to use as a tool for [maximizing Sitecore developer productivity](https://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2015/02/maximize-sitecore-developer-productivity.aspx).

> *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](https://marketplace.sitecore.net/Modules/Sitecore_PowerShell_console.aspx)'s comment on Marketplace

> *Thank you for the GitBook. Invaluable Reference.* - [Nick Wesselman](https://twitter.com/techphoria414)'s [tweet](https://twitter.com/techphoria414/status/632033887632289792)

> *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](https://twitter.com/RehbellOne) [tweet](https://twitter.com/RehbellOne/status/1058048820435607552)

> *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* :smile: - [Richard Seal](https://twitter.com/rich_seal)

## Help and Support

See the [Troubleshooting](/troubleshooting) section for some common fixes.

Questions, comments, and feature requests should be submitted on [GitHub](https://git.io/spe). You may also check out the [SPE Slack channel](https://sitecorechat.slack.com/messages/module-spe/) 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.


# 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.


# Installation

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

## Prerequisites

Take a quick look at the [appendix](/appendix) 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.
* PowerShell [Execution Policy](https://technet.microsoft.com/en-us/library/ee176961.aspx) set to `RemoteSigned` (probably optional)

{% hint style="info" %}
The release of SPE 6.0 introduced name changes to some files which are now reflected throughout the documentation. Review [issue #1109](https://github.com/SitecorePowerShell/Console/issues/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*.
{% endhint %}

## Docker

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

You can find two flavors of the images:

* [Community Built](https://hub.docker.com/r/sitecorepowershell/sitecore-powershell-extensions)
  * 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**

```
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}
```

**Dockerfile (mssql-init)**

```
# escape=`

ARG BASE_IMAGE
ARG SPE_IMAGE

FROM ${SPE_IMAGE} as spe
FROM ${BASE_IMAGE}

COPY --from=spe C:\module\db C:\resources\spe
```

**Dockerfile (cm)**

```
# 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 .\
```

## Installation Wizard

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

[Download](https://github.com/SitecorePowerShell/Console/releases) 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](https://gist.github.com/michaellwest/87c26d25407b0a8bcfbcabfabedbbdb7).

## 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](https://gist.github.com/michaellwest/87c26d25407b0a8bcfbcabfabedbbdb7).

{% hint style="info" %}
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](https://www.maartenwillebrands.nl/2022/02/15/sitecore-removing-iar-items-from-the-database/) may be helpful if you wish to take a more precise approach.
{% endhint %}

### 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](/troubleshooting)


# Contributor Guide

{% hint style="warning" %}
Support for Sitecore 7 has discontinued with SPE 5.0.
{% endhint %}

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 [here](/installation)
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

   ```powershell
   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
   ```
4. 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.
5. 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.
6. 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.
7. Open the solution in Visual Studio.
8. 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`
9. Login to Sitecore
10. 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>
11. SPE is now installed in Sitecore and you're ready for developing!

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`, `9.1` or `9.2` depending on the major/minor version.
4. 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.

> 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, [junction points](https://en.wikipedia.org/wiki/NTFS_junction_point) 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`:

```json
{ 
    "sites": [
        {
            "path": "C:\\inetput\\wwwroot\\SitecoreSPE_8\\Website",
            "version": 8,
            "junction": 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`


# 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:

### Beginner - Get Started

1. **Get up and running** - Start with [Getting Started](/training/getting-started)
2. **Watch the basics** - View our [video series](https://www.youtube.com/playlist?list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b)
3. **Learn PowerShell syntax** - Study [Language Basics](/training/language-basics)
4. **Master commands** - Read [Commands and Pipelines](/training/commands-and-pipelines)
5. **Understand providers** - Learn [Providers](/training/providers)
6. **Practice with examples** - Try [Your First Scripts](/training/first-scripts)
7. **Avoid mistakes** - Review [Common Pitfalls](/training/common-pitfalls)

### Intermediate - Build Skills

8. **Retrieve Sitecore items** - Learn to query and navigate → [Retrieving Items](/working-with-items/retrieving-items)
9. **Modify content** - Edit, create, and delete → [Editing Items](/working-with-items/editing-items), [Creating Items](/working-with-items/creating-and-removing-items)
10. **Move and copy items** - Reorganize content → [Moving and Copying Items](/working-with-items/moving-and-copying-items)
11. **Use interactive dialogs** - Build user interfaces → [Interactive Dialogs](/interfaces/interactive-dialogs)
12. **Explore integration points** - Extend Sitecore UI → [Integration Points](/modules/integration-points)

### Advanced - Master SPE

13. **Create custom reports** - Build powerful analysis tools → [Authoring Reports](/modules/integration-points/reports/authoring-reports)
14. **Build reusable libraries** - Organize your scripts → [Libraries and Scripts](/modules/libraries-and-scripts)
15. **Automate with tasks** - Schedule automated jobs → [Authoring Tasks](/modules/integration-points/tasks/authoring-tasks)
16. **Use remoting** - Control Sitecore from external scripts → [Remoting](/remoting)
17. **Package your work** - Deploy scripts as packages → [Packaging](/modules/packaging)
18. **Plan your next steps** - Review [Next Steps](/training/next-steps)

### Critical - Secure Your Installation

{% hint style="danger" %}
**BEFORE deploying to any environment**, you MUST review security:

* [Security Hardening Guide](/security) - Overview of security concepts
* [Security Checklist](/security/security-checklist) - Step-by-step hardening
* [Security Policies](/security/security-policies) - Configure access control
* **NEVER** install SPE on Content Delivery (CD) servers
* **NEVER** deploy SPE on internet-facing instances
  {% endhint %}

## Resources & Support

### Official Documentation

* **This book** - Comprehensive reference for all SPE features
* [Command Reference](/appendix/common) - Complete list of SPE cmdlets
* [Code Snippets](/code-snippets) - Ready-to-use examples

### Video Tutorials

* [SPE Video Series](https://www.youtube.com/playlist?list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b) - Beginner walkthroughs
* [Blogs and Videos Collection](https://blog.najmanowicz.com/sitecore-powershell-console/) - Community content

### Hands-On Practice

* [Console](/interfaces/console) - Interactive PowerShell terminal in Sitecore
* [ISE (Integrated Scripting Environment)](/interfaces/scripting) - Full-featured script editor with IntelliSense

### Get Help

* **Built-in help**: Use `Get-Help <command-name>` in the Console
* **Troubleshooting**: [Troubleshooting Guide](/troubleshooting)
* **Community**: Join the [#module-spe](/community) channel on Sitecore Slack
* **GitHub**: Report issues or request features at [GitHub](https://github.com/SitecorePowerShell/Console)

Happy scripting!


# 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 → [Installation Guide](/installation)
* ✅ Appropriate permissions to access PowerShell tools → [Security](/security)
* ✅ Basic understanding of Sitecore concepts (items, templates, fields)

{% hint style="info" %}
You don't need to know PowerShell or programming to get started! This guide is designed for Sitecore users who want to automate tasks.
{% endhint %}

## 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](/files/O9MQK63zvPyQcGe5xHIt)

**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](/files/-LA37bAsw4QRxUOSA4FB)

**When to use the ISE:**

* Writing multi-line scripts
* Developing reusable tools
* Saving scripts for later use
* Debugging complex logic

Learn more: [Console](/interfaces/console) | [ISE](/interfaces/scripting)

## 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:

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

### Step 3: Examine the Results

You should see output showing details about your Home item:

```powershell
Name Children Language Version Id                                     TemplateName
---- -------- -------- ------- --                                     ------------
Home False    en       1       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
```

{% hint style="success" %}
**Congratulations!** You just retrieved a Sitecore item using PowerShell. This is the foundation of everything you'll do with SPE.
{% endhint %}

## Understanding What Just Happened

Let's break down that command:

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

* **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

```powershell
Get-ChildItem -Path "master:\content\home"
```

This shows all direct children of the Home item.

### List All Descendants

```powershell
Get-ChildItem -Path "master:\content\home" -Recurse
```

{% hint style="warning" %}
Be careful with `-Recurse` on large content trees! It can take a long time. See [Common Pitfalls](/training/common-pitfalls) for more.
{% endhint %}

### 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.

```powershell
Get-Item -Path "master:\content\home" | Select-Object -Property Name, ID, TemplateName
```

Using `Select-Object`, the properties are trimmed and the output window reflects the specific fields.

**Output:**

```powershell
Name ID                                     TemplateName
---- --                                     ------------
Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
```

### Find Items by Name

```powershell
Get-ChildItem -Path "master:\content\home" | Where-Object { $_.Name -like "*Sample*" }
```

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:

```powershell
# 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
```

### 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.

{% hint style="info" %}
The ISE provides **IntelliSense** - start typing a command and press Ctrl+Space to see suggestions!
{% endhint %}

## Key Concepts

### Variables

Variables store data and start with `$`:

```powershell
$item = Get-Item -Path "master:\content\home"
$name = $item.Name
$count = 5
```

Learn more: [Variables](/working-with-items/variables)

### Pipelines

The pipe `|` chains commands together:

```powershell
Get-ChildItem -Path "master:\content\home" |
    Where-Object { $_.TemplateName -eq "Sample Item" } |
    Select-Object Name, ID
```

Learn more: [Commands and Pipelines](/training/commands-and-pipelines)

### Providers

SPE uses providers to access different data stores. The most important is the **Sitecore provider**:

```powershell
# 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"
```

Learn more: [Providers](/training/providers)

## Common Tasks

Here are some common tasks you can do right now:

### Check if Item Exists

```powershell
if(Test-Path "master:\content\home\test") {
    Write-Host "Item exists!" -ForegroundColor Green
} else {
    Write-Host "Item not found" -ForegroundColor Yellow
}
```

### Count Items by Template

```powershell
$items = Get-ChildItem -Path "master:\content\home" -Recurse
$items | Group-Object TemplateName | Select-Object Name, Count | Sort-Object Count -Descending
```

### Find Items Modified Recently

```powershell
$threshold = (Get-Date).AddDays(-7)
Get-ChildItem -Path "master:\content\home" -Recurse |
    Where-Object { $_."__Updated" -gt $threshold } |
    Select-Object Name, ItemPath, "__Updated"
```

### Export Data to CSV

```powershell
$items = Get-ChildItem -Path "master:\content\home"
$items | Select-Object Name, TemplateName, "__Updated" |
    Export-Csv -Path "$($SitecoreDataFolder)\export\items.csv" -NoTypeInformation
```

## Getting Help

SPE includes extensive built-in help:

### Get Help for a Command

```powershell
Get-Help Get-ItemAcl
```

### Get Detailed Help

```powershell
Get-Help Read-Variable -Detailed
```

### Get Examples

```powershell
Get-Help Find-Item -Examples
```

### List All SPE Commands

```powershell
Get-Command | Where-Object { $_.ImplementingType -and $_.ImplementingType.Assembly.GetName().Name -eq "Spe" }
```

Learn more: [Help](/interfaces/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

{% hint style="info" %}
The Script Library is a great way to learn! Read through examples to see how different commands work together.
{% endhint %}

## 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

{% hint style="danger" %}
**IMPORTANT**: SPE is powerful and requires proper security configuration. Review the [Security Guide](/security) before deploying to any non-development environment.
{% endhint %}

## Next Steps

Now that you're up and running:

1. **Learn the syntax**: [Language Basics](/training/language-basics)
2. **Master commands**: [Commands and Pipelines](/training/commands-and-pipelines)
3. **Understand providers**: [Providers](/training/providers)
4. **Write your first scripts**: [Your First Scripts](/training/first-scripts)
5. **Avoid mistakes**: [Common Pitfalls](/training/common-pitfalls)

## 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.         |
| **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.                         |

### Path Format

```
database:\path\to\item

Examples:
master:\content\home
web:\content\home\article
core:\content
```

### Special Variables

```powershell
$_          # Current item in pipeline
$PSItem     # Same as $_
$true       # Boolean true
$false      # Boolean false
$null       # Null value
```

Ready to dive deeper? Continue with [Language Basics](/training/language-basics)!


# 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.

```csharp
// C# - declare and assign
var name = "Michael";
string title = "Developer";
int count = 5;
```

```powershell
# PowerShell - assign (type is inferred)
$name = "Michael"
$title = "Developer"
$count = 5

# Optionally specify type
[string]$title = "Developer"
[int]$count = 5
```

## 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.

```csharp
// Perform simple math in C#
var total = 1 + 1;
total += 2;
var result = total * 3 / 2;
```

```powershell
# Perform simple math in PowerShell
$total = 1 + 1
$total += 2
$result = $total * 3 / 2
```

**Operators are the same:**

* Addition: `+`
* Subtraction: `-`
* Multiplication: `*`
* Division: `/`
* Modulus: `%`

### Arrays

Working with Dynamic and Fixed dimensional arrays.

```csharp
/*
  Create a new dynamic list of strings in C#
*/
var names = new List<string>();
names.Add("Michael");
names.Add("Adam");
```

```powershell
<#
  Create a new fixed list of strings in PowerShell
#>
[string[]]$names = @()
$names += "Michael"
$names += "Adam"
```

{% hint style="warning" %}
Using `+=` with arrays in PowerShell is slow because it creates a new array each time. See [Performance Considerations](#performance-considerations) for better alternatives.
{% endhint %}

### Hashtables

Working with hashtables (dictionaries).

```csharp
// Create a hashtable of data in C#
var table = new Hashtable();
table["Name"] = "Michael";
table["Age"] = 33;
```

```powershell
# Create a new hashtable of data in PowerShell
$table = @{}
$table["Name"] = "Michael"
$table["Age"] = 33

# Or create inline
$table = @{
    Name = "Michael"
    Age = 33
}
```

### Ordered Dictionaries

Working with dictionaries that preserve insertion order.

```csharp
// Ordered Dictionary in C#
var od = new OrderedDictionary();
od.Add("z","Last Letter");
od.Add("a","First Letter");
```

```powershell
# Ordered Dictionary in PowerShell
$od = [ordered]@{}
$od.Add("z","Last Letter")
$od.Add("a","First Letter")
```

```csharp
// Check if the string is null or empty using a static method in C#
if(string.IsNullOrEmpty(name)) {
  ...
}
else {
  ...
}
```

```powershell
# Check if the string is null or empty using a static method in PowerShell
if([string]::IsNullOrEmpty($name)) {
  ...
} else {
  ...
}
```

**Switch statements:**

```csharp
// C# switch
switch(value) {
    case "A":
        DoSomething();
        break;
    case "B":
        DoSomethingElse();
        break;
    default:
        DoDefault();
        break;
}
```

```powershell
# PowerShell switch
switch($value) {
    "A" {
        Do-Something
    }
    "B" {
        Do-SomethingElse
    }
    default {
        Do-Default
    }
}
```

**Important:** PowerShell uses different comparison operators than C#!

```csharp
// Compare values in C#
name == "Michael"
total <= 3
names.Count() > 2 && name[0] != "Adam"
```

```powershell
# Compare values in PowerShell
$name -eq "Michael"
$total -le 3
$names.Count -gt 2 -and $name[0] -ne "Adam"
```

### Comparison Operators

| C#   | PowerShell | Description           |
| ---- | ---------- | --------------------- |
| `==` | `-eq`      | Equal to              |
| `!=` | `-ne`      | Not equal to          |
| `<`  | `-lt`      | Less than             |
| `>`  | `-gt`      | Greater than          |
| `<=` | `-le`      | Less than or equal    |
| `>=` | `-ge`      | Greater than or equal |

### Logical Operators

| C#     | PowerShell    | Description |
| ------ | ------------- | ----------- |
| `&&`   | `-and`        | Logical AND |
| `\|\|` | `-or`         | Logical OR  |
| `!`    | `-not` or `!` | Logical NOT |

### Pattern Matching

```powershell
# 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
```

Most comparisons in PowerShell are case-insensitive by default. Use operators starting with `c` (like `-ceq`) for case-sensitive comparisons.

```csharp
// Negate value in C#
var isTrue = !false;
var isNotEmpty = !string.IsNullOrEmpty(value);
```

```powershell
# Negate value in PowerShell
$isTrue = !$false
$isTrue = -not $false

$isNotEmpty = ![string]::IsNullOrEmpty($value)
$isNotEmpty = -not [string]::IsNullOrEmpty($value)
```

**Both work the same:**

* `!$value` - Shorter syntax
* `-not $value` - More explicit

### String Interpolation

```csharp
// String interpolation in C#
var message = $"Hello, {name}";
var result = $"Total: {count * 2}";
```

```powershell
# String interpolation in PowerShell
$message = "Hello, $name"
$result = "Total: $($count * 2)"
```

{% hint style="info" %}
Use `$()` for expressions: `"Result: $(2 + 2)"` → "Result: 4"
{% endhint %}

### Escape Characters

Escape double quotes in string. Alternatively you can use a single quote.

```csharp
// Escape characters in C#
string message = "They said, \"SPE is the greatest!\".";
message = 'I said, "Thanks!"';
message = "We celebrated together, 'Go SPE!'";
```

```powershell
# Escape characters in PowerShell
$message = "They said, `"SPE is the greatest!`"."
$message = 'I said, "Thanks!".'
$message = "We celebrated together, 'Go SPE!'."
```

**Escape character:** PowerShell uses backtick `` ` `` instead of backslash `\`

### Multi-line Strings

```csharp
// C# multi-line
var text = @"
Line 1
Line 2
Line 3
";
```

```powershell
# PowerShell here-string
$text = @"
Line 1
Line 2
Line 3
"@
```

### String Operations

```powershell
# 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()
```

### For Loop

```csharp
// C# for loop
for(int i = 0; i < 10; i++) {
    Console.WriteLine(i);
}
```

```powershell
# PowerShell for loop
for($i = 0; $i -lt 10; $i++) {
    Write-Host $i
}
```

### ForEach Loop

```csharp
// C# foreach
foreach(var item in items) {
    ProcessItem(item);
}
```

```powershell
# PowerShell foreach
foreach($item in $items) {
    Process-Item $item
}
```

### While Loop

```csharp
// C# while
while(count < 100) {
    count++;
}
```

```powershell
# PowerShell while
while($count -lt 100) {
    $count++
}
```

### Accessing .NET Types

```csharp
// Access static property in C#
var today = DateTime.Today;
var guid = Guid.NewGuid();
```

```powershell
# Access static property in PowerShell
$today = [datetime]::Today
$guid = [guid]::NewGuid()
```

### Common .NET Types

```powershell
# 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")
```

### Creating .NET Objects

```csharp
// C# - create object
var list = new List<string>();
var dict = new Dictionary<string, int>();
```

```powershell
# 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()
```

## Comments

```csharp
// C# - Single line comment

/*
  C# - Multi-line comment
  More text here
*/
```

```powershell
# PowerShell - Single line comment

<#
  PowerShell - Multi-line comment
  More text here
#>
```

## Functions and Methods

### Calling Methods

```csharp
// C# - call method
string upper = name.ToUpper();
items.Add("new item");
```

```powershell
# 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
```

### Defining Functions

```csharp
// C# - define function
public string GetFullName(string first, string last) {
    return first + " " + last;
}

var name = GetFullName("John", "Smith");
```

```powershell
# PowerShell - define function
function Get-FullName {
    param(
        [string]$First,
        [string]$Last
    )

    return "$First $Last"
}

$name = Get-FullName -First "John" -Last "Smith"
```

## Error Handling

```csharp
// C# - try/catch
try {
    DoSomething();
}
catch(Exception ex) {
    Console.WriteLine(ex.Message);
}
finally {
    Cleanup();
}
```

```powershell
# PowerShell - try/catch
try {
    Do-Something
}
catch {
    Write-Host $_.Exception.Message
}
finally {
    Clean-up
}
```

## Performance Considerations

### Better Collections

Creating arrays with `+=` is slow. Use these instead:

```powershell
# 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
```

### Suppressing Output

Different methods have different performance:

```powershell
# SLOW - Out-Null is a cmdlet
$list.Add($item) | Out-Null

# FAST - redirect to $null
$list.Add($item) > $null
```

## Key Differences Summary

| Concept                  | C#               | PowerShell          |
| ------------------------ | ---------------- | ------------------- |
| **Variables**            | `var name`       | `$name`             |
| **Equals**               | `==`             | `-eq`               |
| **Not equals**           | `!=`             | `-ne`               |
| **And**                  | `&&`             | `-and`              |
| **Or**                   | `\|\|`           | `-or`               |
| **Not**                  | `!`              | `-not` or `!`       |
| **Escape char**          | `\`              | `` ` ``             |
| **String interpolation** | `$"text {var}"`  | `"text $var"`       |
| **Static access**        | `DateTime.Today` | `[datetime]::Today` |
| **Comments**             | `//` or `/* */`  | `#` or `<# #>`      |

## Next Steps

Now that you understand the syntax:

1. **Learn commands**: [Commands and Pipelines](/training/commands-and-pipelines)
2. **Understand providers**: [Providers](/training/providers)
3. **Practice with examples**: [Your First Scripts](/training/first-scripts)
4. **Avoid mistakes**: [Common Pitfalls](/training/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!


# 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.

```powershell
Get-Something [[-SomeParameter] <sometype[]>] [-AnotherParameter <anothertype>] [-SomeSwitch]
```

### 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.

{% hint style="info" %}
The noun in the command should be singular even if the command returns more than one object.
{% endhint %}

**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](https://msdn.microsoft.com/en-us/library/ms714428%28v=vs.85%29.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

{% hint style="info" %}
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.
{% endhint %}

### Parameter Examples

**Example**: The following provides possible permutations for the fake command.

```powershell
<#
    All of the parameters in the command are surrounded by square brackets
    indicating they are optional.
#>
Get-Something
```

```powershell
<#
    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"
```

```powershell
<#
    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
```

### Splatting Parameters

Instead of passing parameters inline, you can "splat" them using a hashtable:

```powershell
# Define parameters in a hashtable
$props = @{
    "SomeParameter" = @("data","data2")
    "AnotherParameter" = 100
    "SomeSwitch" = $true
}

# Splat with @props instead of $props
Get-Something @props
```

**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:**

```powershell
# 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
```

{% hint style="info" %}
Aliases and abbreviations are fine for interactive use in the Console, but always use full names in saved scripts!
{% endhint %}

## 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*`                                |
| **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`               |

{% hint style="info" %}
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.
{% endhint %}

## 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:

```powershell
Command1 | Command2 | Command3
```

* **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

{% hint style="info" %}
The characters `$_` and `$PSItem` represent the current object getting processed in the pipeline.
{% endhint %}

```powershell
Get-ChildItem -Path "master:\content\home" |
    Where-Object { $_.TemplateName -eq "Article" }
    # $_ represents each item as it flows through
```

### Simple Pipeline Examples

**Example:** The following queries a Sitecore item and removes it.

```powershell
# 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
```

**Example:** The following gets children and displays specific properties.

```powershell
Get-ChildItem -Path "master:\content\home" |
    Select-Object -Property Name, TemplateName, ID
```

### 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.

```powershell
# 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
```

{% hint style="info" %}
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.
{% endhint %}

## Common Pipeline Patterns

### Filtering

```powershell
# Filter by property value
Get-ChildItem -Path "master:\content\home" |
    Where-Object { $_.TemplateName -eq "Sample Item" }
```

```powershell
# 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)
    }
```

```powershell
# Filter and negate
Get-ChildItem -Path "master:\content\home" |
    Where-Object { $_.Name -notlike "*Test*" }
```

### Transforming

```powershell
# Select specific properties
Get-ChildItem -Path "master:\content\home" |
    Select-Object Name, TemplateName, ID
```

```powershell
# 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}}
```

```powershell
$items = Get-ChildItem -Path "master:\content\home"
# Expand single property to array of values
$items | Select-Object -ExpandProperty Name
# Returns: @("Name1", "Name2", "Name3")
```

### Grouping and Aggregating

```powershell
# Count items by template
Get-ChildItem -Path "master:\content\home" -Recurse |
    Group-Object TemplateName |
    Select-Object Name, Count |
    Sort-Object Count -Descending
```

### Sorting

```powershell
# 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 }
```

### ForEach Processing

```powershell
# 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() }
```

## 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.

```powershell
# 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
```

### Finding Commands

```powershell
# 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 *
```

### Discovering Properties and Methods

```powershell
# 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
```

{% hint style="info" %}
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**.
{% endhint %}

## 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.

```powershell
# 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
```

**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         |
| `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       |

View all aliases:

```powershell
Get-Alias
```

## Next Steps

Now that you understand commands and pipelines:

1. **Learn about providers**: [Providers](/training/providers)
2. **Practice with examples**: [Your First Scripts](/training/first-scripts)
3. **Avoid common mistakes**: [Common Pitfalls](/training/common-pitfalls)
4. **Deepen your knowledge**: [Working with Items](/working-with-items)

{% hint style="success" %}
The pipeline is PowerShell's superpower! Master it and you'll be able to accomplish complex tasks with surprisingly little code.
{% endhint %}


# 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**: 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`               |
| **Function**    | Function          | `Get-Item -Path function:\prompt`         |
| **Registry**    | HKLM, HKCU        | `Get-Item -Path hklm:\SOFTWARE`           |
| **Variable**    | Variable          | `Get-Item -Path variable:\PSVersionTable` |

## 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.

```powershell
# When you open the Console, you start here:
PS master:\>
```

### Database Drives

The Sitecore provider exposes these databases as drives:

```powershell
# Master database
Get-Item -Path "master:\content\home"

# Web database
Get-Item -Path "web:\content\home"

# Core database
Get-Item -Path "core:\content"
```

### Path Format

Sitecore provider paths follow this format:

```
database:\path\to\item
```

**Examples:**

```powershell
master:\content\home
master:\content\home\articles\my-article
web:\content
core:\system
```

{% hint style="info" %}
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`
  {% endhint %}

## Switching Between Providers

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

```powershell
PS master:\> cd c:\
PS C:\> cd hklm:
PS HKLM:\> cd env:
PS Env:\> cd master:
PS master:\>
```

{% hint style="warning" %}
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.
{% endhint %}

## Working with the Sitecore Provider

### Getting Items

```powershell
# 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
```

### Creating Items

```powershell
# Create a new item
New-Item -Path "master:\content\home" -Name "My New Item" -ItemType "Sample/Sample Item"
```

### Removing Items

```powershell
# Remove an item (goes to Recycle Bin)
Remove-Item -Path "master:\content\home\test-item"
```

### Testing if Item Exists

```powershell
# Check if an item exists
if(Test-Path -Path "master:\content\home\my-item") {
    Write-Host "Item exists!"
}
```

## Provider-Specific Features

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

### Sitecore Provider Features

```powershell
# 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
```

### File System Provider Features

```powershell
# 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
```

## 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

```powershell
# 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
```

## 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`         | `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`         |

## 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](/working-with-items/providers)

## Next Steps

Now that you understand providers:

1. **Practice with examples**: [Your First Scripts](/training/first-scripts)
2. **Avoid common mistakes**: [Common Pitfalls](/training/common-pitfalls)
3. **Deep dive into items**: [Working with Items](/working-with-items)
4. **Read comprehensive provider docs**: [Providers](/working-with-items/providers)


# 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.

```powershell
# 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"
```

**What just happened?**

1. Retrieved the home item using the Sitecore provider → [Learn more](/working-with-items/retrieving-items)
2. Queried all child items recursively
3. Filtered by workflow field value → [Learn more](/working-with-items/editing-items)
4. Displayed results as a report → [Learn more](/appendix/common/show-listview)

## Example 2: Bulk Update Item Fields

**Goal**: Update a field value on multiple items.

```powershell
# 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
```

**Key concepts demonstrated:**

* Filtering by template → [Templates](/code-snippets/manage-templates)
* Proper item editing workflow → [Editing Items](/working-with-items/editing-items)
* Using PowerShell loops and variables

{% hint style="warning" %}
Always use `BeginEdit()` and `EndEdit()` when modifying items. Changes won't persist without this pattern.
{% endhint %}

## Example 3: Interactive User Input

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

```powershell
# 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"
```

**Interactive concepts:**

* Using [Read-Variable](/appendix/common/read-variable) for user input
* Parameter validation
* Conditional logic based on user choices
* See [Interactive Dialogs](/interfaces/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:

```powershell
# 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*" }
```

### 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

{% hint style="info" %}
The ISE provides IntelliSense, syntax highlighting, and debugging capabilities. It's the best place to learn and develop SPE scripts. See [Scripting](/interfaces/scripting) for more details.
{% endhint %}

## 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.

<details>

<summary>Solution</summary>

```powershell
Get-ChildItem -Path "master:\content" -Recurse |
    Where-Object {
        [string]::IsNullOrEmpty($_.Fields["Title"].Value)
    } |
    Show-ListView -Property Name, ItemPath, TemplateName
```

</details>

### Exercise 2: Count Items by Template

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

<details>

<summary>Solution</summary>

```powershell
$items = Get-ChildItem -Path "master:\content\home" -Recurse

$templateCounts = $items | Group-Object TemplateName |
    Select-Object Name, Count |
    Sort-Object Count -Descending

$templateCounts | Show-ListView
```

</details>

### 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.

<details>

<summary>Solution</summary>

```powershell
$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"
```

</details>

## Common Patterns

Here are some frequently used patterns you'll encounter:

### Pattern: Safe Item Editing

```powershell
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): $_"
    }
}
```

### Pattern: Check if Item Exists

```powershell
$itemPath = "master:\content\home\test"
if(Test-Path $itemPath) {
    $item = Get-Item $itemPath
    # Process item
}
else {
    Write-Host "Item not found" -ForegroundColor Yellow
}
```

### Pattern: Process Items with Progress

```powershell
$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
}
```

## Next Steps

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

1. **Avoid common mistakes**: Review [Common Pitfalls](/training/common-pitfalls)
2. **Build on this knowledge**: Explore [Working with Items](/working-with-items)
3. **Create custom reports**: Learn [Authoring Reports](/modules/integration-points/reports/authoring-reports)
4. **Share your scripts**: Build a [Script Library](/modules/libraries-and-scripts)

{% hint style="success" %}
The best way to learn is by doing. Try modifying these examples for your own use cases!
{% endhint %}


# 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.

### The Problem

* ❌ **Wrong**: `$item["Title"] = "New Title"` (changes won't save!)
* ✅ **Correct**:

  ```powershell
  $item.Editing.BeginEdit()
  $item["Title"] = "New Title"
  $item.Editing.EndEdit()
  ```

### 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:

```powershell
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): $_"
    }
}
```

Read more: [Editing Items](/working-with-items/editing-items)

## Using Recursion on Large Trees

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

### The Problem

```powershell
# DANGEROUS on large content trees!
Get-ChildItem -Path "master:\content" -Recurse
```

### 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

```powershell
# Recurse only within a specific subtree
Get-ChildItem -Path "master:\content\home\articles" -Recurse
```

#### Option 2: Use Content Search

```powershell
# 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
```

#### Option 3: Limit Depth

```powershell
$items = Get-ChildItem -Path "master:\content" -Depth 2
```

Read more: [Find-Item](/appendix/indexing/find-item) | [Best Practices](/working-with-items/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

{% hint style="danger" %}
Review the [Security Hardening Guide](/security) and complete the [Security Checklist](/security/security-checklist) before deploying to any non-development environment.
{% endhint %}

## Confusing PowerShell Comparison Operators

PowerShell uses different operators than most programming languages. See [Language Basics](/training/language-basics#comparisons) for the complete comparison operator reference.

### Examples

```powershell
# 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
```

Learn more: [Language Basics - Comparisons](/training/language-basics#comparisons)

## Forgetting About Language Versions

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

### The Problem

```powershell
# This gets the item in the DEFAULT language (usually en)
$item = Get-Item -Path "master:\content\home"
$item["Title"]  # Returns English title
```

### Working with Languages

```powershell
# 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()
```

Read more: [Item Languages](/working-with-items/item-languages)

## Suppressing Output Incorrectly

Different methods of suppressing output have very different performance characteristics.

### The Problem

```powershell
# SLOW - Out-Null is a cmdlet, adds pipeline overhead
$builder.Append("Text") | Out-Null

# FAST - Redirect to $null
$builder.Append("Text") > $null
```

### Performance Comparison

```powershell
# Slow (don't use for simple suppression)
$list.Add($item) | Out-Null

# Fast (use this instead)
$list.Add($item) > $null
```

## 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](/working-with-items/best-practices)
4. **Secure your installation**: Complete the [Security Checklist](/security/security-checklist)

{% hint style="success" %}
Everyone makes mistakes when learning. The key is learning from them and building better habits!
{% endhint %}


# 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

#### Working with Items

Master the core operations for manipulating Sitecore content:

* [Working with Items](/working-with-items) - Complete guide to item manipulation
* [Retrieving Items](/working-with-items/retrieving-items) - Advanced querying techniques
* [Editing Items](/working-with-items/editing-items) - Proper item editing workflows
* [Creating and Removing Items](/working-with-items/creating-and-removing-items) - Item lifecycle management
* [Moving and Copying Items](/working-with-items/moving-and-copying-items) - Reorganizing content
* [Item Languages](/working-with-items/item-languages) - Working with multilingual content
* [Item Security](/working-with-items/item-security) - Managing permissions with PowerShell
* [Best Practices](/working-with-items/best-practices) - Tips for writing efficient scripts

#### User Interfaces

Build rich, interactive experiences for your scripts:

* [Interactive Dialogs](/interfaces/interactive-dialogs) - Build rich UI for your scripts
* [Show-ListView](/appendix/common/show-listview) - Display data in tables with actions
* [Read-Variable](/appendix/common/read-variable) - Create custom input forms
* [Show-FieldEditor](/appendix/common/show-fieldeditor) - Edit item fields in dialogs
* [Show-Result](/appendix/common/show-result) - Display formatted output

#### Building Useful Tools

Create custom tools that extend Sitecore functionality:

* [Creating Reports](/modules/integration-points/reports/authoring-reports) - Build custom content reports
* [Creating Tasks](/modules/integration-points/tasks/authoring-tasks) - Schedule automated jobs
* [Content Editor Integration](/modules/integration-points/content-editor) - Add context menu items
* [Toolbox Scripts](/modules/integration-points/toolbox) - Create administrative tools
* [Control Panel](/modules/integration-points/control-panel) - Add Control Panel applications
* [Event Handlers](/modules/integration-points/event-handlers) - React to Sitecore events

#### Advanced Topics

Take your skills to the next level:

* [Remoting](/remoting) - Automate Sitecore from external scripts
* [Packaging](/modules/packaging) - Package and deploy your work
* [Workflows](/modules/integration-points/workflows) - Integrate with Sitecore workflows
* [Web API](/modules/integration-points/web-api) - Expose scripts via REST API
* [Libraries and Scripts](/modules/libraries-and-scripts) - Organize reusable code

## Reference Materials

Beyond the learning paths above, you'll find these resources helpful:

* [**Command Reference**](/appendix) - Complete list of all SPE cmdlets
* [**Code Snippets**](/code-snippets) - Ready-to-use examples for common scenarios
* [**Interfaces Guide**](/interfaces) - 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
   * Show progress and results
3. **Publishing Dashboard**
   * Show items published in last 24 hours
   * Compare master vs web databases
   * Display publishing statistics
   * Highlight unpublished changes

### Intermediate Projects

4. **Content Migration Tool**
   * Copy items between databases
   * Preserve all field values and versions
   * Handle item relationships
   * Create detailed log
5. **Security Auditor**
   * List all users and their roles
   * Show items with custom security
   * Identify security inheritance breaks
   * Export security matrix
6. **Template Analyzer**
   * Find all templates
   * Show template inheritance tree
   * List fields for each template
   * Identify unused templates

### Advanced Projects

7. **Custom Reporting Engine**
   * Build reusable report framework
   * Support multiple output formats
   * Add scheduling capabilities
   * Email reports automatically
8. **Content Health Monitor**
   * Check for broken links
   * Validate media items exist
   * Find duplicate items
   * Schedule regular scans
9. **Deployment Assistant**
   * Compare environments
   * Package changed items
   * Generate deployment scripts
   * Validate post-deployment

## Essential Security Review

{% hint style="danger" %}
**CRITICAL**: Before deploying SPE to any non-development environment, review [Security Hardening](/security) and complete the [Security Checklist](/security/security-checklist). Remember: SPE should **NEVER** be installed on CD servers or be accessible from internet-facing instances.
{% endhint %}

## Get Help and Support

### When You Get Stuck

* **Built-in help**: Use `Get-Help <command-name>` in the Console
* [**Troubleshooting Guide**](/troubleshooting) - Common issues and solutions
* [**#module-spe**](/community) - Sitecore Community Slack channel
* [**GitHub**](https://github.com/SitecorePowerShell/Console) - 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**](https://www.youtube.com/playlist?list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b) - Official tutorial videos
* [**Blog Collection**](https://blog.najmanowicz.com/sitecore-powershell-console/) - Community articles and examples
* [**Microsoft PowerShell Docs**](https://docs.microsoft.com/en-us/powershell/) - 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

```powershell
# 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
```

### Common Patterns

```powershell
# 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
}
```

***

## 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!** 🚀

{% hint style="success" %}
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!
{% endhint %}


# 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](https://user-images.githubusercontent.com/933163/50198867-4053b380-0313-11e9-9e46-5eb5513417ff.png)

A well known and widely adopted module [Unicorn](https://github.com/SitecoreUnicorn/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](https://kamsar.net/index.php/2017/02/Unicorn-4-Preview-Part-2-SPE-Support/) and [here](https://kamsar.net/index.php/2017/02/Unicorn-4-Preview-Part-2-5-Generating-Packages-with-SPE/).

### Configurations

**Example:** The following lists configurations by name.

```powershell
# Default returns all configurations
Get-UnicornConfiguration

# Exact match
Get-UnicornConfiguration -Filter "Foundation.Foo"

# Filter using a wildcard
Get-UnicornConfiguration -Filter "Foundation.*"
```

### Syncing

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

```powershell
# 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
```

![Example Syncing](https://user-images.githubusercontent.com/933163/50114210-9ccaac00-0209-11e9-9241-2738b50b1f75.png)

### Partial Syncing

```powershell
# 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
```

### Reserializing

```powershell
# Reserialize one
Export-UnicornConfiguration "Foundation.Foo"

# Reserialize multiple by name
Export-UnicornConfiguration @("Foundation.Foo", "Foundation.Bar")

# Reserialize from pipeline
Get-UnicornConfiguration "Foundation.*" | Export-UnicornConfiguration
```

### Partial Reserializing

```powershell
# 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
```

### Converting to Raw Yaml

```powershell
# 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
```

![Converting To Yaml](https://user-images.githubusercontent.com/933163/50114470-32663b80-020a-11e9-917c-6707e85524dd.png)

### Converting from Raw Yaml

```powershell
# 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
```

![Converting from Yaml](https://user-images.githubusercontent.com/933163/50114544-5cb7f900-020a-11e9-90a7-f5b834eb7285.png)

### Deserialization

```powershell
# 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
```

![Deserialization](https://user-images.githubusercontent.com/933163/50114603-8bce6a80-020a-11e9-8876-2df4d24e5443.png)

### Packaging

```powershell
# 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
```

## SPE Modules

The following are Sitecore modules that enhance the SPE experience.

* [SPE Image Importer](https://marketplace.sitecore.net/en/Modules/S/SPE_Image_Uploader_Module10.aspx) : [Himadri Chakrabarti](https://twitter.com/himadric)
* [Multi-Item Publish](https://www.sitecorenutsbolts.net/2015/12/14/Multi-Item-Publish-with-Sitecore-Powershell-Extensions/) : [Richard Seal](https://twitter.com/rich_seal)
* [Publish Status](http://marketplace.sitecore.net/Modules/P/Publish_Status_for_Sitecore_Powershell_Extensions.aspx?sc_lang=en) : [Morten Engel](https://mortenengel.blogspot.com/2018/11/publish-viewercanceler-using-sitecore.html)
* [Westco Pull Up Fields](https://github.com/michaellwest/westco-spe-pullupfields) : [Michael West](https://twitter.com/MichaelWest101)
* [Westco Image Optimizer](https://github.com/michaellwest/westco-spe-imageoptimizer) : [Michael West](https://twitter.com/MichaelWest101)


# 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.](/files/O9MQK63zvPyQcGe5xHIt)

![The Sitecore PowerShell ISE is a scripting interface for running commands and authoring scripts.](/files/-LA37bAsw4QRxUOSA4FB)


# 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 [Elevated Session State](/security) 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.

![PowerShell Console](/files/4KaKgTkwrUQV6qqRoPC1)

## Shortcuts

Below are the shortcuts available in the console.

| **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    | 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                                            |

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


# 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 [Elevated Session State](/security) 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

![PowerShell ISE](/files/-LA37bAsw4QRxUOSA4FB)

* **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](/files/-LA37eOf8fIUMi-K6ryJ)

* **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](/files/-LA37eR3lxDQ7nJB82ui)

* **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](/files/-LA37eTZ6P_qSyFUnR1N)

## Shortcuts

Below are the shortcuts available in the ISE.

| **Shortcut**     | **Usage**                                                                                                     |
| ---------------- | ------------------------------------------------------------------------------------------------------------- |
| TAB              | Indent                                                                                                        |
| Ctrl             | Bypass cached variable value when pressed. [#1346](https://github.com/SitecorePowerShell/Console/issues/1346) |
| 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                                                                                        |
| 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                                                                             |

For more commands built into the script editor see [here](https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts)


# 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.

```powershell
$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](/files/-LA37baEGn4DhpmVo4cp)


# 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.

```powershell
Show-Alert -Title "SPE is great!"
```

No return value.

![Show Alert](/files/-LA37aOxrvqqPC8qWVRU)

### 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.

```powershell
Show-Confirm -Title "Click OK to acknowledge SPE is great!"
```

| Button Name | Return Value |
| ----------- | ------------ |
| OK          | yes          |
| Cancel      | no           |

![Show Confirm](/files/-LA37aQmP4kTQBMiemQN)

### User Input

**Example:** The following displays an input dialog for text.

```powershell
Show-Input "Please provide 5 characters at most" -MaxLength 5
```

| Button Name | Return Value   |
| ----------- | -------------- |
| OK          | < user input > |
| Cancel      | $null          |

![Show Input](/files/-LA37aTHqFdpEYvqwB9U)

**Example:** The following displays an input dialog with a error validation message.

```powershell
$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
```

![Show Input](/files/-LA37aVTEzFVqi3bc-0r)

## 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.

```powershell
$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
```

| Button Name   | Return Value  |
| ------------- | ------------- |
| OK            | ok            |
| Cancel        | cancel        |
| < variables > | < selection > |

![Read Variable](/files/-LA37adhgx8EMJEwu23M)

**Supported Parameter Values**

| Key                    | Type                                | Description                                          | Example                   |
| ---------------------- | ----------------------------------- | ---------------------------------------------------- | ------------------------- |
| Name                   | string                              | Variable name                                        | isSilent                  |
| Value                  | bool string int float datetime Item | Default value                                        | $true                     |
| Title                  | string                              | Header or Label                                      | "Proceed Silently         |
| 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                   |

**Editor Types**

* bool
* check
* date
* date time
* 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

### 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.

```powershell
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
```

**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 |
| ----------------- | ------------ |
| < first button >  | btn\_0       |
| < second button > | btn\_1       |
| < third button >  | btn\_2       |

![Show Confirm Choice](/files/-LA37bLnOCk9ayinFLqy)

### 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.

```powershell
Receive-File (Get-Item "master:\media library\Files") -AdvancedDialog
```

No return value.

![Receive File](/files/-LA37bS9eyUSNZPsoLMB)

### Download

The *Download* dialog provides a way to download files from the server to a local filesystem.

**Example:** The following displays a download dialog.

```powershell
Get-Item -Path "master:\media library\Files\readme" | Send-File
```

![Download](/files/-LA37bYg5V-_p9xxD143)

### 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.

```powershell
Get-Item "master:\content\home" | Show-FieldEditor -Name "*" -PreserveSections
```

| Button Name | Return Value |
| ----------- | ------------ |
| OK          | ok           |
| Cancel      | cancel       |

![Show Field Editor](/files/-LA37bj-BZAc8wiZyjgT)

### 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.

```powershell
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"
```

| Button Name | Return Value      |
| ----------- | ----------------- |
| OK          | < selected file > |
| Cancel      | undetermined      |

![Show File Browser](/files/-LA37bycwZEVOMJCh7HT)

**Example:** The following displays a simple file browser dialog.

```powershell
Show-ModalDialog -HandleParameters @{
    "h"="FileBrowser";
} -Control "FileBrowser" -Width 500
```

| Button Name | Return Value      |
| ----------- | ----------------- |
| OK          | < selected file > |
| Cancel      | undetermined      |

![Show File Browser](/files/z6qY6ogQTagDHDNpFZ59)

**Example:** The following displays a Sheer UI control without any additional parameters.

```powershell
Show-ModalDialog -Control "SetIcon"
```

### 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.

```powershell
Get-Item -Path master:\* | Show-ListView -Property Name, DisplayName, ProviderPath, TemplateName, Language
```

![Show List View](/files/-LA37cJjfk9g07hQjpn5)

### 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.

```powershell
for($i = 0; $i -lt 10; $i++) {
    Write-Verbose "Index = $($i)" -Verbose
}

Show-Result -Text
```

![Show Result Text](/files/-LA37cUH95sVrTG4NVt_)


# 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](/files/-Lmk9pxJZEdR2ktWKc1o)

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

![Paged results of commands](/files/-Lmk9pxLw__HKVysDQ6g)

## Viewing command help

### Console

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

```powershell
Get-Help Get-Rendering
```

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

```powershell
Get-Help Get-Rendering -Full
```

### 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.

![Highlight the command and press Ctrl + Enter](/files/-Lmk9pxNpWAAynh8oOKe)

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

![A help dialog for Get-Rendering](/files/-Lmk9pxPbhhHENCqW-7b)

## 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:

```powershell
<#
    .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
} 
```

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

```powershell
Get-Help Output-String
```

For further information on comment-based help, refer to the [official PowerShell documentation](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comment_based_help).

## 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 [Command Appendix](/appendix).


# 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                                                                                    |
| ------------------ | --------------------------------- | ------------------------------------------------------------------------------------------ |
| `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`                               |

## Documentation Topics

### Fundamentals

Before working with items, understand these foundational concepts:

* [**Providers**](/working-with-items/providers) - PowerShell providers and navigating Sitecore databases
* [**Variables**](/working-with-items/variables) - Built-in variables available in SPE scripts

### Core Item Operations

Learn how to perform essential item operations:

* [**Retrieving Items**](/working-with-items/retrieving-items) - Find items by path, ID, query, or URI
* [**Editing Items**](/working-with-items/editing-items) - Update properties, work with field types, and manage versions
* [**Creating and Removing Items**](/working-with-items/creating-and-removing-items) - Create new items and delete existing ones
* [**Moving and Copying Items**](/working-with-items/moving-and-copying-items) - Transfer and duplicate items

### Specialized Operations

Handle specific aspects of item management:

* [**Item Languages**](/working-with-items/item-languages) - Add, remove, and manage language versions
* [**Item Renderings**](/working-with-items/item-renderings) - Work with presentation details and renderings
* [**Item Security**](/working-with-items/item-security) - Manage item permissions and access control

### Advanced Topics

Optimize your scripts and follow best practices:

* [**Best Practices**](/working-with-items/best-practices) - Performance optimization, bulk operations, and coding patterns

## Common Patterns

### Pattern: Find and Update Items

```powershell
# 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"
    }
```

### Pattern: Bulk Create Items

```powershell
# 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"
}
```

### Pattern: Copy Content Between Databases

```powershell
# 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
```

### Pattern: Audit and Report

```powershell
# 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"
```

## 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
* **Query** - Execute Sitecore queries (`query:` or `fast:`)
* **ID** - Work with items by GUID
* **Uri** - Use ItemUri for complete item identification

See the [Retrieving Items](/working-with-items/retrieving-items) page for detailed parameter documentation.

## Path Formats

SPE supports multiple path formats for flexibility:

```powershell
# 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"
```

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:

```powershell
$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"
```

See [Editing Items](/working-with-items/editing-items) 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
* Batch operations and provide progress feedback

See [Best Practices](/working-with-items/best-practices) for detailed performance guidance.

## See Also

* [**Security**](/security) - Securing SPE and managing users/roles
* [**Appendix - Common**](/appendix/common) - Core cmdlet reference
* [**Appendix - Security**](/appendix/security) - Security cmdlet reference
* [**Remoting**](/remoting) - Automate item operations remotely

## Getting Help

```powershell
# 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" }
```


# 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:

```powershell
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}
```

## 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.

```powershell
Get-PSProvider -PSProvider Sitecore

Name     Capabilities                           Drives
----     ------------                           ------
Sitecore Filter, ExpandWildcards, ShouldProcess {master, web, core}
```

### FileSystem Provider

The FileSystem provider allows interaction with the server's file system.

**Example:** Access file system from SPE.

```powershell
# 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"
```

## PowerShell Drives

Drives are the access points for providers. SPE creates drives for each Sitecore database.

### Sitecore Database Drives

**Example:** List all available drives.

```powershell
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
```

### Drive Structure

Each Sitecore database drive has the following structure:

```
master:\
├── content\
├── layout\
├── media library\
├── system\
└── templates\
```

The root of each drive represents `/sitecore` in Sitecore paths.

{% hint style="info" %}
The text `/sitecore` or `\sitecore` is typically omitted when using the drive names such as `core:`, `master:` and `web:`.
{% endhint %}

## Navigating Between Providers

Use `cd` or `Set-Location` to switch between drives and providers.

**Example:** Navigate between Sitecore databases.

```powershell
# 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:\>
```

**Example:** Navigate between providers.

```powershell
# Switch to file system
PS master:\> cd C:\
PS C:\>

# Return to master database
PS C:\> cd master:
PS master:\>
```

{% hint style="warning" %}
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.
{% endhint %}

## Path Formats

The `Sitecore` provider supports multiple path formats for flexibility.

### Provider Path Format (Recommended)

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

### Sitecore Path Format

```powershell
Get-Item -Path "master:/sitecore/content/home"
```

### Mixed Separators

Both forward and backward slashes work interchangeably:

```powershell
Get-Item -Path "master:\content/home"
Get-Item -Path "master:/content\home"
```

### Relative Paths

Use relative paths when you're already in a specific location:

```powershell
PS master:\content> Get-Item -Path ".\home"
PS master:\content> cd home
PS master:\content\home> Get-Item -Path ".."  # Returns parent (\content)
```

## Provider-Specific Features

### Dynamic Parameters

When using the `Sitecore` provider, cmdlets gain Sitecore-specific dynamic parameters:

**Example:** Using dynamic parameters.

```powershell
# 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']"
```

### Property Access

The `Sitecore` provider exposes Sitecore item properties through PowerShell properties:

**Example:** Access item properties.

```powershell
$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
```

## Common Provider Patterns

### Pattern: Work with Multiple Databases

```powershell
$databases = @("master", "core", "web")

foreach($db in $databases) {
    $itemCount = (Get-ChildItem -Path "$($db):\content" -Recurse).Count
    Write-Host "$db database: $itemCount items"
}
```

### Pattern: Compare Items Across Databases

```powershell
$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"
}
```

### Pattern: File System Operations

```powershell
# 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"
```

### Pattern: Working Directory Management

```powershell
# Save current location
Push-Location

# Do work in another location
cd "master:\templates"
# ... perform operations ...

# Return to previous location
Pop-Location
```

### Pattern: Cross-Provider Operations

```powershell
# 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"
}
```

## 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`                          |
| `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"`      |

### Testing Paths

**Example:** Verify item existence.

```powershell
if (Test-Path "master:\content\home") {
    Write-Host "Item exists"
    $item = Get-Item -Path "master:\content\home"
} else {
    Write-Host "Item not found"
}
```

**Example:** Conditional operations based on existence.

```powershell
$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
```

## Advanced Provider Usage

### Using Provider Paths

Get the full provider path for an item:

**Example:** Access provider path.

```powershell
$item = Get-Item -Path "master:\content\home"
$item.ProviderPath

# master:\content\home
```

### Custom Drive Creation

While rare, you can create custom drives:

**Example:** Create a drive pointing to a specific location.

```powershell
New-PSDrive -Name "content" -PSProvider Sitecore -Root "master:\content"

# Now you can use:
Get-Item -Path "content:\home"
```

### Provider Capabilities

Check what a provider can do:

**Example:** View provider capabilities.

```powershell
(Get-PSProvider -PSProvider Sitecore).Capabilities

# Filter, ExpandWildcards, ShouldProcess
```

## Troubleshooting

### Issue: Dynamic Parameters Not Appearing

**Symptom:** Parameters like `-Language` or `-ID` are not available.

**Solution:** Ensure you're specifying a database path:

```powershell
# 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}"
```

### Issue: File System Path Behavior

**Symptom:** `cd C:` doesn't go to C:\ root.

**Solution:** Always include the backslash for FileSystem provider root:

```powershell
# WRONG
cd C:

# CORRECT
cd C:\
```

### Issue: Path Not Found

**Symptom:** "Cannot find path" error.

**Solution:** Verify the item exists and the path is correct:

```powershell
# 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."
}
```

## Performance Considerations

### Provider vs. Direct API

The `Sitecore` provider adds convenience but may have overhead for large operations:

```powershell
# 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
```

### Caching

Providers may cache data. If you're seeing stale data:

```powershell
# Clear caches
$db = Get-Database -Name "master"
$db.Caches.ItemCache.Clear()
$db.Caches.DataCache.Clear()
```

## See Also

* [Variables](/working-with-items/variables) - Built-in variables for paths
* [Retrieving Items](/working-with-items/retrieving-items) - Finding items using providers
* [Best Practices](/working-with-items/best-practices) - Performance optimization

## References

* [PowerShell Providers Documentation](https://docs.microsoft.com/en-us/powershell/scripting/developer/provider/windows-powershell-provider-overview)
* [Issue #314 - FileSystem Provider Behavior](https://github.com/SitecorePowerShell/Console/issues/314)


# 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                                                                        |
| 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                                                                            |

**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.


# 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 `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 | `-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`                                   |

## Retrieving by Path

The most common way to retrieve items is by their Sitecore path.

**Example:** Retrieve an item by path.

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

**Output:**

```powershell
Name Children Language Version Id                                     TemplateName
---- -------- -------- ------- --                                     ------------
Home True     en       2       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
```

{% hint style="info" %}
The `/sitecore` portion of the path is optional. Both `master:\content\home` and `master:\sitecore\content\home` work identically.
{% endhint %}

**Example:** The C# equivalent for reference.

```csharp
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Items.Item item = master.GetItem("/sitecore/content/home");
```

## Working with Languages

Retrieve items in specific languages or all languages using the `-Language` parameter with wildcards.

{% hint style="warning" %}
When working with multi-language sites, you may find that specifying the `-Language` parameter results in a more consistent behavior.
{% endhint %}

**Example:** Retrieve the Danish version of an item.

```powershell
Get-Item -Path "master:\content\home" -Language "da" |
    Format-Table DisplayName, Language, Id, Version, TemplateName
```

**Output:**

```powershell
DisplayName Language ID                                     Version TemplateName
----------- -------- --                                     ------- ------------
Hjem        da       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} 1       Sample Item
```

**Example:** Retrieve latest version for all languages.

```powershell
Get-Item -Path "master:\content\home" -Language * |
    Format-Table DisplayName, Language, Id, Version, TemplateName
```

**Output:**

```powershell
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
```

## Working with Versions

Retrieve specific versions or all versions using the `-Version` parameter.

**Example:** Retrieve all versions in all languages.

```powershell
Get-Item -Path "master:\content\home" -Language * -Version * |
    Format-Table DisplayName, Language, Id, Version, TemplateName
```

**Output:**

```powershell
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
```

**Example:** Using wildcards for partial matches (all English variants).

```powershell
Get-Item -Path "master:\content\home" -Language "en","en-*"
```

## Retrieving Children

Use `Get-ChildItem` to retrieve an item's children, with optional recursion.

**Example:** Retrieve immediate children only.

```powershell
Get-ChildItem -Path "master:\content"
```

**Example:** Retrieve all descendants recursively.

```powershell
Get-ChildItem -Path "master:\content\home" -Recurse
```

**Example:** Retrieve children in all languages and versions.

```powershell
Get-ChildItem -Path "master:\content" -Language * -Version * |
    Format-Table DisplayName, Language, Id, Version, TemplateName
```

## 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.

```powershell
Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}" -Language *
```

**Output:**

```powershell
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
```

{% hint style="info" %}
When using `-ID`, you must specify the database path (e.g., `master:`) to activate the dynamic parameter.
{% endhint %}

## Retrieving by URI

ItemUri encodes the database, item ID, language, and version in a single string.

**Example:** Retrieve an item by URI.

```powershell
Get-Item -Path "master:" -Uri "sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1"
```

**Output:**

```powershell
Name Children Language Version Id                                     TemplateName
---- -------- -------- ------- --                                     ------------
Home True     en       1       {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} Sample Item
```

## Sitecore Query

Use Sitecore query to find items matching complex criteria. This is more efficient than traversing the tree when you need specific items.

{% hint style="warning" %}
Sitecore query paths containing reserved keywords or spaces require `#` delimiters: `#path with spaces#`
{% endhint %}

**Example:** Find all items with a specific template.

```powershell
Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']"
```

**Output:**

```powershell
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
```

**Example:** Query with language and version wildcards.

```powershell
Get-Item -Path "master:" -Query "/sitecore/content//*[@@templatename='Sample Item']" -Language * -Version * |
    Format-Table DisplayName, Language, Id, Version, TemplateName -AutoSize
```

**Example:** Query using dates (ISO format required) filtering by the publishing restriction where the item (not version) has a future date.

```powershell
$isoDate = [Sitecore.DateUtil]::ToIsoDate([datetime]::Today)
Get-Item -Path "master:" -Query "/sitecore/content/home//*[@__Publish > '$($isoDate)']" |
    Show-ListView -Property ID, Name, ItemPath
```

## Fast Query

{% hint style="warning" %}
Sitecore has deprecated this functionality in XM/XP 10.1.
{% endhint %}

## 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.

```powershell
$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"
```

## Custom Property Sets

Use custom property sets with `Select-Object` to retrieve specific groups of properties.

**Example:** Retrieve security properties using PSSecurity.

```powershell
Get-Item -Path "master:\content\home" | Select-Object -Property PSSecurity
```

**Output:**

```powershell
Name ID                                     __Owner        __Security
---- --                                     -------        ----------
Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} sitecore\Admin ar|sitecore\Developer|pd|+item:read|pe|+item:read|
```

{% hint style="info" %}
Check out [Item Security](/working-with-items/item-security) to learn about managing the security settings using SPE.
{% endhint %}

**Example:** Retrieve template information using PSTemplate.

```powershell
Get-Item -Path "master:" -ID "{04DAD0FD-DB66-4070-881F-17264CA257E1}" | Select-Object -Property PSTemplate
```

**Output:**

```powershell
Name  ID                                     BaseTemplate
----  --                                     ------------
cover {04DAD0FD-DB66-4070-881F-17264CA257E1} {Image, File, Standard template, Advanced...}
```

**Example:** Retrieve image metadata using PSImage.

```powershell
Get-Item -Path "master:\media library\Default Website\cover" | Select-Object -Property PSImage
```

**Output:**

```powershell
Name      : cover
ID        : {04DAD0FD-DB66-4070-881F-17264CA257E1}
Alt       :
Width     : 1600
Height    : 550
Extension : jpg
Size      : 119719
```

**Example:** Retrieve schedule information using PSSchedule.

```powershell
Get-Item -Path "master:\system\Tasks\Schedules\Forms\FileStorageCleanup" |
    Select-Object -Property PSSchedule
```

**Output:**

```powershell
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    :
```

## 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.

```powershell
# 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
```

## Common Retrieval Patterns

### Pattern: Find Items by Template

```powershell
# 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']"
```

### Pattern: Find Recently Modified Items

```powershell
$cutoffDate = (Get-Date).AddDays(-7)
Get-ChildItem -Path "master:\content" -Recurse |
    Where-Object { $_.__Updated -gt $cutoffDate }
```

### Pattern: Find Items by Field Value

```powershell
# 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')]"
```

### Pattern: Get All Media Items Above Size Threshold

```powershell
Get-ChildItem -Path "master:\media library" -Recurse |
    Where-Object { $_.Size -gt 1MB } |
    Select-Object Name, Size, Extension, ItemPath
```

## 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](/working-with-items/editing-items) - Update item properties and fields
* [Best Practices](/working-with-items/best-practices) - Performance optimization guidance
* [Appendix - Common Commands](/appendix/common) - Full cmdlet reference

## References

* [Performance details for different query methods](https://sitecore.stackexchange.com/questions/6803/sitecore-powershell-query-for-big-images-of-a-certain-size/6811#6811)
* [Escaping queries with reserved keywords](https://sitecore.stackexchange.com/questions/10127/how-to-escape-a-query-in-sitecore-powershell)
* [Working with Sitecore Items in PowerShell Extensions](https://blog.najmanowicz.com/2014/10/12/working-with-sitecore-items-in-powershell-extensions/)


# 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
* **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.

```powershell
$item = Get-Item -Path "master:\content\home"
$item.Title = "New Title"
```

**Example:** Update a field with spaces in the name.

```powershell
$item = Get-Item -Path "master:\content\home"
$item."Closing Date" = [datetime]::Today
```

{% hint style="info" %}
Field names containing spaces must be wrapped in quotes (single or double).
{% endhint %}

**Example:** Update system fields.

```powershell
$item = Get-Item -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
$item."__Display name" = "Custom Display Name"
```

**Example:** Dynamically reference fields by variable.

```powershell
$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"
```

## Using Set-ItemProperty

The PowerShell-standard approach using `Set-ItemProperty` is also supported.

**Example:** Update a property using Set-ItemProperty.

```powershell
Set-ItemProperty -Path "master:\content\home" -Name "Title" -Value "New Title"
```

## 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.

```powershell
$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()
```

{% hint style="warning" %}
Always match `BeginEdit()` with `EndEdit()`. If an error occurs between them, the item remains locked. Consider using try/finally blocks for safety.
{% endhint %}

**Example:** Safe edit context with error handling.

```powershell
$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
}
```

## 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.

```powershell
$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
```

### Image Fields

Image fields accept item references from the Media Library.

**Example:** Assign an image to an Image field.

```powershell
$homeItem = Get-Item -Path "master:\content\home"
$homeItem.Image = Get-Item -Path "master:\media library\logo"
```

### Link Fields (General Link)

Link fields accept item references and automatically create the link XML.

**Example:** Assign a content item to a GeneralLink field.

```powershell
$homeItem = Get-Item -Path "master:\content\home"
$homeItem.GeneralLink = Get-Item -Path "master:\content\home\about-us"
```

### Multi-Value Fields

Multi-value fields (Multilist, Treelist, etc.) accept arrays of items.

**Example:** Assign multiple items to a list field.

```powershell
$homeItem = Get-Item -Path "master:\content\home"
$homeItem.ItemList = Get-ChildItem -Path "master:\content\home"
```

**Result in Content Editor:**

![ItemList Assignment](https://blog.najmanowicz.com/wp-content/uploads/2014/10/image1.png)

### Accessing Typed Fields

Use the `._` or `.PSFields` property to access strongly-typed field objects.

**Example:** Access typed Image field properties.

```powershell
$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
```

**Example:** Access typed LinkField properties.

```powershell
$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
```

**Output:**

```powershell
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          :
```

**Example:** Find all TextField instances on an item.

```powershell
$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)"
    }
}
```

## 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:**

```powershell
Get-ChildItem -Path "master:\content\home" |
    ForEach-Object {
        $_.Title = "Updated: $($_.Name)"
    }
```

### Use BeginEdit/EndEdit When:

* Updating many fields on a single item
* Needing explicit control over save timing
* Working with system properties (like BranchId)

**Example:**

```powershell
$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()
```

### Use BulkUpdateContext When:

* Updating many items (hundreds or thousands)
* Performance is critical
* You need to bypass certain Sitecore events

**Example:**

```powershell
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
    }
}
```

{% hint style="warning" %}
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.
{% endhint %}

## Bulk Update Patterns

### Pattern: Update Items with BulkUpdateContext

```powershell
$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
    }
}
```

### Pattern: Update with Progress Reporting

```powershell
$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
```

### Pattern: Conditional Updates

```powershell
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
    }
```

### Pattern: Update from CSV Data

```powershell
$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
    }
}
```

## 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.

```powershell
$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)
}
```

### 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).

```powershell
New-UsingBlock (New-Object Sitecore.SecurityModel.SecurityDisabler) {
    $items = Get-ChildItem -Path "master:\content" -Recurse
    # Process items without security checks
}
```

**Example:** Update items with events disabled.

```powershell
New-UsingBlock (New-Object Sitecore.Data.Events.EventDisabler) {
    foreach($item in $itemsToUpdate) {
        $item.Title = "Updated"
    }
}
```

## Advanced Editing Scenarios

### Update Items in Different Language

```powershell
$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"
```

### Update Specific Version

```powershell
$item = Get-Item -Path "master:\content\home" -Language "en-US" -Version 2
$item.Title = "Updated Version 2"
```

### Copy Field Values Between Items

```powershell
$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()
```

### Update Standard Values

```powershell
$template = Get-Item -Path "master:\templates\Sample\Sample Item"
$standardValues = Get-Item -Path "$($template.ProviderPath)\__Standard Values"
$standardValues.Title = "Default Title"
```

## Performance Optimization

### Avoid: Repeated Automated Property Updates

```powershell
# 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
}
```

### Prefer: Explicit BeginEdit/EndEdit

```powershell
# 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()
}
```

### Best: BulkUpdateContext for Large Datasets

```powershell
# 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
    }
}
```

## Common Pitfalls

### Pitfall: Forgetting to End Edit

```powershell
# BAD - item remains locked if error occurs
$item.Editing.BeginEdit()
$item["Title"] = "New Title"  # If this throws, EndEdit never called
$item.Editing.EndEdit()
```

```powershell
# GOOD - use try/finally
$item.Editing.BeginEdit()
try {
    $item["Title"] = "New Title"
    $item.Editing.EndEdit()
} catch {
    $item.Editing.CancelEdit()
    throw
}
```

### Pitfall: Modifying System Fields Without Care

```powershell
# 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"
```

### Pitfall: Assuming Item Exists

```powershell
# BAD - throws error if item doesn't exist
$item = Get-Item -Path "master:\content\missing"
$item.Title = "New Title"
```

```powershell
# GOOD - check for existence
$item = Get-Item -Path "master:\content\maybe-exists" -ErrorAction SilentlyContinue
if ($item) {
    $item.Title = "New Title"
}
```

## See Also

* [Retrieving Items](/working-with-items/retrieving-items) - Find items to edit
* [Best Practices](/working-with-items/best-practices) - Performance optimization
* [Item Languages](/working-with-items/item-languages) - Manage language versions
* [Appendix - Common Commands](/appendix/common) - Full cmdlet reference

## References

* [Working with Sitecore Items in PowerShell Extensions](https://blog.najmanowicz.com/2014/10/12/working-with-sitecore-items-in-powershell-extensions/)


# 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.

### Basic Item Creation

**Example:** Create an item by specifying template name.

```powershell
$itemPath = "master:\content\home\Sample Item 3"
New-Item -Path $itemPath -ItemType "Sample/Sample Item"
```

**Output:**

```powershell

Name                             Children Language Version Id                                     TemplateName
----                             -------- -------- ------- --                                     ------------
Sample Item 3                    False    en       1       {29A68114-5137-4A46-A87C-3789B8D898FB} Sample Item
```

{% hint style="info" %}
The `-ItemType` parameter accepts either the template path (e.g., "Sample/Sample Item") or the template ID.
{% endhint %}

**Example:** Create an item using template ID.

```powershell
$itemPath = "master:\content\home\Sample Item 4"
$templateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
New-Item -Path $itemPath -ItemType $templateId
```

### 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.

```powershell
$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
```

**Output:**

```powershell

Name                             Children Language Version Id                                     TemplateName
----                             -------- -------- ------- --                                     ------------
Sample Item 5                    False    en       1       {9459ADDD-4471-4ED3-A041-D33E559BD321} Sample Item
```

{% hint style="warning" %}
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.
{% endhint %}

### 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.

```powershell
$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
```

**Output:**

```powershell

Name                             Children Language Version Id                                     TemplateName
----                             -------- -------- ------- --                                     ------------
Sample Item 6                    False    en       1       {E7A73426-B9BB-4056-A15C-2E835796A4DD} Sample Item
```

### 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.

```powershell
$itemPath = "master:\content\home\Sample Item 7"
New-Item -Path $itemPath -ItemType "Sample/Sample Item" -Language "en-CA"
```

**Output:**

```powershell

Name                             Children Language Version Id                                     TemplateName
----                             -------- -------- ------- --                                     ------------
Sample Item 7                    False    en-CA    1       {5303A55C-5853-409D-AFC8-0DF04F4C1065} Sample Item
```

{% hint style="info" %}
When you specify a language during creation, only that language version is created. Other language versions are not automatically added.
{% endhint %}

### Starting Workflows

Use the `-StartWorkflow` parameter to initiate the default workflow after item creation.

**Example:** Create an item and start its workflow.

```powershell
$itemPath = "master:\content\home\Sample Item 8"
New-Item -Path $itemPath -ItemType "Sample/Sample Item" -StartWorkflow
```

### Setting Field Values During Creation

After creating an item, you can immediately set field values.

**Example:** Create and populate an item.

```powershell
$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"
```

## Bulk Item Creation

### Pattern: Create Items from CSV

```powershell
# 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
}
```

### Pattern: Create Items with Progress Reporting

```powershell
$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
```

### Pattern: Create Hierarchical Structure

```powershell
$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"
    }
}
```

### Pattern: Create Items from JSON

```powershell
$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
}
```

## 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).

```powershell
Remove-Item -Path "master:\content\home\Sample Item 3"
```

**Example:** Remove an item permanently (bypasses Recycle Bin).

```powershell
Remove-Item -Path "master:\content\home\Sample Item 3" -Permanently
```

{% hint style="danger" %}
Using `-Permanently` cannot be undone. Items are deleted from the database immediately. Use with extreme caution, especially in production environments.
{% endhint %}

### Removing Items via Pipeline

**Example:** Remove items from pipeline.

```powershell
Get-Item -Path "master:\content\home\delete-me" | Remove-Item
```

**Example:** Remove multiple items matching criteria.

```powershell
Get-ChildItem -Path "master:\content\temp" -Recurse |
    Where-Object { $_.Name -like "Test*" } |
    Remove-Item
```

### Bulk Removal Patterns

### Pattern: Remove Old Items

```powershell
$cutoffDate = (Get-Date).AddYears(-2)
Get-ChildItem -Path "master:\content\archive" -Recurse |
    Where-Object { $_.__Created -lt $cutoffDate } |
    Remove-Item -Permanently
```

### Pattern: Remove Items by Template

```powershell
Get-ChildItem -Path "master:\content\home" -Recurse |
    Where-Object { $_.TemplateName -eq "Temporary Item" } |
    Remove-Item
```

### Pattern: Clean Up Empty Folders

```powershell
Get-ChildItem -Path "master:\content\home" -Recurse |
    Where-Object { $_.TemplateName -eq "Folder" -and -not $_.HasChildren } |
    Remove-Item
```

### Pattern: Remove with Confirmation

```powershell
$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
    }
}
```

### Pattern: Safe Removal with Reporting

```powershell
$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
```

## 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             | `-Parent $parentItem` |
| StartWorkflow | New-Item    | Initiates default workflow        | `-StartWorkflow`      |
| Permanently   | Remove-Item | Bypasses Recycle Bin              | `-Permanently`        |
| FailSilently  | Remove-Item | Suppresses errors                 | `-FailSilently`       |

## 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.

```powershell
$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
```

```powershell
$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
```

## Error Handling

Always handle potential errors when creating or removing items.

### Pattern: Create with Error Handling

```powershell
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
}
```

### Pattern: Bulk Create with Error Logging

```powershell
$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
```

## 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.

```powershell
$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()
```

## See Also

* [Retrieving Items](/working-with-items/retrieving-items) - Find items to work with
* [Editing Items](/working-with-items/editing-items) - Update item properties
* [Moving and Copying Items](/working-with-items/moving-and-copying-items) - Transfer items
* [Best Practices](/working-with-items/best-practices) - Performance optimization
* [Appendix - Common Commands](/appendix/common) - Full cmdlet reference

## References

* [Working with Sitecore Items in PowerShell Extensions](https://blog.najmanowicz.com/2014/10/12/working-with-sitecore-items-in-powershell-extensions/)


# 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.

### Basic Move Operations

**Example:** Move an item to a new parent.

```powershell
$sourcePath = "master:\content\home\sample item"
$destinationPath = "master:\content\home\moved"
Move-Item -Path $sourcePath -Destination $destinationPath
```

{% hint style="info" %}
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.
{% endhint %}

**Example:** Move and rename in one operation.

```powershell
# 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
```

### Moving via Pipeline

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

```powershell
Get-Item -Path "master:" -ID "{65736CA0-7D69-452A-A16F-2F42264D21C5}" |
    Move-Item -Destination "master:{DFDDF372-3AB7-45B1-9E7C-0D0B27350439}"
```

### Moving with Children

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

**Example:** Move an entire content tree.

```powershell
Move-Item -Path "master:\content\home\old-section" `
          -Destination "master:\content\archive\"
```

## 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.

```powershell
$originalPath = "master:\content\home\original"
$copyPath = "master:\content\home\copy"
Copy-Item -Path $originalPath -Destination $copyPath
```

{% hint style="info" %}
The item name in the destination path determines the new item's name. Lowercase names in the destination result in lowercase item names.
{% endhint %}

**Example:** Copy and return the new item.

```powershell
$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)"
```

### Recursive Copying

**Example:** Copy an entire tree maintaining structure.

```powershell
$sourceId = "{AF27FAD3-2AF0-4682-9BF7-375197587579}"
$destinationId = "{53F94442-555B-4622-B813-A16ED2CAB01B}"

Get-Item -Path "master:" -ID $sourceId | Copy-Item -Destination $destinationId -Recurse
```

### 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.

```powershell
Copy-Item -Path "master:\content\home" `
          -Destination "web:\content\home" `
          -TransferOptions 0
```

{% hint style="warning" %}
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.
{% endhint %}

### 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).

```powershell
# 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
```

## Bulk Operations

### Pattern: Move Multiple Items

```powershell
Get-ChildItem -Path "master:\content\temp" -Recurse |
    Where-Object { $_.TemplateName -eq "Sample Item" } |
    ForEach-Object {
        Move-Item -Path $_.ProviderPath -Destination "master:\content\archive"
    }
```

### Pattern: Copy Items Based on Criteria

```powershell
$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"
    }
```

### Pattern: Reorganize Content Structure

```powershell
# 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)"
    }
```

### Pattern: Copy with Progress Reporting

```powershell
$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
```

## Maintaining Structure

### Pattern: Copy Tree Maintaining Hierarchy

```powershell
$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
```

## 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)     | `-TransferOptions 0`       |
| PassThru        | Copy-Item            | Returns the new item                     | `-PassThru`                |
| Recurse         | Copy-Item            | Includes all descendants                 | `-Recurse`                 |

## 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

```powershell
# BAD - if parent doesn't exist, item is renamed
Move-Item -Path "master:\content\home\demo" `
          -Destination "master:\content\nonexistent"
```

```powershell
# 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
}
```

### Pitfall: Copying Without PassThru

```powershell
# BAD - can't access the new item
Copy-Item -Path "master:\content\home\demo" -Destination "master:\content\copy"
# No reference to the copied item
```

```powershell
# 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"
```

## See Also

* [Retrieving Items](/working-with-items/retrieving-items) - Find items to move or copy
* [Creating and Removing Items](/working-with-items/creating-and-removing-items) - Item lifecycle management
* [Best Practices](/working-with-items/best-practices) - Performance optimization
* [Appendix - Common Commands](/appendix/common) - Full cmdlet reference

## References

* [Working with Sitecore Items in PowerShell Extensions](https://blog.najmanowicz.com/2014/10/12/working-with-sitecore-items-in-powershell-extensions/)


# Item Languages

The section on [working with items](/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.

```powershell
Get-ChildItem "master:\content" -Recurse |
    Add-ItemLanguage -Language "en-us" -TargetLanguage "en-ca" -IfExist OverwriteLatest
```

**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.

```powershell
$languageParameters = @{
    Path = "master:\content\home"
    Language = "en"
    TargetLanguage = @("pl-pl","en-us")
    IfExist = "Skip"
    IgnoredFields = @("Title")
}
Add-ItemLanguage @languageParameters
```

**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`.

```powershell
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
```

**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.

```powershell
Add-ItemLanguage -Path "master:\content\home" -TargetLanguage "pl-pl" -IfExist Skip -DoNotCopyFields -Recurse
```

## Remove Language Version

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

```powershell
Get-ChildItem "master:\content" -Recurse |
    Remove-ItemLanguage -Language "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.

```powershell
$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
```

## Parameters and Configuration

Supported parameters:

* `-Recurse` Translates item and its children
* `-IfExist` Accepts one of 3 pretty self explanatory actions: `Skip`, `Append` or `OverwriteLatest`
* `-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.

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

```xml
<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>
```

### References

* [Issue 184](https://github.com/SitecorePowerShell/Console/issues/184)
* [Remove All Content items in French](https://stackoverflow.com/questions/29928540/powershell-script-to-remove-all-content-items-for-french-version-in-sitecore)


# 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.

```powershell
$defaultLayout = Get-LayoutDevice -Default
$rootItem = Get-Item -Path "master:" -ID "{961563FC-3445-4558-BF3A-06DF06BA6298}"
Get-Rendering -Item $rootItem -Device $defaultLayout -FinalLayout
```

### Update rendering parameters

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

```powershell
$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)" 
    } 
}
```

### Find pages using rendering

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

```powershell
Get-Item "master:\layout\Renderings\Feature\Experience Accelerator\Page Content\Page Content" | 
    Get-ItemReferrer | Where-Object { $_.ContentPath.StartsWith("/Demo/usa/Home") } | Show-ListView
```

### Find renderings marked cacheable

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

```powershell
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
```

### Find renderings with personalization

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

```powershell
$query = "fast:/sitecore/content//*[@__renderings='%<conditions%' or @#__Final Renderings#='%<conditions%']"
$items = Get-Item -Path "master:" -Query $query
```

### Disable cacheable setting on renderings

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

```powershell
$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
```

### Move renderings between placeholders

**Example:** The following moves renderings from one placeholder to another. [See this article for more details](https://www.kasaku.co.uk/2018/02/28/updating-rendering-placeholders/).

```powershell
$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])"
            }
        }
    }
}
```

### Remove datasource from rendering

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

```powershell
Get-Rendering -Item $item -PlaceHolder "main" | 
  Foreach-Object { Set-Rendering -Item $item -Instance $_ -DataSource $null -FinalLayout }
```

### Replace compatible rendering

```powershell
$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
```

### Further Reading

* [Parse raw layout xml and count components](https://sitecore.stackexchange.com/questions/4952/get-amount-of-components-on-final-layout-programmatically)


# 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                           |
| ------------ | ------------------------------------- |
| 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              |
| field:read   | Read specific fields                  |
| field:write  | Write specific fields                 |
| \*           | Rights may be inherited by decendants |

### Propagation Types

Control how access rules propagate through the content tree:

| Propagation Type | Description                                      |
| ---------------- | ------------------------------------------------ |
| Any              | Applies to item and descendants                  |
| Descendants      | Applies only to descendants, not the item itself |
| Entity           | Applies only to this specific item               |

### Security Permissions

| Permission Type  | Description                                     |
| ---------------- | ----------------------------------------------- |
| 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  |

### Raw Serialized Security Field

| Text | Description             |
| ---- | ----------------------- |
| ar   | Role account type       |
| au   | User account type       |
| pd   | Propagate descendants   |
| pe   | Propagate entity (item) |
| p\*  | Propagate any           |
| ^    | Allow inheritance       |
| !    | Deny inheritance        |
| +    | Allow access            |
| -    | Deny access             |

**Example:** The `sitecore\Author` role allowed access to read the item.

```
ar|sitecore\Author|pe|+item:read|
```

**Example:** The `sitecore\Author` role denied access to read the item descendants.

```
ar|sitecore\Author|pd|-item:read|
```

**Example:** Security rights for the parent item are not passed to the child items. Inheritance to descendants are denied for the `sitecore\Author` role.

```
ar|sitecore\Author|pd|^*|
```

**Example:** The `sitecore\Developer` role is allowed access to read the item and descendants.

```
ar|sitecore\Developer|pd|+item:read|pe|+item:read|
```

## Security Commands

Use `Get-Command` to discover all security-related commands:

```powershell
Get-Command -Noun Role*,User,ItemAcl* | Select-Object -Property Name | Sort-Object -Property Name
```

## 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.

```powershell
Get-Item -Path "master:\content\home" | Select-Object -Property PSSecurity
```

**Output:**

```powershell
Name ID                                     __Owner        __Security
---- --                                     -------        ----------
Home {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} sitecore\Admin ar|sitecore\Developer|pd|+item:read|pe|+item:read|
```

**Example:** Get detailed ACL information.

```powershell
$item = Get-Item -Path "master:\content\home"
Get-ItemAcl -Item $item
```

**Output:**

```powershell
Account            AccessRight PermissionType PropagationType SecurityPermission
-------            ----------- -------------- --------------- ------------------
sitecore\Developer item:read   Access         Descendants     AllowAccess
sitecore\Developer item:read   Access         Entity          AllowAccess
```

### 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.

```powershell
$devRead = @{
    "Identity" = "sitecore\Developer"
    "PropagationType" = "Any"
    "SecurityPermission" = "AllowInheritance"
    "AccessRight" = "item:read"
}

$acl = New-ItemAcl @devRead
```

**Example:** Create an ACL denying inheritance.

```powershell
$everyoneDeny = @{
    "Identity" = "\Everyone"
    "PropagationType" = "Any"
    "SecurityPermission" = "DenyInheritance"
    "AccessRight" = "*"
}

$acl = New-ItemAcl @everyoneDeny
```

### Applying Access Rules

Use `Add-ItemAcl` to apply access rules to items.

**Example:** Apply an ACL to an item.

```powershell
$aclForEveryone = @{
    "Identity" = "\Everyone"
    "PropagationType" = "Any"
    "SecurityPermission" = "DenyInheritance"
    "AccessRight" = "*"
}

$acl = New-ItemAcl @aclForEveryone

Get-Item -Path "master:\content\home" |
    Add-ItemAcl -AccessRules $acl -PassThru
```

**Example:** Grant role-specific access.

```powershell
$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
```

**Output:**

```powershell
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
```

![Assign Security Rights Dialog](/files/hu4xxqzR3pafSEQYHQqG)

### Modifying Access Rules

Use `Set-ItemAcl` to replace existing access rules.

**Example:** Replace all access rules on an item.

```powershell
$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
```

### Removing Access Rules

Use `Clear-ItemAcl` to remove access rules from items.

**Example:** Clear all custom access rules.

```powershell
Get-Item -Path "master:\content\home" | Clear-ItemAcl
```

### 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.

```powershell
$item = Get-Item -Path "master:\content\home"
$user = Get-Role -Identity "sitecore\Author"
Test-ItemAcl -Item $item -User $user -AccessRight "item:read"
```

## Bulk Security Operations

### Pattern: Apply Security to Content Item

```powershell
$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
```

### Pattern: Apply Security to Content Tree

```powershell
$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)"
}
```

### Pattern: Security Audit Report

```powershell
$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
```

### Pattern: Clone Security Settings

```powershell
# 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 Locking

Prevent other users from editing items by locking them.

### Locking Items

**Example:** Lock an item for editing.

```powershell
$item = Get-Item -Path "master:\content\home"
Lock-Item -Item $item
```

**Example:** Lock items in bulk.

```powershell
Get-ChildItem -Path "master:\content\protected" -Recurse |
    ForEach-Object {
        Lock-Item -Item $_
        Write-Host "Locked: $($_.ItemPath)"
    }
```

### Unlocking Items

**Example:** Unlock an item.

```powershell
$item = Get-Item -Path "master:\content\home"
Unlock-Item -Item $item
```

**Example:** Unlock all items in a tree.

```powershell
Get-ChildItem -Path "master:\content\protected" -Recurse |
    Where-Object { $_.Locking.IsLocked() } |
    ForEach-Object {
        Unlock-Item -Item $_
        Write-Host "Unlocked: $($_.ItemPath)"
    }
```

### Checking Lock Status

**Example:** Check if an item is locked.

```powershell
$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 Protection

Protect items from accidental deletion or modification.

### Protecting Items

**Example:** Protect an item from deletion.

```powershell
$item = Get-Item -Path "master:\content\protected"
Protect-Item -Item $item
```

**Example:** Protect critical content.

```powershell
$criticalItems = Get-ChildItem -Path "master:\content\critical" -Recurse

foreach($item in $criticalItems) {
    Protect-Item -Item $item
    Write-Host "Protected: $($item.ItemPath)"
}
```

### Unprotecting Items

**Example:** Remove item protection.

```powershell
$item = Get-Item -Path "master:\content\home"
Unprotect-Item -Item $item
```

**Example:** Unprotect items in bulk.

```powershell
Get-ChildItem -Path "master:\content\temp" -Recurse |
    ForEach-Object {
        Unprotect-Item -Item $_
    }
```

## 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
5. **Test before production** - Always test security changes in development first
6. **Use SecurityDisabler cautiously** - Only in controlled, administrative scripts
7. **Principle of least privilege** - Grant minimum permissions necessary

## See Also

* [Security - Users and Roles](/security/users-and-roles) - Managing users and roles
* [Editing Items](/working-with-items/editing-items) - Update item properties
* [Best Practices](/working-with-items/best-practices) - Performance and security patterns
* [Appendix - Security Commands](/appendix/security) - Full security cmdlet reference

## References

* [Sitecore Security Guide](https://doc.sitecore.com/xp/en/developers/latest/platform-administration-and-architecture/security.html)
* [Principle of Least Privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege)


# Best Practices

This page provides guidance on writing efficient, maintainable, and performant SPE scripts for working with Sitecore items.

## Performance Optimization

### Query Method Selection

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)        | ⭐⭐          | ✓        | ✓              |
| Sitecore Query     | Specific criteria, medium trees | ⭐⭐          | ✓        | ✓              |
| `Find-Item`        | Large trees (>500 items)        | ⭐⭐⭐⭐        | ✓        | Partial        |

**Example:** Performance comparison for finding items by template.

```powershell
# 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
```

### Bulk Update Performance

When updating many items, use appropriate context objects to improve performance:

**Example:** Performance tiers for bulk updates.

```powershell
# 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
        }
    }
}
```

### 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.

```powershell
$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
```

### 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.

```powershell
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
```

### Error Handling

Implement comprehensive error handling:

**Example:** Robust error handling pattern.

```powershell
$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
```

## Progress Reporting

Always provide feedback for long-running operations:

**Example:** Comprehensive progress reporting.

```powershell
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)"
}
```

**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.

```powershell
$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"
    }
}
```

### Version Management

Handle versions carefully to avoid unintended consequences:

**Example:** Safe version operations.

```powershell
# 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)"
```

## Field Type Handling

### Type-Safe Field Access

Use typed field access when working with complex fields:

**Example:** Safe field type handling.

```powershell
$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)"
}
```

### Date Handling

Always use ISO format for date fields:

**Example:** Proper date handling.

```powershell
$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
```

## Testing and Validation

### Dry Run Support

Implement dry-run mode for destructive operations:

**Example:** Dry-run pattern.

```powershell
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
```

### Validation Before Operations

Validate data before making changes:

//TODO

## Logging and Auditing

### Comprehensive Logging

Log operations for audit trails:

**Example:** Logging pattern.

```powershell
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"
```

## Common Anti-Patterns

### ❌ Anti-Pattern: Not Checking Item Existence

```powershell
# BAD
$item = Get-Item -Path "master:\content\maybe-exists"
$item.Title = "New Title"  # Throws if item doesn't exist
```

```powershell
# GOOD
$item = Get-Item -Path "master:\content\maybe-exists" -ErrorAction SilentlyContinue
if ($item) {
    $item.Title = "New Title"
} else {
    Write-Warning "Item not found"
}
```

### ❌ Anti-Pattern: Inefficient Queries

//TODO

### ❌ Anti-Pattern: Swallowing Errors

```powershell
# BAD
foreach($item in $items) {
    try {
        $item.Title = "Updated"
    } catch {
        # Silent failure
    }
}
```

```powershell
# 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
}
```

## Performance Benchmarking

Use `Measure-Command` to identify bottlenecks:

**Example:** Performance comparison.

```powershell
# 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'))"
```

## See Also

* [Retrieving Items](/working-with-items/retrieving-items) - Query optimization techniques
* [Editing Items](/working-with-items/editing-items) - Update performance patterns
* [Item Security](/working-with-items/item-security) - Security best practices
* [Appendix - Common Commands](/appendix/common) - Cmdlet reference

## References

* [Sitecore Query Performance](https://sitecore.stackexchange.com/questions/6803/sitecore-powershell-query-for-big-images-of-a-certain-size/6811#6811)
* [PowerShell Best Practices](https://docs.microsoft.com/en-us/powershell/scripting/developer/cmdlet/cmdlet-development-guidelines)


# 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 [integration points](/modules/integration-points) 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.
* More reasons can be found in Adam's [post](https://github.com/SitecorePowerShell/Book/tree/9c7126d7a38df6ef372e8baef52f9a02baabd550/modules/\[https:/blog.najmanowicz.com/2014/11/01/sitecore-powershell-extensions-3-0-modules-proposal/]/README.md).

{% hint style="warning" %}
The *Platform* module is one you should avoid changing.
{% endhint %}

## 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](/files/-LA37dVXhhj8uPEGxIb4)
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](/files/-LA37_A5p7JMnQmXDmd1)
4. Select the appropriate integration points for your module.

   ![Integration Point Libraries](/files/-LA37_BdW8tzCH7IRNSP)
5. Select the module and enable for use.

   ![Module Activation](/files/-LA37dYPeRyhdRVg4rOM)
6. Open the ISE, switch to the *Settings* tab, and rebuild integrations.


# 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*.

```powershell
# /sitecore/system/modules/powershell/script library/spe rocks/functions/get-datemessage
function Get-DateMessage {
  "The current date and time is: $(Get-Date)"
}
```

```powershell
# /sitecore/system/modules/powershell/script library/spe rocks/alerts/show-datemessage
Import-Function -Name Get-DateMessage

Show-Alert (Get-DateMessage)
```

Some names we've used included:

* Beginner Tutorials
* **Content Editor**
* Content Maintenance
* Content Interrogation
* Development
* **Event Handlers**
* **Functions**
* **Internal**
* **Page Editor**
* **Pipelines**
* Profile and Security
* **Reports**
* Script Testing
* **Tasks**
* **Toolbox**
* User Interaction
* **Web API**

{% hint style="info" %}
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.
{% endhint %}

### 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 [#1388](https://github.com/SitecorePowerShell/Console/issues/1388)
    * where calling the *specific* PowerShell script returns value that *compares to* *value* [#1388](https://github.com/SitecorePowerShell/Console/issues/1388)
    * where *specific* persistent PowerShell session was already initiated [#153](https://github.com/SitecorePowerShell/Console/issues/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](https://github.com/SitecorePowerShell/Console/issues/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](https://github.com/SitecorePowerShell/Console/issues/383)
    * when the edited script is *in a state* [#383](https://github.com/SitecorePowerShell/Console/issues/383)
  * **PowerShell Security**
    * where the current user has delegated access [#1283](https://github.com/SitecorePowerShell/Console/issues/1283)
    * where the current user is a member of the *specific* role, either directory or through inheritance [#1036](https://github.com/SitecorePowerShell/Console/issues/1036)
  * **PowerShell System**
    * where the Sitecore.config numeric setting *name* *compares to* *number* [#1385](https://github.com/SitecorePowerShell/Console/issues/1385)
    * where the Sitecore.config string setting *name* *compares to* *value* [#1385](https://github.com/SitecorePowerShell/Console/issues/1385)
    * where the Web.config numeric AppSetting *name* *compares to* *number* [#1385](https://github.com/SitecorePowerShell/Console/issues/1385)
    * where the Web.config string setting *name* *compares to* *value* [#1385](https://github.com/SitecorePowerShell/Console/issues/1385)
* **EnableRule** (Enable if rules are met or not defined) - typically controls enabled state of integration points.
  * ***Same as above***

#### 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                                                                                 |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Content Editor [Context Menu](/modules/integration-points/content-editor#context-menu) | Content Editor [Context Menu](/modules/integration-points/content-editor#context-menu)     |
|                                                                                        | Content Editor [Gutter](/modules/integration-points/content-editor#gutter)                 |
| Content Editor [Insert Item](/modules/integration-points/content-editor#insert-item)   |                                                                                            |
| Content Editor [Ribbon](/modules/integration-points/content-editor#ribbon)             | Content Editor [Ribbon](/modules/integration-points/content-editor#ribbon)                 |
|                                                                                        | Content Editor [Warning](/modules/integration-points/content-editor#warning)               |
|                                                                                        | [DataSources](/modules/integration-points/data-sources)                                    |
|                                                                                        | [Event Handlers](/modules/integration-points/event-handlers)                               |
| ISE Plugin                                                                             | ISE Plugin                                                                                 |
| [Reports](/modules/integration-points/reports)                                         | [Reports](/modules/integration-points/reports)                                             |
| Reports List View Action                                                               | Reports List View Action                                                                   |
| Reports List View Export                                                               | Reports List View Export                                                                   |
|                                                                                        | Page Editor [Notification](/modules/integration-points/page-editor#notification)           |
|                                                                                        | Page Editor [Experience Button](/modules/integration-points/page-editor#experience-button) |
|                                                                                        | [Pipelines](/modules/integration-points/pipelines)                                         |
|                                                                                        | [Tasks](/modules/integration-points/tasks)                                                 |
| [Toolbox](/modules/integration-points/toolbox)                                         |                                                                                            |
|                                                                                        | [Workflow Action](/modules/integration-points/workflows)                                   |

## 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* [fields](#fields).

**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.


# 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.

{% hint style="info" %}
Be certain to enable the module when you need to use it.
{% endhint %}

* [**Content Editor**](/modules/integration-points/content-editor)
  * 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)](#syncing-integrations).
  * Insert Item - Visibility can be control using rules made available from within the *Interactive* field section.
  * Ribbon - Requires the library to be [synced (see below)](#syncing-integrations). 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**](/modules/integration-points/control-panel) - Requires the library to be [synced (see below)](#syncing-integrations).
* [**Data Sources**](https://github.com/sitecorepowershell/sitecore-powershell-extensions/tree/b6365f8ecf54966c2e1757f549f543976500aa52/date-sources.md) - 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](https://blog.najmanowicz.com/2013/04/17/powershell-scripted-datasources-in-sitecore-part-1/) and [here](https://github.com/SitecorePowerShell/Book/tree/9c7126d7a38df6ef372e8baef52f9a02baabd550/modules/integration-points/\[https:/blog.najmanowicz.com/2013/05/06/powershell-scripted-data-sources-in-sitecore-part-2/]/README.md). The *Source* field simply references the script like *script:/sitecore/system/Modules/PowerShell/Script Library/\[MODULE NAME]/Data Sources/\[SCRIPT NAME]*.
* [**Event Handlers**](/modules/integration-points/event-handlers) - Requires a patch file to enable the desired events. Read more about it [here](https://blog.najmanowicz.com/2013/05/27/react-to-sitecore-events-with-powershell-scripts/).
* [**Functions**](/modules/integration-points/functions) - Exposes scripts to the command *Import-Function*.
* **Internal**
  * [ISE Plugins](/modules/integration-points/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**](/modules/integration-points/page-editor) (Experience Editor)
  * Notification - Appears as a notification message beneath the ribbon in the *Experience Editor*.
* [**Pipelines**](/modules/integration-points/pipelines)
  * LoggedIn
  * LoggingIn
  * Logout
* [**Reports**](/modules/integration-points/reports) - Appears as a shortcut under *Sitecore -> Reporting Tools -> PowerShell Reports*.
* [**Toolbox**](/modules/integration-points/toolbox) - Appears as a shortcut under *Sitecore -> Toolbox*. Visibility can be control using rules made available from within the *Interactive* field section.
* [**Tasks**](/modules/integration-points/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**](/modules/integration-points/web-api) - Exposes scripts than can be consumed through [SPE Remoting](/remoting). The script can be executed by requesting a specific url.
* [**Workflows**](/modules/integration-points/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](https://blog.najmanowicz.com/2014/11/09/introducing-powershell-actions-for-sitecore-workflows/).

## Other Integrations

* **Remoting** - Interact with SPE through the provided web services as described [here](/remoting). 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](https://github.com/SitecorePowerShell/Book/blob/f781a87f549920aab0a7dede0ddf4c261e1aecb4/interfaces/scripting.md#settings-tab) section of the Scripting documents for instructions.


# 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
* Package Generator

  ![Package Generator](/files/-LA37TnmsHlVWnMxDvrA)
* Task Management

See how Adam added [context menu PowerShell scripts](https://blog.najmanowicz.com/2011/11/22/context-powershell-scripts-for-sitecore/).

## 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.
   * Return the gutter object
3. Configure any **Enable** rules to ensure the script runs only when necessary.
4. Rebuild the gutter integration from within the ISE.
   * Settings tab
   * Integration chunk
   * Sync Library with Content Editor Gutter command

**Note:** Examples included in the following modules

* Publishing Status Gutter

  ![Publishing Status](/files/-LA37Tt8H_Vtdixm4SoF)

## 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** rules as needed.

**Note:** Examples included in the following modules

* Task Management

  ![Insert Scheduled Task](/files/-LA37TwmwDbl8-pKpCs4)
* 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** library. The name of the script will appear in the ribbon chunk as a command.
4. 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.
5. Edit the script to perform the appropriate actions. The script can run in the background and show dialogs.
6. Change the icon of the item to match the script purpose.
7. Configure any **Enable** or **Show** rules as needed.

![Ribbon Script Library Structure](/files/d7LvFPfqipuw4RPIw1jX)

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

```powershell
# Use the notation "." to get the current directory/item.
$item = Get-Item -Path .
Show-Alert -Title $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]`

![Small and Combo Buttons](/files/-LA37U9S1xE-rZ1CxiPi)

![Buttons in the Ribbon](/files/-LA37UBd82LGPHG-pGLN)

See the birth of [extending the Sitecore ribbon with powershell scripts](https://blog.najmanowicz.com/2011/11/24/extending-sitecore-ribbon-with-powershell-scripts/) by Adam.

Check out an example of the [5 steps to extending the Sitecore ribbon](https://sitecoresandbox.com/2016/06/03/content-editor-ribbon-buttons-using-sitecore-powershell-extensions/) 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.

![Contextual Ribbon Command](https://user-images.githubusercontent.com/933163/51213796-8a639100-18e1-11e9-858a-f5611cc71f0b.png)

The ribbon structure would look like the following:

![Script Library Structure](https://user-images.githubusercontent.com/933163/51213924-f5ad6300-18e1-11e9-9aa8-42020f849a10.png)

## 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.
   * Include options to the warning by adding one or more secondary scripts to the script library.
4. Configure any **Enable** rules to ensure the script only runs when required.

**Note:** Examples included in the following modules

* License Expiration - disabled by default

![License Expiration Warning](/files/-LA37ULPEhXNasiL4ENS)

Alan provided a nice example [here ](https://alan-null.github.io/2016/04/content-editor-notifications)on setting up the warning with commands.


# 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


# 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
* 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*.

  ```powershell
  # The script must return an item. This is useful for populating a Droplink.
  Get-ChildItem -Path "master:" -ID "{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}"
  ```
* 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.

  ```powershell
  script:/sitecore/system/Modules/PowerShell/Script Library/X-Demo/Data Sources/Get-GlobalOption
  ```
* Enjoy the results.

![Droplink query](/files/-LA37Zj4lGlB6daCCjes)

## Rendering Data Source Roots

//TODO

## Rendering Data Source Items

//TODO

## References

* PowerShell Scripted Data Sources [part 1](https://blog.najmanowicz.com/2013/04/17/powershell-scripted-datasources-in-sitecore-part-1/) and [part 2](https://blog.najmanowicz.com/2013/05/06/powershell-scripted-data-sources-in-sitecore-part-2/)
* Sitecore Spark [article](https://github.com/SitecorePowerShell/Book/tree/5daee3160885dadd7031fee723dccf12a33abd7b/modules/integration-points/\[https:/www.sitecorespark.com/blog/2018/3/using-sitecore-powershell-scripts-for-datasources]/README.md) on using scripted datasources


# 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:

```xml
<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>
```

## 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.

![Item Added Event Handler](/files/-LA37_XwMI-w0qKeJSRe)


# 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` to discover the available functions.

![Module Creation](/files/-LA37ZCnvLttqgYNoELr)

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

![Shared Functions Library](/files/-LA37ZDnl5fSJKWOhGxY)

![Autocomplete in ISE](/files/-LA37ZE4AXt_JxtoJUDg)

Here's a short video on authoring custom functions.

![Creating Functions](https://img.youtube.com/vi/bn4LSDF8p4g/0.jpg)

[Click for a demo](https://www.youtube.com/watch?v=bn4LSDF8p4g)


# 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.

![ISE Plugins](https://user-images.githubusercontent.com/933163/61412200-dea9f680-a8ad-11e9-8ba8-2610d6f63a39.png)

## 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:

![Analyze Script](https://user-images.githubusercontent.com/933163/61412797-680df880-a8af-11e9-9656-e1cc609d26fe.png)

{% hint style="info" %}
The path structure needs to follow `[MODULE]/Internal/ISE Plugins/[PLUGIN_NAME]`. Here we have `X-Demo/Internal/ISE Plugins/Analyze Script`.
{% endhint %}

Use the following sample to fill in the script body.

```powershell
if([string]::IsNullOrWhiteSpace($scriptText)){
    Show-Alert "Script is empty - nothing to format."
    exit
}

Import-Module -Name PSScriptAnalyzer
Invoke-ScriptAnalyzer -ScriptDefinition $scriptText
```

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

![Example results](https://user-images.githubusercontent.com/933163/61413046-1fa30a80-a8b0-11e9-84ac-bcd536f18b42.png)


# 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](/files/-LA37TjH3uvnuCCZQhd7)

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

```powershell
$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** or **Show** rules as needed.

![An Experience Button for sending emails](/files/7K9hygKztSz8a1OTqRx9)

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

```powershell
$item = Get-Item -Path .
$response = Show-Input -Prompt "What's the message for $($item.Name)?"
if($response) {
    $mailSettings = @{
        To = @("Michael West < mw@test.com >")
        From = "Console < noreply@test.com >"
        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
```

![Message Input](/files/2V09ezVNhvvuwslyHQVE)

![Email Response](/files/5UnEGHJpK3yWDJfGeXBq)


# Pipelines

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

```powershell
 $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

```powershell
$pipelineArgs.Username
$pipelineArgs.Password
$pipelineArgs.Success
$pipelineArgs.StartUrl
```

## Logged In

**Note:** Examples included in the following modules

* Automatically show quick info section

```powershell
$pipelineArgs.Username
$pipelineArgs.StartUrl
```

## Logout

**Note:** Examples included in the following modules

* Unlock user items on logout


# 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 [Advanced System Report](https://github.com/SitecorePowerShell/Book/tree/9c7126d7a38df6ef372e8baef52f9a02baabd550/modules/integration-points/reports/\[https:/marketplace.sitecore.net/en/Modules/A/Advanced/_System/_Reporter.aspx]) (ASR) module.

## Running a Report

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

![Reports](/files/-LA37bI0QZb-iEDgOXqG)

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

![Unused Media Items](/files/-LA37bJ2Gt6a1kQASVBp)

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

![Unused Media Items Output](/files/-LA37bJNITNJ944y-DHH)

## 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                       |
|                                        | 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                   | -                                  |

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](/files/-LA37bd89H_hqF8_ZjcI)

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](/files/FblH7saHwQHVkfCVGep4)
3. Verify the reports are now visible to the Authoring users.

   ![Reports with Access](/files/tOXa34wOecENgNW8YOgw)

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


# 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.

![Choose report index](/files/-LA37XsoMYvH1QbNtgvR)

Next you will be prompted with a variety of buttons and knobs to narrow down the search results.

![Filter report results](/files/-LA37XtMzqG4qf6T65AY)

Finally the report is shown. Each row has an option to show more field results.

![Final results](/files/-LA37XthH3a84ufab-2x)

The *Show Full Info* link will then returns the additional fields not shown in the report.

![Show Full Info](/files/Zxa6lx09oRe4mOIv7PGz)

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:**

* [Creating Beautiful Sitecore Reports Easily with PowerShell Extensions](https://blog.najmanowicz.com/2014/10/25/creating-beautiful-sitecore-reports-easily-with-powershell-extensions/)

## 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:**

* [Images with an empty alt field](https://sitecorejunkie.com/2014/05/28/create-a-custom-report-in-sitecore-powershell-extensions)
* [Unused media items](https://michaellwest.blogspot.com/2014/04/reports-with-sitecore-powershell.html)

## Report Actions

Content extracted from [Turn Your Sitecore Powershell Reports into Applications with Action Scripts](https://blog.najmanowicz.com/2015/05/05/turn-your-sitecore-powershell-reports-into-applications-with-action-scripts/) 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.

![Actions seen for scheduled task items](/files/-LA37XzlQLqqwULY6zMi)

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`

```powershell
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)"}
}
```

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` – 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.

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`.
* 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.

#### 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 [persistent session](https://blog.najmanowicz.com/2014/10/26/sitecore-powershell-extensions-persistent-sessions/) 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`.

![Rules configuration for actions](/files/-LA37YJVdHspxsrR5eVD)

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:

```powershell
Get-ChildItem master:\ | Show-ListView -ViewName ListChildren
```

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.

![Action script](/files/-LA37YN6_flavnbU5S81)

Now I need to save my script in the proper Script Library in my enabled module:

![Save action script](/files/bj70JpPVZlSPhi03nGvF)

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.

![Open rules editor for report](/files/IV6jo2rhnOBjx2GgvU7y)

Now you can specify that you want the action to only appear when the report is named "ListChildren".

![Add rules for report](/files/-LA37YV8KzOv7-1249HL)

Confirm the save on all dialogs to persist your changes. Now our action appears when we run this script in ISE.

```powershell
Get-ChildItem master:\ | Show-ListView -ViewName ListChildren -Property Name, ProviderPath
```

![Now the List Children action is available](/files/WvpjnawGkHJ9pmk08m4A)

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:

```powershell
Get-ChildItem master:\ | Show-ListView -Property Name, ProviderPath
```

![Now the action is unavailable](/files/hfmf9GBNegXRlM9eQC50)

#### 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:

![Updating report content](/files/-LA37YgIdl5JIM3zbuw0)

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:

```powershell
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."
```

And you will see the following output:

![Show progress of long running actions](/files/-LA37YrAkvKpCCbzLzLr)

#### 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
* `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.

**Example:** The following example all of the UI elements in the report.

```powershell
Get-ChildItem master:\ | 
    Show-ListView `
        -Hide AllActions, AllExport, Filter, PagingWhenNotNeeded, StatusBar `
        -Property Name, DisplayName, ProviderPath, __Updated, "__Updated By"
```

![Report with all UI elements hidden](https://cloud.githubusercontent.com/assets/1209953/11334655/bfede644-91d6-11e5-8473-6f94be74b3e5.png)

## Examples from the community!

[Active Commerce](https://www.activecommerce.com/) for Sitecore product has published reports on Github that you can checkout [here](https://github.com/ActiveCommerce/activecommerce-powershell-extensions).


# 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](https://img.youtube.com/vi/Q6QKqRwrkuU/0.jpg)

[Click for a demo](https://www.youtube.com/watch?v=Q6QKqRwrkuU)

## Scheduled Task Command

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

![PowerShell Script Command](/files/-LA37Oz5sJCNXsVg6VmZ)

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.

![PowerShell Script Task](/files/-LA37P-XFQUFmYKObiCS)

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                                                           |
| ----------------------- | ---------------------------------------------------------------- |
| System Maintenance      | Archive Sitecore logs, Clean up deleted items older than 30 days |
| User Session Management | Remove idle user sessions                                        |

## 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:

![Insert Option for Task](/files/-LA37P1Hsk3H2lJJETDW)

Run or edit the scheduled task:

![Run or Edit Task Schedule](/files/-LA37P1gcxH7GX6t_e3V)

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.

![Dialog to Select Task Scripts](/files/-LA37P2sgO-MHwqg0MkE)

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

![Dialog to Edit Task Schedule](/files/-LA37P3kHtqBCqbrqXZQ)

**Note:** Examples included are in the following modules

* License Expiration
* Media Library Maintenance
* System Maintenance

See how Adam added [powershell driven Sitecore scheduled tasks](https://github.com/SitecorePowerShell/Book/tree/a1cbd06eba0aad8913e553f4aaa08de0412c635a/modules/integration-points/tasks/\[https:/blog.najmanowicz.com/2011/11/29/powershell-driven-sitecore-scheduled-tasks/]/README.md).


# 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.

![Scheduled Task Menu](/files/-LA37eCJV8K51qQjGS1Q)

![Edit Scheduled Task](/files/-LA37eCc9U2Ipfoyqfbx)

## References

* [Custom Scheduled Task by Mike Reynolds](https://sitecorejunkie.com/2014/05/31/execute-powershell-scripts-in-scheduled-tasks-using-sitecore-powershell-extensions/)


# 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:

![Toolbox](https://user-images.githubusercontent.com/933163/50113236-fda4b500-0206-11e9-8997-c629927a5148.png)

**Note:** Examples included in the following modules

* Authorable Reports
* Logged in Session Manager
* Package Generator
* Task Management
* Platform

## Available Tools

### Index Viewer

This tool provides similar functionality to the [Index Viewer](https://marketplace.sitecore.net/en/Modules/I/Index_Viewer.aspx) module. Search and rebuild the index on-demand.

![Index Viewer](https://user-images.githubusercontent.com/933163/50112430-d351f800-0204-11e9-9d5c-07c99c163205.png)

### Logged in Session Manager

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

![Logged in Session Manager](https://user-images.githubusercontent.com/933163/50112838-e1ecdf00-0205-11e9-8959-9d4332859162.png)

### Rules based report

Generate a report using the Sitecore Rules Engine.

![Rules based report](https://user-images.githubusercontent.com/933163/50112876-fd57ea00-0205-11e9-89ac-f407ada390a8.png)

### PowerShell Background Session Manager

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

![PowerShell Background Session Manager](https://user-images.githubusercontent.com/933163/50112986-51fb6500-0206-11e9-8c4e-2905f1378dc9.png)

### Create Anti-Package

This tool provides similar functionality to the [Sitecore Rocks](https://github.com/SitecorePowerShell/Book/tree/9c7126d7a38df6ef372e8baef52f9a02baabd550/modules/integration-points/\[https:/marketplace.sitecore.net/en/Modules/S/Sitecore/_Rocks.aspx]) module.

![Create Anti-Package](https://user-images.githubusercontent.com/933163/50112920-1fea0300-0206-11e9-9a37-138c9cb9f273.png)

### Re-create Site from Sitemap

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

![Re-create Site from Sitemap](https://user-images.githubusercontent.com/933163/50113021-68a1bc00-0206-11e9-8f82-e7bc1d8eaefd.png)

### Task Manager

View and manage the configured scheduled tasks.

![Task Manager](https://user-images.githubusercontent.com/933163/50113111-a30b5900-0206-11e9-84b1-5ce866bb1d85.png)

## 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](/files/-LA37_A5p7JMnQmXDmd1)
* Select the *Toolbox* item and click *Proceed*.

  ![Module Toolbox Library](/files/-LA37_BdW8tzCH7IRNSP)

  1. Create a *PowerShell Script* under the *Toolbox* item.
* Right click the *Toolbox* library and choose *PowerShell Script*.

  ![Libary Script](/files/-LA37_EjFalDXHO-zV6Y)

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

     ![ISE Edit](/files/-LA37_GGftm-5n-V_DDT)
  2. Run the *Rebuild All* command in the ISE by navigating to the *Settings* tab and selecting the icon to rebuild. Be certain to enable the module before running the rebuild command.

     ![ISE Settings Tab](/files/-LA37_HoKSadE_JsGL2_)
  3. Verify the new toolbox item appears in the Toolbox.

     ![Toolbox](https://user-images.githubusercontent.com/933163/50113236-fda4b500-0206-11e9-8997-c629927a5148.png)


# 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`. 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.

Headers:

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

```powershell
$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)"
```

**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 [here](/security). 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 [here](https://vimeo.com/134196432).


# 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`.
3. Edit the *Script body* with the appropriate script. I like to save my workflow scripts in a library called *Workflows*.
4. 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.
5. Edit the script in your *Workflows* library to perform the appropriate actions. The script can run in the background and show dialogs.
6. Change the icon of the workflow action item to match the script purpose.
7. Celebrate your success with the team!

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

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

See how Adam integrated [workflow actions](https://blog.najmanowicz.com/2014/11/09/introducing-powershell-actions-for-sitecore-workflows/) if you are really curious to know more.

## References

* [Fixing problematic content or Workflow state](https://www.cognifide.com/blogs/sitecore/feel-the-power-in-powershell/)


# 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.

```powershell
$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.

```powershell
$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"
```

**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.

```powershell
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
```

**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.

```powershell
$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}"
```

```powershell
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
```


# 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.

### 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](/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 [Security](/security) page for more details.

![SPE Remoting Module](https://img.youtube.com/vi/fGvT8eDdWrg/0.jpg)

[Click for a demo](https://www.youtube.com/watch?v=fGvT8eDdWrg)

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](/security). 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:

```powershell
New-WebServiceProxy : The request failed with HTTP status 401: Unauthorized.
```

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

```powershell
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
```

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

```powershell
# 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
```

### 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](/security) page for more details about the services available and how to configure.

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

```powershell
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
```

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

```powershell
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
```

### Script Sessions and Web API Tutorial

![SPE Web API](https://img.youtube.com/vi/SmZBGKOryzQ/0.jpg)

[Click for a demo](https://www.youtube.com/watch?v=SmZBGKOryzQ)

## 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.

{% hint style="info" %}
These commands are not only used for remoting, we just thought it made sense to talk about them here.
{% endhint %}

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

```powershell
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
```

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

```powershell
$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
    }
}
```

**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](https://github.com/SitecorePowerShell/Book/tree/a1cbd06eba0aad8913e553f4aaa08de0412c635a/\[https:/blogs.technet.microsoft.com/heyscriptingguy/2014/03/30/understanding-streams-redirection-and-write-host-in-powershell/]/README.md).

```powershell
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
```

**Example:** The following improves upon the previous example.

```powershell
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
```

## 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):

```
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.NewItemCommand
```

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

**Example:**

```
Invoke-RemoteScript -ScriptBlock {
    Set-Location -Path "master:"
    ...
    [The rest of your script]
    ...
}
```

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](https://michaellwest.blogspot.com/2015/07/sitecore-powershell-extensions-remoting.html)
* Adam's initial post on [Remoting](https://blog.najmanowicz.com/2014/10/10/sitecore-powershell-extensions-remoting/)


# 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.

{% hint style="danger" %}
**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.
{% endhint %}

## Quick Start

New to SPE security? Start here:

1. [**Getting Started**](/security/getting-started) - Essential security setup for new installations
2. [**Security Policies**](/security/security-policies) - Understand the SPE security model
3. [**Security Checklist**](/security/security-checklist) - Validate your deployment before going live

## Security Documentation

### Core Security Topics

#### [Security Policies](/security/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)](/security/session-elevation)

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](/security/web-services)

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](/security/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](/security/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](/security/iis-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](/security/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](/security/minimal-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](/security/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](/security/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](/security/getting-started#development-environment)

### 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](/security/getting-started#qastaging-environment)

### 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](/security/security-checklist#production-environment)

### 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/minimal-deployment)

## Security Layers (Defense in Depth)

SPE security uses multiple layers for comprehensive protection:

```
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
```

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](/security/security-policies) to understand the model
2. Configure [Session Elevation](/security/session-elevation) with 5-minute Password timeout
3. Disable unnecessary [Web Services](/security/web-services)
4. Configure [IIS Security](/security/iis-security) to deny anonymous access
5. Enable [Logging and Monitoring](/security/logging-and-monitoring)
6. Complete the [Security Checklist](/security/security-checklist)

### Scenario 2: Setting Up CI/CD Automation

**Goal:** Enable remote automation from build servers

**Steps:**

1. Use [Minimal Deployment](/security/minimal-deployment) package
2. Enable Remoting in [Web Services](/security/web-services) with specific user
3. Configure [IIS Security](/security/iis-security) with IP restrictions to build servers
4. Configure [File Upload Restrictions](/security/file-upload-restrictions) for packages only
5. Set up [Logging and Monitoring](/security/logging-and-monitoring) for automation activity
6. Test with [Security Checklist - CI/CD](/security/security-checklist#cicd-environment)

### Scenario 3: Delegating Report Access

**Goal:** Allow content authors to run administrative reports

**Steps:**

1. Understand [Delegated Access](/security/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 [Logging and Monitoring](/security/logging-and-monitoring)

### 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](/security/session-elevation) with Confirm action (not Password)
3. Test Console and ISE with federated authentication
4. Configure [Web Services](/security/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      | [Web Services](/security/web-services)                                                 |
| `App_Config\Include\Spe\Spe.IdentityServer.config` | Identity Server integration | [Getting Started](/security/getting-started#identity-server-configuration-sitecore-91) |
| `App_Config\Include\Spe\Custom\*.config`           | Your security patches       | All topics                                                                             |
| `sitecore modules\PowerShell\Services\web.config`  | IIS-level security          | [IIS Security](/security/iis-security)                                                 |

### Security Policies Location

| Policy                  | Location                                                            | Documentation                                    |
| ----------------------- | ------------------------------------------------------------------- | ------------------------------------------------ |
| Application Visibility  | `core:\content\Applications\PowerShell`                             | [Security Policies](/security/security-policies) |
| Menu Item Security      | `core:\content\Applications\Content Editor\Context Menues\Default\` | [Security Policies](/security/security-policies) |
| Script Library Security | Item-level security on scripts                                      | [Users and Roles](/security/users-and-roles)     |
| Delegated Access        | SPE configuration items                                             | [Delegated Access](/security/delegated-access)   |

### 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) | Use custom role instead            |

## Getting Help

### Documentation Navigation

* **New to SPE Security?** Start with [Getting Started](/security/getting-started)
* **Deploying to production?** Use the [Security Checklist](/security/security-checklist)
* **Setting up automation?** See [Minimal Deployment](/security/minimal-deployment)
* **Need to debug?** Check [Logging and Monitoring](/security/logging-and-monitoring)
* **Configuring a specific feature?** See topic-specific guides below

### Support Resources

* **GitHub Issues:** [SitecorePowerShell/Console](https://github.com/SitecorePowerShell/Console/issues)
* **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](/security/security-checklist#emergency-procedures)
2. Review logs using [Logging and Monitoring](/security/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](https://github.com/SitecorePowerShell/Book/blob/master/installation.md) - Initial SPE installation
* [Interfaces](/interfaces) - Console, ISE, and Interactive Dialogs
* [Remoting](/remoting) - Using SPE Remoting for automation
* [Modules](/modules) - Integration points and features
* [Appendix - Security Cmdlets](/appendix/security) - PowerShell security commands

### External References

* [Sitecore Security Best Practices](https://doc.sitecore.com/xp/en/developers/latest/platform-administration-and-architecture/security.html)
* [OWASP Top 10](https://owasp.org/www-project-top-ten/)
* [Principle of Least Privilege](https://en.wikipedia.org/wiki/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"

```xml
<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 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


# Getting Started

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

## Critical Security Warnings

{% hint style="danger" %}
**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.
{% endhint %}

## Quick Security Checklist

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

### ✓ Environment Assessment

* [ ] Confirm this is a Content Management (CM) server
* [ ] Verify the server is NOT internet-facing
* [ ] Ensure the server is behind a firewall
* [ ] Confirm this is NOT a Content Delivery (CD) instance

### ✓ 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.

* [ ] Review enabled services in `App_Config\Include\Spe\Spe.config`
* [ ] Only enable services you specifically need
* [ ] Configure HTTPS for any enabled external services
* [ ] Review the [Web Services](/security/web-services) documentation

### ✓ User Access Control

* [ ] Review default role permissions (under `core:\content\Applications\PowerShell`)
* [ ] Ensure only trusted administrators have access
* [ ] Enable Session Elevation (UAC) for production environments
* [ ] Configure appropriate token expiration times
* [ ] Review the [Session Elevation](/security/session-elevation) documentation

### ✓ Application Pool Security

* [ ] Review the application pool service account permissions
* [ ] Ensure the account follows the principle of least privilege
* [ ] Verify file system access is restricted to necessary directories only
* [ ] Consider using a named service account instead of ApplicationPoolIdentity

### ✓ Content Editor Security

* [ ] Verify PowerShell Console visibility is restricted to `sitecore\Developer` role
* [ ] Verify PowerShell ISE visibility is restricted to `sitecore\Developer` role
* [ ] Review context menu security settings
* [ ] Test that non-privileged users cannot access SPE features

## 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:

```xml
<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>
```

### Step 3: Configure IIS Authentication

Protect the SPE services directory at the IIS level.

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

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>
```

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
5. Verify Session Elevation prompts appear when expected
6. Test that scripts execute successfully after elevation

## Environment-Specific Recommendations

### Development Environment

For local development machines, you may use relaxed settings:

```xml
<token name="Console">
  <patch:attribute name="expiration">01:00:00</patch:attribute>
  <patch:attribute name="elevationAction">Allow</patch:attribute>
</token>
```

{% hint style="warning" %}
**Never use `elevationAction="Allow"` in non-development environments!**
{% endhint %}

### QA/Staging Environment

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

```xml
<token name="Console">
  <patch:attribute name="expiration">00:15:00</patch:attribute>
  <patch:attribute name="elevationAction">Password</patch:attribute>
</token>
```

### Production Environment

Use the strictest settings:

```xml
<token name="Console">
  <patch:attribute name="expiration">00:05:00</patch:attribute>
  <patch:attribute name="elevationAction">Password</patch:attribute>
</token>
```

For Azure AD/SSO environments, use:

```xml
<token name="Console">
  <patch:attribute name="elevationAction">Confirm</patch:attribute>
</token>
```

## 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 [Security Policies](/security/security-policies) to understand the security model
2. Configure [Session Elevation](/security/session-elevation) for your environment
3. If you need external access, carefully review [Web Services](/security/web-services) security
4. Learn about [User and Role Management](/security/users-and-roles)
5. Complete the [Security Checklist](/security/security-checklist) before deployment

## 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 [Security Hardening](/security) documentation
* Check the [Security Checklist](/security/security-checklist)
* Visit the [GitHub repository](https://github.com/SitecorePowerShell/Console)
* Join #module-spe on Sitecore Community Slack


# 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

* [ ] **Confirmed this is a Content Management (CM) server**
* [ ] **Confirmed this is NOT a Content Delivery (CD) instance**
* [ ] **Confirmed server is NOT internet-facing**
* [ ] **Confirmed server is behind a firewall**
* [ ] **Confirmed SPE is NOT installed on production CD servers**

{% hint style="danger" %}
**STOP:** If any of the above are not true, DO NOT proceed with SPE installation.
{% endhint %}

## Configuration Checklist

### 1. Web Services Security

Review `App_Config\Include\Spe\Spe.config` (via patch file):

**Services Status:**

* [ ] **remoting** - Disabled (unless specifically needed for CI/CD)
* [ ] **restfulv1** - Disabled (deprecated)
* [ ] **restfulv2** - Disabled (unless Web API is needed)
* [ ] **fileDownload** - Disabled (unless SPE Remoting is used)
* [ ] **fileUpload** - Disabled (unless SPE Remoting is used)
* [ ] **mediaDownload** - Disabled (unless SPE Remoting is used)
* [ ] **mediaUpload** - Disabled (unless SPE Remoting is used)
* [ ] **handleDownload** - Enabled (required for report exports)
* [ ] **client** - Enabled (required for Console/ISE)
* [ ] **execution** - Enabled (required for SPE features)

**If Remoting is Enabled:**

* [ ] `requireSecureConnection="true"` is configured
* [ ] Authorization is configured with specific roles/users
* [ ] Default roles have been reviewed and restricted
* [ ] Only necessary users/roles have access

**Documentation:** [Web Services Security](/security/web-services)

### 2. Session Elevation (UAC)

**Token Configuration:**

* [ ] Console token expiration is appropriate for environment
  * Dev: 30-60 minutes ✓
  * QA: 10-15 minutes ✓
  * Prod: 3-5 minutes ✓
* [ ] Console `elevationAction` is configured
  * Dev: Allow (acceptable) ✓
  * QA/Prod: Password or Confirm ✓
* [ ] ISE token expiration is appropriate for environment
* [ ] ISE `elevationAction` is configured appropriately
* [ ] ItemSave token expiration is appropriate for environment
* [ ] ItemSave `elevationAction` is configured appropriately
* [ ] For Azure AD/SSO environments, using `Confirm` instead of `Password`

**Quick Test:**

* [ ] Tested that elevation prompts appear when accessing Console
* [ ] Tested that elevation prompts appear when accessing ISE
* [ ] Tested that elevation can be dropped manually
* [ ] Tested that sessions expire after configured time

**Documentation:** [Session Elevation](/security/session-elevation)

### 3. User and Role Access

**Sitecore Security:**

* [ ] PowerShell Console is restricted to `sitecore\Developer` role (or more restrictive)
* [ ] PowerShell ISE is restricted to `sitecore\Developer` role (or more restrictive)
* [ ] Content Editor context menus are appropriately restricted
* [ ] Script libraries have appropriate item-level security
* [ ] Reviewed who is in the `sitecore\Developer` role
* [ ] Removed unnecessary users from Developer role
* [ ] Custom roles are configured if needed (instead of using broad defaults)

**Application Pool Account:**

* [ ] Service account follows principle of least privilege
* [ ] Service account is NOT LocalSystem or Administrator
* [ ] File system permissions have been audited
* [ ] Service account cannot write to system directories
* [ ] Service account cannot write to web root (except App\_Data)

**Documentation:** [Security Policies](/security/security-policies), [Users and Roles](/security/users-and-roles)

### 4. File Upload Restrictions

**Configuration:**

* [ ] Allowed file types are restricted to necessary types only
* [ ] Dangerous file types (.exe, .dll, .ps1, .bat, .cmd) are NOT allowed
* [ ] Upload locations are restricted to safe directories
* [ ] `$SitecoreTempFolder` is the primary upload location
* [ ] Upload paths do NOT include web root or bin folder
* [ ] MIME type patterns are configured (not just extensions)

**Quick Test:**

* [ ] Tested that allowed file types can be uploaded
* [ ] Tested that disallowed file types are blocked
* [ ] Tested that uploads to unauthorized paths are blocked

**Documentation:** [File Upload Restrictions](/security/file-upload-restrictions)

### 5. IIS-Level Security

**Web.config Configuration** (`sitecore modules\PowerShell\Services\web.config`):

* [ ] Anonymous access is denied (`<deny users="?" />`)
* [ ] If using Windows Authentication:
  * [ ] Anonymous authentication disabled in IIS
  * [ ] Windows Authentication enabled in IIS
  * [ ] Allowed users/roles are configured
  * [ ] Remoting clients configured with Credential parameter

**Additional IIS Security:**

* [ ] IP restrictions configured (if applicable for CI/CD)
* [ ] HTTPS requirement configured (production environments)
* [ ] Request filtering configured to block dangerous patterns
* [ ] Request size limits configured appropriately
* [ ] Dangerous HTTP verbs (TRACE, OPTIONS) are blocked

**Quick Test:**

* [ ] Tested that anonymous access is denied (401 response)
* [ ] Tested that authenticated access works
* [ ] Tested that HTTP is blocked/redirected (if HTTPS required)
* [ ] Tested that unauthorized IPs are blocked (if IP restrictions configured)

**Documentation:** [IIS Security](/security/iis-security)

### 6. Delegated Access

**If Using Delegated Access:**

* [ ] Delegated access items are properly configured
* [ ] Requester roles are specific (not broad like "Everyone")
* [ ] Impersonated users follow least privilege (not always Admin)
* [ ] Delegated scripts are reviewed for security
* [ ] Delegated scripts validate input
* [ ] Delegated scripts include confirmations for destructive operations
* [ ] Delegated scripts log actions
* [ ] Item-level security protects delegated access configurations

**If NOT Using Delegated Access:**

* [ ] No delegated access items are enabled

**Documentation:** [Delegated Access](/security/delegated-access)

### 7. Identity Server (Sitecore 9.1+)

**For Sitecore 9.1+ with Identity Server:**

* [ ] `Spe.IdentityServer.config` is enabled
* [ ] Configuration prevents infinite loop in SPE Console
* [ ] Tested Console works with Identity Server authentication

**Documentation:** [Getting Started - Identity Server](/security/getting-started#identity-server-configuration-sitecore-91)

### 8. Minimal Web Service Deployment

**For CI/CD Environments:**

* [ ] Using minimal deployment package if full SPE not needed
* [ ] Only required files are deployed:
  * [ ] `Spe.config`
  * [ ] `Spe.Minimal.config`
  * [ ] `Spe.dll` and `Spe.Abstractions.dll`
  * [ ] Services web.config
  * [ ] Service files (asmx/ashx)
* [ ] Control sources are disabled (patch applied)
* [ ] Remoting is enabled with proper security

**Documentation:** [Minimal Deployment](/security/minimal-deployment)

## Testing Checklist

### Functional Testing

**As Non-Administrator User:**

* [ ] Cannot see PowerShell Console in Sitecore menu
* [ ] Cannot see PowerShell ISE in Sitecore menu
* [ ] Cannot see PowerShell context menus
* [ ] Cannot access `/sitecore/shell/Applications/PowerShell` directly

**As Administrator User (without elevated session):**

* [ ] See Console/ISE in menu
* [ ] Prompted for elevation when accessing Console
* [ ] Prompted for elevation when accessing ISE
* [ ] Prompted for elevation when editing script items
* [ ] Content Editor shows warning on PowerShell items

**As Administrator User (with elevated session):**

* [ ] Can access Console successfully
* [ ] Can access ISE successfully
* [ ] Can edit PowerShell script items
* [ ] Session drops after configured timeout
* [ ] Can manually drop elevated session

**Web Services (if enabled):**

* [ ] Anonymous access is denied (401)
* [ ] Authenticated access works
* [ ] Unauthorized users are denied (403)
* [ ] File upload restrictions work as expected
* [ ] IP restrictions work as expected (if configured)

### Security Testing

**Attack Surface:**

* [ ] Web services return 401/403 for unauthorized access
* [ ] Cannot upload dangerous file types
* [ ] Cannot upload to dangerous locations
* [ ] Cannot bypass authentication
* [ ] Cannot bypass Session Elevation
* [ ] HTTPS is enforced (if configured)

**Privilege Escalation:**

* [ ] Non-privileged users cannot access SPE features
* [ ] Non-privileged users cannot modify scripts
* [ ] Delegated access works as intended (if configured)
* [ ] Delegated access is properly restricted

## Logging and Monitoring Checklist

**Logging Configuration:**

* [ ] SPE logging is enabled
* [ ] Log level is appropriate (INFO for production)
* [ ] Logs are being written to expected location
* [ ] Log rotation is configured

**Monitoring:**

* [ ] Reviewing SPE logs regularly for suspicious activity
* [ ] Monitoring for failed authentication attempts
* [ ] Monitoring for delegated access usage
* [ ] Monitoring for Session Elevation denials
* [ ] IIS logs are reviewed for web service access
* [ ] Alert system configured for security events (optional)

**Documentation:** [Logging and Monitoring](/security/logging-and-monitoring)

## Documentation Checklist

**Required Documentation:**

* [ ] Security configuration is documented
* [ ] Roles and their access levels are documented
* [ ] Enabled web services and reasons are documented
* [ ] Delegated access configurations are documented (if used)
* [ ] IP restrictions and reasons are documented (if configured)
* [ ] Session elevation timeouts and rationale are documented
* [ ] Emergency procedures are documented
* [ ] Contact information for security issues is documented

## Compliance Checklist

**Organizational Requirements:**

* [ ] Security configuration reviewed by security team
* [ ] Configuration meets organizational security standards
* [ ] Any exceptions are documented and approved
* [ ] Change management process followed
* [ ] Security sign-off obtained (if required)

**Regulatory Compliance (if applicable):**

* [ ] GDPR requirements addressed (if applicable)
* [ ] PCI-DSS requirements addressed (if applicable)
* [ ] HIPAA requirements addressed (if applicable)
* [ ] SOC 2 requirements addressed (if applicable)

## Sign-Off

**Deployment Approval:**

* [ ] All checklist items completed
* [ ] Security testing passed
* [ ] Documentation complete
* [ ] Stakeholders notified

**Approved By:**

* [ ] Developer: \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ Date: \_\_\_\_\_\_\_\_\_
* [ ] Security Team: \_\_\_\_\_\_\_\_\_\_\_\_\_ Date: \_\_\_\_\_\_\_\_\_
* [ ] IT Operations: \_\_\_\_\_\_\_\_\_\_\_\_\_ Date: \_\_\_\_\_\_\_\_\_

## Post-Deployment Checklist

**Within 24 Hours:**

* [ ] Monitor logs for errors
* [ ] Monitor logs for unauthorized access attempts
* [ ] Verify Session Elevation is working in production
* [ ] Verify web services respond appropriately
* [ ] Test key SPE features (Console, ISE, Reports)

**Within 1 Week:**

* [ ] Review all logs for security events
* [ ] Verify no unexpected errors
* [ ] Confirm monitoring/alerting is working
* [ ] Document any issues and resolutions

**Monthly:**

* [ ] Review role membership
* [ ] Review enabled web services
* [ ] Review delegated access configurations
* [ ] Audit logs for suspicious activity
* [ ] Review and update documentation

## Environment-Specific Checklists

### Development Environment

**Minimum Requirements:**

* [ ] Session Elevation configured (can be relaxed)
* [ ] Web services disabled unless needed for testing
* [ ] Basic authentication configured

**Optional:**

* IP restrictions
* Strict session timeouts
* HTTPS enforcement

### QA/Staging Environment

**Must Match Production:**

* [ ] Identical Session Elevation configuration
* [ ] Identical web service configuration
* [ ] Identical authentication requirements
* [ ] Similar HTTPS requirements

### Production Environment

**Strictest Security:**

* [ ] Session Elevation with Password or Confirm (never Allow)
* [ ] Short timeout (3-5 minutes)
* [ ] All unnecessary web services disabled
* [ ] Anonymous access denied
* [ ] HTTPS required
* [ ] IP restrictions (if applicable)
* [ ] Request filtering enabled
* [ ] Comprehensive logging
* [ ] Regular monitoring

### CI/CD Environment

**Automation-Focused:**

* [ ] Minimal deployment package
* [ ] Remoting enabled with strict authorization
* [ ] IP restrictions to build servers
* [ ] HTTPS required
* [ ] Service account configured
* [ ] Comprehensive logging

## 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`    | Deny anonymous              |
| **Sitecore Security** | Core DB items            | Role permissions            |
| **Remoting Auth**     | `Spe.config` (via patch) | Authorization roles/users   |

## Related Documentation

* [Getting Started](/security/getting-started) - Initial security setup
* [Security Policies](/security/security-policies) - Understanding the security model
* [Session Elevation](/security/session-elevation) - UAC configuration
* [Web Services](/security/web-services) - Web service security
* [IIS Security](/security/iis-security) - IIS-level protection
* [File Upload Restrictions](/security/file-upload-restrictions) - Upload security
* [Delegated Access](/security/delegated-access) - Controlled privilege escalation
* [Logging and Monitoring](/security/logging-and-monitoring) - Audit and monitoring
* [Users and Roles](/security/users-and-roles) - 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
   * Identify scope of incident
3. **Remediation:**
   * Change service account passwords
   * Review and tighten security configuration
   * Apply security patches if needed
   * Re-deploy with validated security
4. **Recovery:**
   * Restore from backup if necessary
   * Re-enable services with enhanced security
   * Monitor closely for 48 hours
   * Document lessons learned

### Quick Lockdown

To immediately lock down SPE:

```xml
<!-- 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>
```

Add to `Services\web.config`:

```xml
<authorization>
  <deny users="*" />
</authorization>
```

## 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}}


# 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)
2. **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

{% hint style="warning" %}
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.
{% endhint %}

**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       | ❌ **Never use** - grants unlimited 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:

```powershell
# 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
```

### 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](/security/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:

```powershell
# This respects Sitecore security
Get-Item -Path "master:\content\home"

# This also respects Sitecore security
Get-User -Identity "sitecore\testuser"
```

However, scripts can bypass Sitecore security just like any other Sitecore API code:

```powershell
# This bypasses Sitecore security
New-UsingBlock (New-Object Sitecore.SecurityModel.SecurityDisabler) {
    # Code here runs with full Sitecore permissions
    Get-Item -Path "master:\content\home"
}
```

{% hint style="danger" %}
**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.
{% endhint %}

### 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)     | `core:\content\Applications\PowerShell\PowerShellRunner`         |
| **PowerShell Reports**  | `sitecore\Sitecore Client Authoring` (read) | See [Reports documentation](/modules/integration-points/reports) |

**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:

```powershell
# 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()
```

## 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    | ❌ Denied by Windows    |
| Delete file outside Sitecore | Has file permission | Is administrator    | ✅ Success (dangerous!) |

## 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)](/security/session-elevation) - Require reauthentication
* [Web Services Security](/security/web-services) - Disable unnecessary endpoints
* [IIS-Level Security](/security/iis-security) - Block anonymous access
* [Monitoring and Logging](/security/logging-and-monitoring) - Detect unauthorized access

## Next Steps

* Configure [Session Elevation](/security/session-elevation) to add an additional authentication layer
* Review [Web Services Security](/security/web-services) if you need external access
* Learn about [User and Role Management](/security/users-and-roles)
* Complete the [Security Checklist](/security/security-checklist)

## References

* [Sitecore Security API Documentation](https://doc.sitecore.com/xp/en/developers/latest/platform-administration-and-architecture/security-api.html)
* [IIS Application Pool Identities](https://docs.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities)


# 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.

```powershell
Get-Command -Noun Role*,User,ItemAcl* | Select-Object -Property Name | Sort-Object -Property Name
```

## 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.

### 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.

```powershell
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*"
```

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.

```powershell
Get-User -Id "michael" -Authenticated | 
    Set-User -ProfileItemId "{AE4C4969-5B7E-4B4E-9042-B2D8701CE214}"
```

**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.

```powershell
$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
```

## Roles

**Example:** The following queries roles using the specified identity.

```powershell
# Identity can be "[domain]\[name]", "Creator-Owner", and "\Everyone"
Get-Role -Identity "default\Everyone"
```

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

```powershell
Get-Role -Filter * | Show-ListView -Property Name, Domain
```

**Example:** The following adds a user to a role.

```powershell
$user = Get-User -Identity "sitecore\author"
$role = Get-Role -Identity "sitecore\Sitecore Client Authoring"
Add-RoleMember -Identity $role -Members $user
```

**Example:** The following removes a user from a role.

```powershell
$user = Get-User -Identity "sitecore\author"
$role = Get-Role -Identity "sitecore\Sitecore Client Authoring"
Remove-RoleMember -Identity $role -Members $user
```

## See Also

* [Working with Items - Item Security](/working-with-items/item-security) - Managing item-level security and ACLs
* [Appendix - Security Commands](/appendix/security) - Full security cmdlet reference

## References

* [Using Get-User command to query over 200k users](https://stackoverflow.com/questions/34982451/sitecore-powershell-get-user-command/34994302#34994302)
* [Explore Sitecore Users Properties](https://lets-share.senktas.net/2017/02/explore-sitecore-users.html)


# 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`)
2. **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.

```xml
<token name="Console">
  <patch:attribute name="elevationAction">Allow</patch:attribute>
</token>
```

{% hint style="danger" %}
**Never use Allow in production!** This completely disables session elevation and should only be used on local development machines.
{% endhint %}

### Block

**Use Case:** Completely disable a feature

Always blocks access. The gate cannot be used at all.

```xml
<token name="Console">
  <patch:attribute name="elevationAction">Block</patch:attribute>
</token>
```

**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.

```xml
<token name="Console">
  <patch:attribute name="elevationAction">Password</patch:attribute>
  <patch:attribute name="expiration">00:05:00</patch:attribute>
</token>
```

**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](/files/-LA37dy4MWJhe4x9dBtg)

**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.

```xml
<token name="Console">
  <patch:attribute name="elevationAction">Confirm</patch:attribute>
  <patch:attribute name="expiration">00:05:00</patch:attribute>
</token>
```

**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](/files/nZTzyJ8hGTml6z53TZTM)

**After Elevation:**

The warning changes to show the session is elevated with a "Drop" option:

![Drop elevated session state](/files/-LA37e6NYAxxEhaW-3Hd)

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](/files/VzJ2UByyaJnT4Lv5lcr8)

Click **"Elevate session"** to authenticate and reveal the fields.

**After Elevation:**

Fields become editable with an option to drop the session:

![Drop session](/files/-LA37e18KNZnLyEJwcH8)

## Configuration Examples

### Development Environment

Relaxed settings for local development:

```xml
<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>
```

### Production Environment (Standard Auth)

Strict settings with password requirement:

```xml
<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>
```

### Production Environment (SSO/Azure AD)

Settings for federated authentication:

```xml
<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>
```

### Disable Console, Enable ISE Only

Lock down the Console while allowing ISE access:

```xml
<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>
```

## 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:

```xml
<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>
```

### Independent Tokens

Each gate can have its own token for fine-grained control:

```xml
<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>
```

## 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           | Require reauthentication        |
| **Production (SSO/Azure AD)**  | Confirm            | Provide confirmation step       |

### 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](/security/web-services) for external access
* Learn about [Delegated Access](/security/delegated-access) for controlled privilege escalation
* Review [User and Role Management](/security/users-and-roles)
* Complete the [Security Checklist](/security/security-checklist)


# 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:**

* 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

{% hint style="info" %}
This feature was introduced in SPE with [#1283](https://github.com/SitecorePowerShell/Console/issues/1283)
{% endhint %}

## 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

```
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
```

## 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](https://user-images.githubusercontent.com/933163/191065624-65c400c8-8628-4ede-b669-52d1e3e1c513.png)

![Delegated access template](https://user-images.githubusercontent.com/933163/191063313-7c51250e-9740-4054-890e-7fb282912ddc.png)

### 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

{% hint style="warning" %}
**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.
{% endhint %}

### 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](https://user-images.githubusercontent.com/933163/191064401-d135e275-aeea-4315-a505-acca61d6c963.png)

**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)

{% hint style="danger" %}
**Important:** Test thoroughly before enabling in production. Delegated access grants powerful permissions to lower-privileged users.
{% endhint %}

## Audit Logging

All delegated access operations are logged to the SPE log file.

**Log Entry Format:**

```
2304 14:02:32 INFO [Gutter] Executing script {CFE81AF6-2468-4E62-8BF2-588B7CC60F80} for Context User sitecore\contentauthor as sitecore\Admin.
```

**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:**

```powershell
# 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 = $_
            }
        }
    }
}
```

## 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              |
| **Testing**           | Test in QA first             | Catch security issues before production |
| **Review**            | Quarterly access review      | Remove unused delegations               |

### Script Security

When writing scripts for delegated access:

1. **Validate All Input:**

   ```powershell
   if ([string]::IsNullOrWhiteSpace($itemPath)) {
       Show-Alert "Invalid item path"
       return
   }
   ```
2. **Limit Scope:**

   ```powershell
   # 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
   }
   ```
3. **Confirm Destructive Operations:**

   ```powershell
   $result = Show-Confirm "This will delete $($items.Count) items. Continue?"
   if ($result -ne "yes") { return }
   ```
4. **Log Actions:**

   ```powershell
   Write-Log "Delegated access: $([Sitecore.Context]::User.Name) published $($item.Paths.FullPath)"
   ```

## 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](/security/security-policies) - Understand SPE security model
* [Session Elevation](/security/session-elevation) - Additional authentication layer
* [User and Role Management](/security/users-and-roles) - Managing Sitecore roles
* [Logging and Monitoring](/security/logging-and-monitoring) - Audit delegated access usage

## References

* [GitHub Issue #1283](https://github.com/SitecorePowerShell/Console/issues/1283) - Feature introduction


# 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
* Web services only (Remoting)

{% hint style="info" %}
This deployment is specifically designed for environments that only need remote script execution via SPE Remoting.
{% endhint %}

## 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 |
| ------------------------------------------- | ------------------------- | -------- |
| `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    |

### Web Service Files

| File Path                                                    | Purpose               | Required |
| ------------------------------------------------------------ | --------------------- | -------- |
| `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    |

### 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
5. Test connectivity

### 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`

```xml
<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

### Enable Remoting Service

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

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

```xml
<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>
```

### Secure Web Services

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

```xml
<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>
```

## Testing the Deployment

### Verify Minimal Installation

```powershell
# 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
```

## Security Best Practices

### Minimal Deployment Security Checklist

* [ ] **Remoting disabled by default** - Only enable when configuration complete
* [ ] **HTTPS required** (`requireSecureConnection="true"`)
* [ ] **Anonymous access denied** in web.config
* [ ] **Specific user accounts** configured (not Admin)
* [ ] **IP restrictions** configured (if applicable)
* [ ] **File upload restrictions** properly configured
* [ ] **Service accounts** use strong passwords
* [ ] **Service accounts** have minimal Sitecore permissions
* [ ] **Logging enabled** for all remote operations
* [ ] **Regular log review** scheduled
* [ ] **UI components verified disabled**

### 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
5. **Monitoring** - Comprehensive logging and alerts

## 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
5. IP address blocked

**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

* [Web Services Security](/security/web-services) - Detailed web service configuration
* [IIS Security](/security/iis-security) - IIS-level hardening
* [File Upload Restrictions](/security/file-upload-restrictions) - Configure upload limits
* [Security Checklist](/security/security-checklist) - Validation checklist
* [Logging and Monitoring](/security/logging-and-monitoring) - Monitoring remote operations
* [Remoting](/remoting) - Using SPE Remoting features

## References

* [SPE Remoting Documentation](/remoting)
* [SPE Minimal Package Download](https://github.com/SitecorePowerShell/Console/releases)


# 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
* Requiring Windows Authentication
* Blocking access at the web server level
* Protecting against attacks before they reach Sitecore

{% hint style="success" %}
**Defense in Depth:** Even if Sitecore security is bypassed, IIS security provides a second barrier.
{% endhint %}

## SPE Web Services Directory

SPE web services are located in:

```
sitecore modules\PowerShell\Services\
```

**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`:

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>
```

### 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:

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>
```

#### 3. Configure Remoting Clients

When using Windows Authentication, SPE Remoting commands require the **Credential** parameter:

```powershell
# 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)
```

### 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

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
      <allow users="DOMAIN\username1, DOMAIN\username2" />
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>
```

### Allow Specific Roles

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
      <allow roles="DOMAIN\Sitecore Administrators" />
      <deny users="*" />
    </authorization>
  </system.web>
</configuration>
```

### Order Matters

Rules are evaluated top to bottom. First match wins.

**Example:**

```xml
<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>
```

## 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:**

```xml
<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>
```

**Deny specific IPs:**

```xml
<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>
```

### 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`:

```xml
<system.webServer>
  <security>
    <ipSecurity allowUnlisted="false">
      <add ipAddress="10.0.0.100" allowed="true" />
    </ipSecurity>
  </security>
</system.webServer>
```

## SSL/TLS Requirements

Require HTTPS for all SPE web service access.

### Configuration via web.config

```xml
<configuration>
  <system.webServer>
    <security>
      <access sslFlags="Ssl, SslNegotiateCert" />
    </security>
  </system.webServer>
</configuration>
```

**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

```xml
<system.webServer>
  <security>
    <access sslFlags="Ssl" />
  </security>
</system.webServer>
```

### Require Client Certificates

For maximum security, require client certificates:

```xml
<system.webServer>
  <security>
    <access sslFlags="Ssl, SslRequireCert" />
  </security>
</system.webServer>
```

{% hint style="info" %}
**Note:** SPE also has a `requireSecureConnection` setting at the application level. Using both provides defense in depth.
{% endhint %}

## URL Rewrite Rules

Use IIS URL Rewrite module to block or redirect requests.

### Block Suspicious Patterns

```xml
<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>
```

### Redirect HTTP to HTTPS

```xml
<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>
```

## Request Filtering

Use IIS Request Filtering to block dangerous requests.

### Block Specific File Extensions

```xml
<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>
```

### Limit Request Size

```xml
<system.webServer>
  <security>
    <requestFiltering>
      <!-- Max 10MB requests -->
      <requestLimits maxAllowedContentLength="10485760" />
    </requestFiltering>
  </security>
</system.webServer>
```

### Block HTTP Verbs

```xml
<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>
```

## Complete Configuration Examples

### Production Environment (Standard Auth)

Strict security with deny anonymous:

```xml
<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>
```

### CI/CD Environment

Allow only build server, require HTTPS:

```xml
<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>
```

### Windows Authentication Environment

Require Windows auth with specific roles:

```xml
<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>
```

### High Security Environment

Multiple layers of protection:

```xml
<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>
```

## 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](/security/web-services) - Sitecore-level web service configuration
* [Security Policies](/security/security-policies) - Understanding SPE security model
* [Security Checklist](/security/security-checklist) - Validate your complete security configuration
* [Logging and Monitoring](/security/logging-and-monitoring) - Monitor for unauthorized access attempts

## References

* [ASP.NET Authorization](https://docs.microsoft.com/en-us/previous-versions/aspnet/wce3kxhd\(v=vs.100\))
* [IIS IP Security](https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/ipsecurity/)
* [IIS Request Filtering](https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/)
* [IIS URL Rewrite](https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/url-rewrite-module-configuration-reference)


# 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)
* RESTful API access
* File and media uploads/downloads
* Report exports

{% hint style="danger" %}
**Security Warning:** Only enable web services you specifically need. Each enabled service increases your attack surface. Never enable services on internet-facing servers.
{% endhint %}

## Service Configuration

Services are configured in `App_Config\Include\Spe\Spe.config`:

```xml
<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>
```

## 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:**

```xml
<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>
```

**Restrict to specific users:**

```xml
<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>
```

{% hint style="warning" %}
**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.
{% endhint %}

### 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

```xml
<configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
  <sitecore>
    <powershell>
      <services>
        <restfulv2>
          <patch:attribute name="enabled">true</patch:attribute>
        </restfulv2>
      </services>
    </powershell>
  </sitecore>
</configuration>
```

### 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](/security/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:

```xml
<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>
```

### CI/CD Configuration

Enable remoting for build automation, with strict security:

```xml
<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>
```

### Web API Configuration

Enable RESTful v2 for web API endpoints:

```xml
<configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
  <sitecore>
    <powershell>
      <services>
        <restfulv2>
          <patch:attribute name="enabled">true</patch:attribute>
        </restfulv2>
      </services>
    </powershell>
  </sitecore>
</configuration>
```

### Full SPE Remoting

Enable all remoting capabilities (use with caution):

```xml
<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>
```

## Role-Based Authorization

Restrict remoting access to specific roles or users.

### Default Authorization

By default, these roles can use remoting (when enabled):

```xml
<authorization>
  <add Permission="Allow" IdentityType="Role" Identity="sitecore\PowerShell Extensions Remoting" />
</authorization>
```

### Replace Default Roles

Remove default roles and add your own:

```xml
<authorization>
  <patch:delete />
</authorization>
<authorization>
  <add Permission="Allow" IdentityType="Role" Identity="sitecore\Automation" />
  <add Permission="Allow" IdentityType="Role" Identity="sitecore\Developers" />
</authorization>
```

### Add Specific Users

Grant access to individual users:

```xml
<authorization>
  <add Permission="Allow" IdentityType="User" Identity="sitecore\ci-user" />
  <add Permission="Allow" IdentityType="User" Identity="sitecore\deployment-user" />
</authorization>
```

### Combine Roles and Users

```xml
<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>
```

## IIS-Level Protection

Add an additional security layer by configuring IIS authentication.

### Deny Anonymous Access

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

```xml
<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>
```

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:

```powershell
$session = New-ScriptSession -Username "domain\user" -Password "password" -ConnectionUri "https://sitecore.local"
```

## 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 | Only UI features unless remoting needed |
| **Production CD** | None - don't install SPE          | CD servers should not have SPE          |

### 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                 | 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                                   |

## 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](/security/file-upload-restrictions)).

## Related Topics

* [File Upload Restrictions](/security/file-upload-restrictions) - Configure allowed file types and paths
* [IIS Security](/security/iis-security) - Additional IIS-level hardening
* [Remoting](/remoting) - Using SPE Remoting features
* [Web API](/modules/integration-points/web-api) - Building RESTful APIs with SPE

## References

* [SPE Remoting Documentation](/remoting)
* [ASP.NET Authorization](https://docs.microsoft.com/en-us/previous-versions/aspnet/wce3kxhd\(v=vs.100\))


# 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 [File Upload service](/security/web-services) is enabled, SPE enforces restrictions on:

* **File Types** - Which file extensions and MIME types can be uploaded
* **Upload Locations** - Which directories files can be written to

These restrictions apply to uploads via:

* SPE Remoting file upload
* Custom scripts using upload functionality

{% hint style="info" %}
This feature was introduced in SPE with [#1362](https://github.com/SitecorePowerShell/Console/issues/1362)
{% endhint %}

## Default Configuration

By default, SPE allows limited file types and restricts uploads to the Sitecore temp folder:

```xml
<powershell>
  <uploadFile>
    <allowedFileTypes>
      <pattern>image/*</pattern>
      <pattern>.xls</pattern>
      <pattern>.xlsx</pattern>
      <pattern>.csv</pattern>
    </allowedFileTypes>
    <allowedLocations>
      <path>$SitecoreMediaFolder</path>
    </allowedLocations>
  </uploadFile>
</powershell>
```

## 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

```xml
<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>
```

#### Allow MIME Type Categories

```xml
<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>
```

#### Allow Office Documents

```xml
<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>
```

### 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`          | `text/plain`, `text/*`                  |
| **Data Files**   | `.json`, `.xml`         | `application/json`, `application/xml`   |
| **Archives**     | `.zip`                  | `application/zip`                       |

{% hint style="danger" %}
**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.
{% endhint %}

## 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    | `C:\inetpub\wwwroot\temp`              |
| `$SitecoreMediaFolder`   | Media folder   | `C:\inetpub\wwwroot\upload`            |

### Configuration Examples

#### Allow Only Temp Folder (Most Secure)

```xml
<configuration xmlns:patch="https://www.sitecore.net/xmlconfig/">
  <sitecore>
    <powershell>
      <uploadFile>
        <allowedLocations>
          <path>$SitecoreTempFolder</path>
        </allowedLocations>
      </uploadFile>
    </powershell>
  </sitecore>
</configuration>
```

{% hint style="success" %}
**Recommended:** Standardize your solution with a folder that you will routinely clean.
{% endhint %}

#### Allow Multiple Locations

```xml
<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>
```

### Dangerous Locations to NEVER Allow

❌ **Never allow uploads to these locations:**

```xml
<!-- 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>
```

## Complete Configuration Examples

### Secure Configuration (Data Import Use Case)

Allow CSV/Excel imports to a dedicated import folder:

```xml
<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>
```

## 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](/security/web-services) - Enable/disable file upload service
* [Security Checklist](/security/security-checklist) - Validate your configuration
* [Logging and Monitoring](/security/logging-and-monitoring) - Monitor upload activity

## References

* [GitHub Issue #1362](https://github.com/SitecorePowerShell/Console/issues/1362) - Feature introduction


# 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

{% hint style="success" %}
**Security Best Practice:** Enable comprehensive logging in all non-development environments to create an audit trail.
{% endhint %}

## SPE Log Files

### Default Log Location

SPE logs are written to:

```
$SitecoreLogFolder\SPE.log.{date}.txt
```

Typically resolves to:

```
C:\inetpub\wwwroot\App_Data\logs\SPE.log.20260101.txt
```

## Log Levels

SPE supports standard log4net levels:

| Level     | Description                     | Use Case                        |
| --------- | ------------------------------- | ------------------------------- |
| **DEBUG** | Detailed diagnostic information | Development and troubleshooting |
| **INFO**  | Informational messages          | Production (recommended)        |
| **WARN**  | Warning messages                | Production (recommended)        |
| **ERROR** | Error messages                  | Always enabled                  |
| **FATAL** | Critical errors                 | Always enabled                  |

### Configuring Log Level

Edit your log4net configuration (typically in `App_Config\Sitecore.config` or a patch file):

```xml
<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>
```

**Recommended Settings:**

| Environment     | Log Level    | Rationale                                 |
| --------------- | ------------ | ----------------------------------------- |
| **Development** | DEBUG        | Maximum detail for troubleshooting        |
| **QA/Staging**  | INFO         | Balance detail and volume                 |
| **Production**  | INFO or WARN | Important events without excessive detail |

## What Gets Logged

### Script Execution

**Format:**

```
INFO Arbitrary script execution in ISE by user: 'sitecore\Admin'
```

### Session Elevation

**Format:**

```
WARN Session state elevated for 'ISE' by user: sitecore\Admin
```

### Delegated Access

**Format:**

```
INFO [Gutter] Executing script {CFE81AF6-2468-4E62-8BF2-588B7CC60F80} for Context User sitecore\test as sitecore\Admin.
```

**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:**

```
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.
```

**Logged Events:**

* Remoting connections
* File uploads/downloads
* RESTful API calls
* Authorization failures

### Authentication Events

**Format:**

```
INFO [Runner] Executing script {BD07C7D1-700D-450C-B79B-8526C6643BF3} for Context User sitecore\test2 as sitecore\Admin.
```

**Logged Events:**

* Successful authentication
* Failed authentication
* Authorization denials

### Errors and Exceptions

**Format:**

```powershell
# TODO
```

**Includes:**

* Exception details
* Stack traces
* User context
* Operation being performed

## Monitoring Strategies

### Real-Time Monitoring

#### Using PowerShell to Tail Logs

```powershell
# 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
```

```powershell
# 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}
```

#### Monitor for Specific Events

```powershell
# Watch for tasks
Get-Content "$SitecoreLogFolder\SPE.log.20251201.txt" | Where-Object { $_ -match "\[Task\]" }
```

```powershell
# Watch for warnings
Get-Content "$SitecoreLogFolder\SPE.log.20251201.txt" | Where-Object { $_ -match "WARN" }
```

### Log Analysis

#### Find Failed Authentication Attempts

```powershell
$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.
```

#### Track Delegated Access Usage

```powershell
$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
```

#### Find Unauthorized Access Attempts

```powershell
$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.
```

#### Analyze Web Service Usage

```powershell
$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
```

### Scheduled Log Review

Create a scheduled task to analyze logs daily:

```powershell
# TODO: Example using Send-MailMessage
```

## IIS Log Integration

### IIS Logs for Web Services

IIS logs provide additional context for web service access:

**Location:**

```
C:\inetpub\logs\LogFiles\W3SVC1\
```

### Useful IIS Log Fields

| Field             | Description            | Security Value                         |
| ----------------- | ---------------------- | -------------------------------------- |
| **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       | Find authorization failures (401, 403) |
| **cs-User-Agent** | User agent string      | Identify automation vs browsers        |

### Analyzing IIS Logs for SPE

Find SPE web service requests:

```powershell
# TODO Inspect IIS Logs
```

Find failed authentication (401) to SPE services:

```powershell
# TODO Inspect IIS Logs
```

## Alerting

### Simple Email Alerts

Create alerts for critical security events:

```powershell
# TODO Example with Send-MailMessage
```

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      |
| ----------- | ------------------------ |
| **PCI-DSS** | 1 year (3 months online) |
| **HIPAA**   | 6 years                  |
| **SOC 2**   | 1+ years                 |
| **GDPR**    | Varies by data type      |

**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            |
| ------------------------ | ------------------------------- | -------------------- |
| **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        |
| **File Upload Attempts** | File upload failures            | Monitor for patterns |
| **Script Errors**        | Script execution errors         | Monitor trends       |

## 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
* 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

❌ **Don't:**

* Disable logging in production
* Ignore failed authentication attempts
* Delete logs prematurely
* Log sensitive data (passwords, tokens)
* Rely solely on manual log review
* Forget to monitor IIS logs too
* Ignore ERROR and WARN messages
* Let log files consume all disk space

### Monitoring Frequency

| Activity             | Frequency  | Method                        |
| -------------------- | ---------- | ----------------------------- |
| **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 |
| **Quarterly Report** | Quarterly  | Executive summary             |

## 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

* [Security Checklist](/security/security-checklist) - Includes logging validation
* [Delegated Access](/security/delegated-access) - Monitoring delegated access usage
* [Web Services](/security/web-services) - Monitoring web service security
* [IIS Security](/security/iis-security) - IIS log integration

## References

* [log4net Documentation](https://logging.apache.org/log4net/)
  * Your Sitecore implementation may require vendor-specific documentation as log4net is bundled/compiled in the Sitecore libraries.
* [Sitecore Logging Documentation](https://doc.sitecore.com/xp/en/developers/latest/platform-administration-and-architecture/logging.html)
* [IIS Log File Formats](https://docs.microsoft.com/en-us/iis/manage/provisioning-and-managing-iis/configure-logging-in-iis)


# 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](https://twitter.com/scriptingspe).

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

* [Book issue tracker](https://github.com/SitecorePowerShell/Book/issues)
* [Module issue tracker](https://github.com/SitecorePowerShell/Console/issues)
* [Module releases](https://github.com/SitecorePowerShell/Console/releases)

See the [Appendix](/appendix) for a compatibility matrix.


# 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`.

{% hint style="info" %}
You can see the Sitecore Stack Exchange answer [here](https://sitecore.stackexchange.com/questions/17984/unable-to-elevate-console-in-9-1-azure-paas/18775#18775) describing the contents of the configuration.
{% endhint %}

### Hanging Installation Wizard

Some users have reported an [issue](https://github.com/SitecorePowerShell/Console/issues/404) 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 [here](https://github.com/SitecorePowerShell/Book/tree/5daee3160885dadd7031fee723dccf12a33abd7b/\[https:/blog.martinmiles.net/post/sitecore-8-re-indexing-errors-out-and-module-installation-never-ends-without-mongodb-running]/README.md).

**Hack:** Run this script on Sitecore 8.0.

```powershell
$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" }
```

## Exception Messages

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

* [378](https://github.com/SitecorePowerShell/Console/issues/378) - 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.
* Web API - Scripts not existing or can't be found.

### 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 #[1005](https://github.com/SitecorePowerShell/Console/issues/1005).
* **"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.
  * `[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12`


# 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.

```powershell
# 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
```

## Media item url

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

```powershell
$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
```

## Parse Html

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

```powershell
$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;
}
```

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

```powershell
$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
```

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

[Sitecore Stack Exchanage](https://sitecore.stackexchange.com/a/20845/95)

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

```powershell
$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
```

## Workflow History

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

```powershell
$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)',''))"
    }
}
```

## Restore Recycle bin items

**Example:** The following restores items in the media library that were removed yesterday. [Credit](https://gist.github.com/technomaz/58890edff903123083c77ad8f1b1b2e2) @technomaz.

```powershell
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)"
        }
    }
}
```

## Purge Recycle bin items

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

```powershell
$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"
```

## Run JavaScript

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

```powershell
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');"
```

![Invoke JavaScript](/files/-LA37d_OtRAwvvYruYW5)

## Remoting

**Example:** [Remote Package Installation](https://gist.github.com/michaellwest/14e9ef98f9e8b450c1b39813d13cbc50)

```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
```

Not seeing what you are looking for? You can always check out some Github Gists that [Adam](https://gist.github.com/adamnaj) and [Michael](https://gist.github.com/michaellwest) have shared or the [Sitecore Stack Exchange](https://sitecore.stackexchange.com/questions/tagged/powershell-extensions).


# 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 [here](https://gist.github.com/michaellwest/f563b0b3597f6c0a75d6).

```powershell
$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
}
```

### Remove Item Link

Example: The following removes an item link followed by removing the item. Originally posted [here](https://gist.github.com/michaellwest/f563b0b3597f6c0a75d6).

```powershell
# 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
}
```


# 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.

```powershell
# Hardcoded list of Ids.
$item.Editing.BeginEdit()
$item["Allowed Controls"] = "{guid1}|{guid2}|{guid3}"
$item.Editing.EndEdit()
```

```powershell
# 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()
```

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

```powershell
[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()
```

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

```powershell
[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
```

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

```powershell
$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}"
    }
}
```

**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.

```powershell
$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 "|"
}
```

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

```powershell
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($_) } }
```

## Edit NameValueListField

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

```powershell
$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,"&")
```


# Manage Templates

Examples for managing item templates.

## Manage Templates

### Change Template

```powershell
# 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
    }
```

## Sitecore Stack Exchange

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

* [Question](https://sitecore.stackexchange.com/a/15168/95) Find all items based on a template found anywhere in the inheritance chain.


# Dialogs

Examples for managing complex interactive dialogs.

## Basic text controls

```powershell
<#
    .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
}
```

## Number controls

```powershell
<#
    .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)"
}
```

## Checkbox control

```powershell
<#
    .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
    }
}
```

## Dropdown combo controls

```powershell
<#
    .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
}
```

## Checklist control

```powershell
<#
    .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)"
        }
    }
}
```

## Radio button control

```powershell
<#
    .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 }
    }
}
```

## Date Time control

```powershell
<#
    .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
}
```

## Single item picker with a tree

```powershell
<#
    .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
    }
}
```

## Treelist control

```powershell
<#
    .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"
#>
```

## Multilist controls

```powershell
<#
    .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.
#>
```

## Droplist contol

```powershell
<#
    .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.
#>
```

## Grouped dropdown controls

```powershell
<#
    .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.
#>
```

## User role pickers

```powershell
<#
    .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"
#>
```

## Rule editor controls

```powershell
<#
    .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
#>
```

## Info display controls

```powershell
<#
    .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.
#>
```

## Variable binding

```powershell
<#
    .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
#>
```

## Tabbed dialog

```powershell
<#
    .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"
#>
```

## Conditional visibility

```powershell
<#
    .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
#>
```

## Column layout

```powershell
<#
    .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
#>
```

## Mandatory fields

```powershell
<#
    .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
#>
```

## Dialog customization

```powershell
<#
    .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
#>
```

## Simple dialog

```powershell
<#
    .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
#>
```

## Comprehensive example

```powershell
<#
    .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
```


# Appendix

[Downloads are hosted on Github](https://github.com/SitecorePowerShell/Console/releases/)

## Compatibility Table

**Legend:** "–" - not supported; "✓" - supported.

### Sitecore 9.3 and newer

| SPE ↓ / Sitecore→ | **9.3** | **10.0** | **10.1** | **10.2** | **10.3** | **10.4** |
| ----------------- | ------- | -------- | -------- | -------- | -------- | -------- |
| 8.0               | ✓       | ✓        | ✓        | ✓        | ✓        | ✓        |
| 7.0               | ✓       | ✓        | ✓        | ✓        | ✓        | ✓        |
| 6.4               | ✓       | ✓        | ✓        | ✓        | ✓        | -        |
| 6.3               | ✓       | ✓        | ✓        | ✓        | -        | -        |
| 6.2               | ✓       | ✓        | ✓        | -        | -        | -        |
| 6.1               | ✓       | ✓        | ✓        | -        | -        | -        |
| 6.0               | ✓       | ✓        | ✓        | -        | -        | -        |

### Sitecore 9.2 and older

| SPE ↓ / Sitecore→ | **8.0** | **8.1** | **8.2** | **9.0** | **9.1** | **9.2**                           |
| ----------------- | ------- | ------- | ------- | ------- | ------- | --------------------------------- |
| 8.0               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 7.0               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 6.4               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 6.3               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 6.2               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 6.1               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 6.0               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓                                 |
| 5.1               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓ [\[2\]](#notes)                 |
| 5.0               | ✓       | ✓       | ✓       | ✓       | ✓       | ✓ [\[1\]](#notes) [\[2\]](#notes) |
| 4.7               | ✓       | ✓       | ✓       | ✓       | ✓       | –                                 |
| 4.6               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.5               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.4               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.3               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.2               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.1               | ✓       | ✓       | ✓       | –       | –       | –                                 |
| 4.0               | ✓       | ✓       | –       | –       | –       | –                                 |

### Compatibility Notes <a href="#notes" id="notes"></a>

* \[1] Released by Sitecore for SXA which can be download from the [SXA 1.9.0 release page](https://dev.sitecore.net/Downloads/Sitecore_Experience_Accelerator/19/Sitecore_Experience_Accelerator_190.aspx) 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 ([#1129](https://github.com/SitecorePowerShell/Console/issues/1129))
  * Indexing commands unsupported ([#1133](https://github.com/SitecorePowerShell/Console/issues/1133))

### 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.
* **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.


# Common


# 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\[]>

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.

```powershell
PS master:\> Add-BaseTemplate -Path "master:/sitecore/content/User Defined/Page" -Template "/sitecore/templates/User Defined/BaseTemplate"
```

### EXAMPLE 2

Add multiple base templates to a template, using items.

```powershell
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)
```

## Related Topics

* [Remove-BaseTemplate](/appendix/common/remove-basetemplate)
* [Get-ItemTemplate](/appendix/common/get-itemtemplate)
* [Set-ItemTemplate](/appendix/common/set-itemtemplate)
* <https://github.com/SitecorePowerShell/Console/>


# Add-ItemVersion

Creates a version of the item in a new language based on an existing language version.

## Syntax

```powershell
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[]>]
```

## 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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -TargetLanguage \<String\[]>

Language or a list of languages that should be created

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -DoNotCopyFields \<SwitchParameter>

Creates a new version in the target language but does not copy field values from the original language

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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
* \_\_Page Level Test Set Definition
* \_\_Reminder date
* \_\_Reminder recipients
* \_\_Reminder text

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

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Item \<Item>

The item / version to be processed.

| 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 processed - additionally specify Language parameter to fetch different item language than the current user language.

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Id \<String>

Id of 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 |

## 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

```powershell
PS master:\> Add-ItemVersion -Path "master:\content\home" -Language "en" -TargetLanguage "pl-pl", "en-us" -IfExist Skip -IgnoredFields "Title"
```

### EXAMPLE 2

```powershell
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
```

### 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.

```powershell
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
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>
* [Remove-ItemVersion](/appendix/common/remove-itemversion)
* New-Item
* <https://gist.github.com/AdamNaj/b36ea095e3668c22c07e>


# Close-Window

Closes the runner job window after the script completes.

## Syntax

Close-Window

## 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

```powershell
PS master:\> Close-Window
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# ConvertFrom-CliXml

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

## Syntax

ConvertFrom-CliXml \[-InputObject] \<String>

## 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

```powershell
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
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>
* [ConvertTo-CliXml](/appendix/common/convertto-clixml)
* ConvertTo-Xml
* ConvertFrom-Xml
* Export-CliXml
* Import-CliXml
* <https://github.com/SitecorePowerShell/Console/issues/218>


# 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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -PassThru \<SwitchParameter>

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Item \<Item>

The item to be converted.

| 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 converted

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Id \<String>

Id of the item to be converted

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Database \<String>

Database containing the item to be converted

| 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

```powershell
PS master:\> ConvertFrom-ItemClone -Path master:\content\home
```

## Related Topics

* [New-ItemClone](/appendix/common/new-itemclone)
* [Get-ItemClone](/appendix/common/get-itemclone)
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |                |
| --------------------------- | -------------- |
| 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.

* 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

```powershell
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
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>
* [ConvertFrom-CliXml](/appendix/common/convertfrom-clixml)
* ConvertFrom-Xml
* ConvertTo-Xml
* Export-CliXml
* Import-CliXml


# 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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Item \<Item>

The item to be processed.

| 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 processed - additionally specify Language parameter to fetch different item language than the current user language.

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| 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 |

## 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.

```powershell
Get-Item -Path "master:\content\home" | Expand-Token
```

### 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).

```powershell
$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
```

## Related Topics

* <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/>


# Get-Archive

Returns Sitecore database archives.

## Syntax

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

## 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

```powershell
PS master:\> Get-Archive -Database "master"

Name                                        Items
----                                        -----
archive                                         0
recyclebin                                   1950
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# Get-ArchiveItem

Retrieves a list of items found in the specified archive.

## Syntax

```powershell
Get-ArchiveItem -Archive <Archive>
Get-ArchiveItem -Archive <Archive> [-ItemId <ID>]
Get-ArchiveItem -Archive <Archive> [-Identity <AccountIdentity>]
```

## 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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -ItemId \<ID>

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

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Identity \<AccountIdentity>

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

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

## 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.

```powershell
$database = Get-Database -Name "master"
$archiveName = "recyclebin"
$archive = Get-Archive -Database $database -Name $archiveName
Get-ArchiveItem -Archive $archive
```

### EXAMPLE 2

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

```powershell
$database = Get-Database -Name "master"
$archiveName = "recyclebin"
$archive = Get-Archive -Database $database -Name $archiveName
Get-ArchiveItem -Archive $archive -ItemId "{1BB32980-66B4-4ADA-9170-10A9D3336613}"
```

### EXAMPLE 3

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

```powershell
$database = Get-Database -Name "master"
$archiveName = "recyclebin"
$archive = Get-Archive -Database $database -Name $archiveName
Get-ArchiveItem -Archive $archive -Identity "sitecore\admin"
```

### EXAMPLE 4

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

```powershell
$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}"
```

## Related Topics

* Remove-ArchiveItem
* Restore-ArchiveItem
* Remove-Item
* Remove-ItemVersion
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

## 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

```powershell
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
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# Get-Database

Retrieves a Sitecore Database.

## Syntax

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

## 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

```powershell
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
```

### EXAMPLE 2

```powershell
PS master:\> Get-Database -Name "master"

Name                 Languages                      Protected  Read Only
----                 ---------                      ---------  ---------
master               {en, de-DE, es-ES, pt-BR...}   False      False
```

### EXAMPLE 3

```powershell
PS master:\> Get-Item . | Get-Database

Name                 Languages                      Protected  Read Only
----                 ---------                      ---------  ---------
master               {en, de-DE, es-ES, pt-BR...}   False      False
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# 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                     |                                |
| --------------------------- | ------------------------------ |
| 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 for clones presence.

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Id \<String>

Id of the item to be analysed for clones presence.

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Database \<String>

Database containing the item to be processed - if item is being provided through 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

```powershell
PS master:\> Get-ItemClone -Path master:\content\home
```

## Related Topics

* [New-ItemClone](/appendix/common/new-itemclone)
* [ConvertFrom-ItemClone](/appendix/common/convertfrom-itemclone)
* <https://github.com/SitecorePowerShell/Console/>
* <https://github.com/SitecorePowerShell/Console/issues/218>
* Get-Item


# Get-ItemCloneNotification

## Syntax

```powershell
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[]>]
```

## Detailed Description

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

## 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.

```powershell
$clonedItem = Get-Item -Path "master:" -ID "{9F158637-52C2-4005-8329-21527685CB71}"
Get-ItemCloneNotification -Item $clonedItem
```

### EXAMPLE 2

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

```powershell
$clonedItem = Get-Item -Path "master:" -ID "{9F158637-52C2-4005-8329-21527685CB71}"
$clonedItem | Get-ItemCloneNotification -NotificationType ItemMovedChildRemovedNotification
```


# 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\[]>]

## 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

```powershell
PS master:\> Get-ItemField -Path master:\content\home

Text
Title
Image
```

### 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.

```powershell
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.
```

## Related Topics

* [Get-ItemTemplate](/appendix/common/get-itemtemplate)
* [Reset-ItemField](/appendix/common/reset-itemfield)
* <https://github.com/SitecorePowerShell/Console/>


# 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\[]>]

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

```powershell
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
```

### EXAMPLE 2

```powershell
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
```

## Related Topics

* [Get-ItemReferrer](/appendix/common/get-itemreferrer)
* [Update-ItemReferrer](/appendix/common/update-itemreferrer)
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | true                           |
| Position?                   | named                          |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| 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 linking to 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

```powershell
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
```

### EXAMPLE 2

```powershell
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
```

## Related Topics

* [Get-ItemReference](/appendix/common/get-itemreference)
* [Update-ItemReferrer](/appendix/common/update-itemreferrer)
* <https://github.com/SitecorePowerShell/Console/>


# 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]

## 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

```powershell
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
```

### 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

```powershell
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
```

## Related Topics

* [Get-ItemField](/appendix/common/get-itemfield)
* [Set-ItemTemplate](/appendix/common/set-itemtemplate)
* [Add-BaseTemplate](/appendix/common/add-basetemplate)
* [Remove-BaseTemplate](/appendix/common/remove-basetemplate)
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |       |
| --------------------------- | ----- |
| 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 |

### -Item \<Item>

The item to have its history items returned.

| Aliases                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | true                           |
| Position?                   | 1                              |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| Accept Wildcard Characters? | false                          |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Database \<String>

Database containing the item to have its history items returned - 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.Workflows.WorkflowEvent

## Notes

Help Author: Adam Najmanowicz, Michael West

## Examples

### EXAMPLE

```powershell
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
```

## Related Topics

* [New-ItemWorkflowEvent](/appendix/common/new-itemworkflowevent)
* Execute-Workflow
* <https://github.com/SitecorePowerShell/Console/>


# 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

```powershell
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
```

### EXAMPLE 2

```powershell
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
```

### EXAMPLE 3

```powershell
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} }
```

![Example 3](/files/-LTu9z0_fcsJEGdjl4bA)

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>
* <https://www.youtube.com/watch?v=N3xgZcU9FqQ&list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b&index=9>


# 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>

## 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

```powershell
PS master:\> Get-SpeModule -Database (Get-Database "master")
```

### EXAMPLE 2

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

```powershell
PS master:\> Get-SpeModule -Database (Get-Database "master")
```

### EXAMPLE 3

Return the module the piped script belongs to

```powershell
PS master:\> Get-item "master:\system\Modules\PowerShell\Script Library\Copy Renderings\Content Editor\Context Menu\Layout\Copy Renderings" |  Get-SpeModule
```

## Related Topics

* [Get-SpeModuleFeatureRoot](/appendix/common/get-spemodulefeatureroot)
* <https://blog.najmanowicz.com/2014/11/01/sitecore-powershell-extensions-3-0-modules-proposal/>
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | false                          |
| Position?                   | named                          |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| Accept Wildcard Characters? | false                          |

### -ReturnPath \<SwitchParameter>

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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
* functions
* listViewExport
* listViewRibbon
* pipelineLoggedIn
* pipelineLoggingIn
* pipelineLogout
* toolbox
* startMenuReports
* eventHandlers
* webAPI
* pageEditorNotification
* isePlugi

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| 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

  System.String

## Notes

Help Author: Adam Najmanowicz, Michael West

## Examples

### EXAMPLE 1

Return the library item for "Content Editor Context Menu"

```powershell
$module = Get-SpeModule -Name "Copy Renderings"
Get-SpeModuleFeatureRoot -Feature contentEditorContextMenu -Module $module
```

### EXAMPLE 2

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

```powershell
$module = Get-SpeModule -Name "Copy Renderings"
Get-SpeModuleFeatureRoot -Module $module -Feature listViewExport -ReturnPath
```

## Related Topics

* [Get-SpeModule](/appendix/common/get-spemodule)
* <https://blog.najmanowicz.com/2014/11/01/sitecore-powershell-extensions-3-0-modules-proposal/>
* <https://github.com/SitecorePowerShell/Console/>


# 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                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | true                           |
| Position?                   | named                          |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| Accept Wildcard Characters? | false                          |

### -Path \<String>

Path to the item to be returned as Task Schedule.

| Aliases                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | true                           |
| Position?                   | named                          |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| Accept Wildcard Characters? | false                          |

### -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                     |                |
| --------------------------- | -------------- |
| Required?                   | false          |
| Position?                   | 2              |
| Default Value               |                |
| Accept Pipeline Input?      | true (ByValue) |
| Accept Wildcard Characters? | false          |

### -Name \<String>

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

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | 1     |
| 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.Tasks.ScheduleItem

## Notes

Help Author: Adam Najmanowicz, Michael West

## Examples

### EXAMPLE 1

```powershell
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
```

### EXAMPLE 2

```powershell
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
```

### EXAMPLE 3

```powershell
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
```

## Related Topics

* [Start-TaskSchedule](/appendix/common/start-taskschedule)
* <https://github.com/SitecorePowerShell/Console/>
* <https://www.youtube.com/watch?v=N3xgZcU9FqQ&list=PLph7ZchYd_nCypVZSNkudGwPFRqf1na0b&index=9>


# Get-UserAgent

Returns the current user's browser user agent.

## Syntax

## Detailed Description

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

```powershell
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
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# Import-Function

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

## Syntax

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

## 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

```powershell
PS master:\> Import-Function -Name Resolve-Error
```

## Related Topics

* [Invoke-Script](/appendix/common/invoke-script)
* <https://github.com/SitecorePowerShell/Console/>


# Invoke-JavaScript

## Syntax

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

## Detailed Description

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

## Parameters

### -Script  \<String>

| Aliases                     |                |
| --------------------------- | -------------- |
| Required?                   | true           |
| Position?                   | 1              |
| Default Value               |                |
| Accept Pipeline Input?      | true (ByValue) |
| Accept Wildcard Characters? | false          |

### -OnScriptEnd \<SwitchParameter>

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |


# 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\[]>]

## 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

```powershell
Invoke-Script 'Examples\Script Testing\Long Running Script with Progress Demo'
```

### EXAMPLE 2

Run a script with arguments passed in.

```powershell
$scriptItem = Get-Item -Path "master:" -ID "{35311878-54EF-4E7A-9B95-3B63F5DEE97D}"

$arguments = @{
    TemplateId = "{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}"
}
$scriptItem | Invoke-Script -ArgumentList $arguments
```

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

```powershell
param($params)
$templateId = $params.templateId

Get-ItemReferrer -ID $templateId
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>
* [Import-Function](/appendix/common/import-function)


# 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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| 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 |

### -Item \<Item>

The item to be sent to the command.

| 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 sent to the command - additionally specify Language parameter to fetch different item language than the current user language.

| Aliases                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Database \<String>

Database containing the item to be sent to the command - 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

## Notes

Help Author: Adam Najmanowicz, Michael West

## Examples

### EXAMPLE 1

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

```powershell
PS master:\> Get-Item master:\content\home\ | Invoke-ShellCommand "item:publishingviewer"
```

### EXAMPLE 2

Initiate /sitecore/content/home item duplication.

```powershell
PS master:\> Get-Item master:/content/home | Invoke-ShellCommand "item:duplicate"
```

### EXAMPLE 3

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

```powershell
PS master:\> Get-Item master:/content/home | Invoke-ShellCommand "contenteditor:properties"
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# 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                     |       |
| --------------------------- | ----- |
| Required?                   | false |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Comments \<String>

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

| 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 |

### -Item \<Item>

The item to have the workflow action executed.

| Aliases                     |                                |
| --------------------------- | ------------------------------ |
| Required?                   | true                           |
| Position?                   | 1                              |
| Default Value               |                                |
| Accept Pipeline Input?      | true (ByValue, ByPropertyName) |
| Accept Wildcard Characters? | false                          |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | 1     |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -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                     |       |
| --------------------------- | ----- |
| Required?                   | true  |
| Position?                   | named |
| Default Value               |       |
| Accept Pipeline Input?      | false |
| Accept Wildcard Characters? | false |

### -Database \<String>

Database containing the item to have the workflow action executed - 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

## Notes

Help Author: Adam Najmanowicz, Michael West

## Examples

### EXAMPLE 1

Submit item to approval, item gotten from path

```powershell
PS master:\> Invoke-Workflow -Path master:/content/home -CommandName "Submit" -Comments "Automated"
```

### EXAMPLE 2

Reject item, item gotten from pipeline

```powershell
PS master:\> Get-Item master:/content/home | Invoke-Workflow -CommandName "Reject" -Comments "Automated"
```

## Related Topics

* <https://github.com/SitecorePowerShell/Console/>


# 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]

## 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.

```powershell
PS master:\> $newTarget = Get-Item master:\content\new-target\
PS master:\> New-ItemClone -Path master:\content\home -Destination $newTarget -Name "New Home"
```

## Related Topics

* [Get-ItemClone](/appendix/common/get-itemclone)
* [ConvertFrom-ItemClone](/appendix/common/convertfrom-itemclone)
* New-Item
* <https://github.com/SitecorePowerShell/Console/>
* <https://github.com/SitecorePowerShell/Console/issues/218>




---

[Next Page](/llms-full.txt/1)

