Feel the Power of PowerShell

06 May 2013
Szymon Kuzniak
Frink_Cognifide_2016_HeaderImages_0117
Powershell completes Sitecore
 It is always fun when a client request comes 30 minutes before the end of your work day. Recently I was asked to release a new market, and after believing I could finish on time, I selected the option to include child pages, ensured the correct language was selected, hit the publish button and… I could not believe my eyes. The content looked like it had been perforated with a heavy machine gun. A few of the pages were published but all the rest were missing.

Join me on my journey from the Dark Ages of manual processing to the scripting enlightenment with Powershell!

What went wrong this time?

Good Morning workflows! Most of the pages were still in the 'draft' state, which means they could not be simply published before they were all approved. And there were a decent number of pages to approve. Having visions of hot dinner slipping slowly away, I started to explore my options. An approval of a page would take me half a minute. So for forty pages it would be twenty minutes of constant work. Constant, dull work for each market to be processed.

There has to be a better way

Luckily I was still sitting next to Adam who, whenever asked questions about how to perform a batch operation on Sitecore, has always the same answer: Powershell. But what is important is that this answer is always right!

 I asked the client if I could approve all the pages and started writing the appropriate script. If I had decided to manually click on every page to approve it, I would have to wait for the response helplessly. Coding was a much funnier alternative. I found a nice and ready to use snippet by my colleague Kris who did similar things but in different conditions, though the idea was still the same. So by the time I was permitted to approve all pages, the result was only one script call away. And the next day, when I had to publish another market, it was still a matter of a single script. Oh, how I love batch processing!

Enough of cool stories

Let's get to the meat. Here you can find the script I used with explanations.

As mentioned I based my solution on a script already created (thanks Kris!).

The first important part was a function to filter items. It would have been very easy to fall into a trap of putting the whole script into a huge single-monster-liner but I believed one had better not to go that way.

This routine is expected to filter out some items which do not meet the criteria but in my case I needed to actually add more items. More specifically I needed to include all language variations of the item.
function FilterItemsToProcess($item)
{
    Get-Item $item.ProviderPath -Language *
}
I was pretty sure this would not be very straightforward. The Sitecore API has an interesting approach when it comes to getting the item in different language versions. It turned out that with Powershell it was easier than it had ever been before with code. Basically all I had to do was to call cmdlet Get-Item, specify the original path and ask to include all versions. The asterisk there is an actual wildcard not just ALL_LANGUAGES_INDICATOR, which means you can safely use "en-*" for each variation of the English language.

 Another nice piece of functionality (worth extracting into a separate function) was the routine for changing the workflow state. Thanks to Powershell, it does not require a beginning edit and committing your changes. All I had to do was to assign a correct ID to an appropriate field. I actually did even more and ensured that all the items were not only in a correct workflow state but also in a correct workflow!
function ProcessItem($item)
{
    $item.__Workflow = "{My-super-sweet-workflow-id}";
    $item."__Workflow state" = "{My-even-sweeter-approved-state-id}";
}
When I had all my helpers ready I could look if the rest of the script required to change. Now here comes another advantage of the approach with using functions. It turned out that all the varying functionality was abstracted into functions and all I had to do was to adjust them to my needs.

The following line gets the items which should be processed in the correct language version. The context is set by running the script in an appropriate market so that we are approving one branch only  (not the whole tree). It is quite important to remember about narrowing script execution.
$itemsToProcess = get-childitem . -recurse | foreach {FilterItemsToProcess($_)}
And finally the execution itself. Again not much to do here thanks to abstraction. Huge kudos for showing a nicely formatted state before and after the change. Somewhere in the middle, there is a small, inconspicuous but extremely powerful call to our process method for each filtered item.
if($itemsToProcess -ne $null)
{
    $itemsToProcess | format-table -auto -property `
        @{Expression={$_."__Updated by"};Label="Updated"},`
        @{Expression={$_.__Workflow};Label="Workflow"},`
        @{Expression={$_."__Workflow state"};Label="State"}, `
        Language, ItemPath

    $itemsToProcess | foreach {ProcessItem($_)}

    $itemsToProcess | format-table -auto -property `
        @{Expression={$_."__Updated by"};Label="Updated"},`
        @{Expression={$_.__Workflow};Label="Workflow"},`
        @{Expression={$_."__Workflow state"};Label="State"}, `
        Language, ItemPath
}
else
{
    Write-Host "No items to process"
}
This abstraction has also a great advantage when testing the script. All you need to do is to cut out this little bit of code and rather than show two similar lists of items, this script will do nothing unexpected. Brilliant!

Was it worth it?

With Powershell, I have been able to delegate all the dull and boring jobs to the mindless script. Now, not only have I saved myself from zombie-like tasks but I have also saved tons of time I can now spend playing table foot.. erm coding. It took me about half an hour to develop the script and I have used it three times so far. This means I have already saved half an hour. But now every following call will add to this number.

I have also shown you how Powershell can ease some of the tasks in Sitecore which are not so obvious to use with the API. Not to mention the fact that I did not have to release anything to do that. All you need is the console and then you are free to script!

This template can actually be used to do any kind of processing items in Sitecore (and with small changes in any other environment). It's simple in terms of construction and usage, so feel free to take it and modify at your will. Feel the power of Powershell!

Remember: with great power comes great responsibility. Use the Sitecore Powershell with care. Always perform a database backup and test your scripts in a non-production environment. Cognifide will take no responsibility for any damage caused by the improper use of scripts.