I'm writing an SPE script and am looping over my site nodes. For each site node, I want to check if a particular descendant exists and if not then create it. I have the list of top-level nodes, but cannot figure out how to query each of those nodes for a descendant.

If I was writing in regular query syntax, I could write something like this:

var sites = database.SelectItems("fast:/sitecore/content/Master/*[@@templatename='Website']");
foreach (var site in sites)
    var settingsItem = site.Axes.SelectItem("descendant::*[@@templatename='Settings']");
    //now check if SettingsItem is null, if so create etc

What I have in my SPE script:

#get the list of top-level site nodes
$sites = Get-Item master: -Query "fast:/sitecore/content/Master//*[@@templatename='Website']";
foreach ($site in $sites)
    # get descendant of each $site item that inherits from "Settings" template 
    $settings = ???
    if ($settings == null) {
        #create settings item etc...

3 Answers 3


In your code, $site will be of the type Sitecore.Data.Items.BaseItem, so it has all the standard API available.

You can achieve the desired behavior like this:

$settings =
    $site.Axes.GetDescendants() |
        ? { $_.TemplateName -eq "Settings" } |
        select -first 1

if($settings -eq $null) {
    # create settings etc

If performance is important for you, you can use Fast Query:

$query = "fast:" + $site.Paths.Path + "//*[@@templateid='{your-template-id-here}']"

$settings = Get-Item master: -Query $query | select -first 1

Note that I used the ID of the template instead of its name. This reduces the need for SQL joins and makes the query much faster.

  • Cool, I didn't know about calling methods like that. $site.Axes.GetDescendants() will be a bit of a killer though won't it.. Presume I could also do $site.Axes.SelectSingleItem() right? Commented Nov 24, 2016 at 21:58
  • 1
    @MatthewDresser Your original SelectSingleItem query will perform exactly the same as GetDescendants. See my updated answer for a faster solution. Commented Nov 25, 2016 at 6:16
  • ah ok, thanks for that, I didn't know about that. Thanks for the updated solution. Out of interest, if the site item (or one of its ancestors) was named with a space or underscore or hyphen, would that query still work, or would I need to escape it manually? Commented Nov 25, 2016 at 9:17
  • 1
    @MatthewDresser It would work even with whitespaces, underscores and hyphens, yes. Commented Nov 25, 2016 at 9:26

Try this snippet.

# get descendant of each $site item that inherits from "Settings" template 
# $site = gi .
$settingsBase = "{6669DC16-F106-44B5-96BE-7A31AE82B5B5}"
$settingItems= Get-ChildItem -Path $site.Paths.Path | Where-Object { 

$settingsBase is a base settings template ID or base settings template Name.

Be careful. If you have multiple settings it will return an array, so select single (first element) you can use $settingItems | select -First 1

  • I just need to find descendants of the site item based on my "Settings" template. Commented Nov 24, 2016 at 22:02
  • Isn't my code doing that? (removed -Recurse switch) Commented Nov 24, 2016 at 22:08
  • Apologies, my question was badly worded, it should have said "...of an item using a template" Commented Nov 24, 2016 at 22:15
  • No worries. I am glad you've got a solution for your problem. Commented Nov 24, 2016 at 22:19

Dmytro Shevchenko's answer did what was needed, but the Axes.GetDescendants() call will, as the name suggests, retrieve all items which is a pretty expensive operation. The code below seems to work ok:

$settings = $site.Axes.SelectSingleItem("descendant::*[@@templatename='Settings']")
  • It doesn't meet that criteria: "get a descendant of an item inheriting from a template", which is important if your solution must work on instances where somebody wants to override Settings template. Commented Nov 24, 2016 at 22:13
  • 1
    Please note that, since your query is not a Fast Query, this solution will be equivalent to .GetDescendants(), i.e. it will iterate through each item's children recursively. If you really need good performance, you can try converting your query to a Fast Query. Keep in mind that descendant:: won't work with Fast Query unless you change the value of the FastQueryDescendantsDisabled setting to true in the Sitecore.config. Commented Nov 25, 2016 at 5:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.