Sitecore PowerShell – Practical Scripts, Part 1

powershell

I have been working a lot lately with the Sitecore PowerShell module. Our site is international and therefore we need to support lots of different languages, and the PowerShell module is an invaluable tool in maintaining content across cultures.

There are lots of great resources available to learn more about the module.
Here I am going to start compiling a repository of (hopefully) useful, practical scripts that you can borrow, steal, and learn from. Here we go…

Quick syntax note: in most of the examples below, I use the following syntax for selecting items:

Get-Item -Path "master:/sitecore/content/Home/About Us"

Technically, the “/sitecore” part is not necessary – PowerShell assumes that part. But when copy/pasting out of Sitecore, I’ve found it’s a lot easier to just paste in the entire path rather than go back and remove that one little piece. It really doesn’t matter. Of course you can also use the -ID for selecting, but again, I’m so used to just copy/pasting the path that it’s just easier for me. Do what you like 🙂

Adding Item Languages

These are probably the most-used scripts in my arsenal. We are forever needing to copy/create new language versions for items and child items.
(NOTE: we don’t use language fallbacks much, mostly for compliance and legal reasons, and because they have caused us too many headaches in the past. Therefore managing separate versions for each language/country is an essential and time-consuming task. These scripts help.)

Add Item Language – Single Item

As the title suggests, this simply takes a single item and creates new language versions of that item, copied from a single version. The “-Language” value is the one we’re copying from, and the “-TargetLanguage” is the list we’re copying to. The “-TargetLanguage” value can be a list or a single string.

Get-Item -Path "master:/sitecore/content/Home/About Us" | 
    Add-ItemLanguage -Language "en-US" -TargetLanguage @("en-CA","fr-CA","de-DE") -IfExist Skip

Add Item Language – Child Items

Same as above, but this time we’re creating new language versions for all child items of an item. Very helpful for bulk operations like setting up a new country/language.
NOTE: this does NOT copy the parent item, so if you’re doing bulk operations, don’t forget the parent!

Get-ChildItem "master:/sitecore/content/Home/About Us" -Recurse | 
    Add-ItemLanguage -Language "en-US" -TargetLanguage @("en-CA","fr-CA","de-DE") -IfExist Skip

Updating Fields

Like language fallbacks, we don’t use shared fields all that much either – there are always exceptions for a handful of countries that make shared fields an impossibility. So often we need to update field values across multiple language versions. Here are some useful update scripts:

Set String/Text Value

Updates a single text value.
Another syntax note: as in most programming languages, there are many ways to write a particular script. The “foreach” loop makes the most sense to my C# brain, so that is the syntax I use most often. If you want to experiment with other ways, go for it.

# get all child "Product Item" templates, all languages
$itemList = Get-ChildItem -Path "master:/sitecore/content/Home/Products" -Language * -Recurse | 
    Where-Object { $_.TemplateName -eq "Product Item" }
    
foreach ($item in $itemList)
{
    # check to make sure we need to update the field
    if ($item."Product Type" -ne "widget")
    {
        $item.Editing.BeginEdit()
        $item."Product Type" = "widget"
        $item.Editing.EndEdit()
    }
}

Set Boolean Value

Updates a single boolean/checkbox value.

# get single item, all languages
$items = Get-Item -Path "master:/sitecore/content/Home/Products" -Language *
foreach ($item in $items)
{
    # set Right Align Text to true/checked
    $item."Right Align Text" = [int]1
    # set Full Screen to false/unchecked
    $item."Full Screen" = [int]0
}

Set Workflow Values

Updates workflow fields for a specific media item

# get the Sitecore IDs for the workflow and the approved status
$workflow = "{1B497ED4-6132-4BDF-8AB8-07890AF0DF8A}"
$approved = "{5E50B26D-6344-4167-9CFD-9C7898458EE3}"

# get all child items, ignoring media folders
$items = Get-ChildItem -Path "master:/media library/widget images" -Language * -Recurse | 
    Where-Object { $_.TemplateName -ne "Media folder" }
$items.Editing.BeginEdit()
foreach ($item in $items)
{
    # set all workflow fields as needed
    $item.__Workflow = $workflow
    $item."__Workflow state" = $approved
    $item.__Lock = ""
    $item."__Default workflow" = $workflow
}
$items.Editing.EndEdit()

So that’s it for Part 1. There are lots more to come, so stay tuned.

Building a JQuery Retinal Scanner

I have been having tons of fun working on the viral site for Erin Kellison’s Segue Institute. We’ve added lots of cool content to the site, and have plans to keep it going (and growing) for quite a while.

Maybe my favorite section of the site is the retinal scanner. It’s the second page you come to when you visit the site (the initial page is a login page). The Segue Institute is supposed to be a very high-tech facility, and the site experience is meant to be that of a Segue employee logging in to their secure website to poke around.

Probably one of the big reasons I like the scanner page so much is because it wasn’t planned. I was working on the main site navigation in the internal pages, and it was giving me fits. I was having a rough time trying to come up with something that was clean and clear to the user, but also fit with the high-tech theme. In a moment of frustration I decided to take a little break, and started brainstorming about various high-tech devices or designs that could work on the site. And immediately I knew we needed a retinal scanner. I started on it that very second, and after a few hours I had it. Gotta love inspiration.

So, on to the good stuff. The scanner is really quite simple. It consists of two images: (1) the scanner background with the sight lines and green radial gradient, and (2) the laser. I went with green because, well, it looked cool. The scanner background is nothing special, just some lines and a gradient on a transparent background. The laser is just a line of green to which I applied some filters for the blurs on the ends. I also added some noise to give it that fluttery sort of look that lasers get when they pass over objects.

The final pieces of the puzzle were two small text paragraphs: one static, with a simple message (“Please hold still”, heh heh) and one hidden, for display when the scanner is finished.

The HTML is again pretty simple. We have a “content” div wrapper, a div for the static message, a div for the hidden message (“auth”), and a div for the scanner (“scanPanel”).  NOTE: line breaks below are for display purposes only. AND ANOTHER THING: both “scanPanel” and “imgLaser” are positioned absolutely so that all the animations start and stop in the right place.

<div id="content">
  <div id="scanPanel" class="contentDiv">
    <img id="imgScanOverlay" src="img/scanbed.png" style="display: none;"/>
    <img id="imgLaser" src="img/scan.png" style="display: none; 
        position: absolute; top: 82px; left: 50px;"/>
  </div>
  <div>
    RETINAL SCAN IN PROGRESS...PLEASE HOLD STILL
  </div>
  <div id="auth" style="display: none;">
    AUTHORIZATION SUCCEEDED...LOADING DASHBOARD
  </div>
</div>

The javascript is where the magic happens. It all starts with a call to loadPanel(), which simply fades in the scanner div. Then the callback method, showScanner(), kicks off a series of animations:

  1. the scanner background is faded in
  2. the laser image is faded in
  3. the laser image’s “top” CSS property is animated to 390px, over a 2.5 second duration. Notice that here we are using the jquery easing plugin to get the effect that the scanner is speeding up through the center, and slowing down at the bottom. There are a bunch of options available here…basically I just tried them and picked the one that felt right.
  4. The laser is animated again, this time back up to the top. Again the easing plugin does its thing.
  5. The laser image is faded out
  6. The callback from the fadeout locates the hidden message and fades it in
  7. Finally, the callback from the fade in does a redirect to the main site. Whew!
NOTE: you could reduce all the nesting below by setting up individual functions for each of the callbacks, however I kind of prefer it this way, it’s easier to visualize what’s going on. Plus, once you minify it, who cares about nesting anyway?
$(document).ready(function () {
  loadPanel($("#scanPanel"))
});

loadPanel = function (panel) {
  panel.fadeIn(500, showScanner)
};

showScanner = function () {
  $("#imgScanOverlay").stop().fadeIn(1800, function () {
    $("#imgLaser").fadeIn(500, function () {
      $(this).animate({ top: "390px" }, 2500, "easeInOutQuint", function () {
        $(this).animate({ top: "82px" }, 2500, "easeInOutQuint", function () {
          $(this).fadeOut(1000, function () {
            $("#auth").fadeIn(1000, function () {
              redirect()
            })
          })
        })
      })
    })
  })
};

redirect = function () {
  setTimeout("window.location = 'dashboard.html';", 2000)
};

So that’s pretty much it. The one thing that I wish I could do with this is make the scanner appear more 3-D when it is animated. Perhaps by animating the width or thickness of the “laser” through its path. Sounds like a fun project for another day.

See the full effect at the SegueInstitute website.

Enjoy!