Powershell script to work on matching item names from external source

Many times there are scenarios when we are given with a excel file or csv from external source which has item names but not the item’s Sitecore IDs. Like we are given a excel with product names and other features which came from SAP resource.

Here the main challenge is to find the Sitecore item under a bucket folder which contains almost 8k items and then apply the logic(update or deletion) using a Powershell script. Getting the item based on item name will be slow and costly operation and the script will be too slow in making the updates. As the data is provided by external source so we don’t have the Item Ids which is the fastest way to find a item in Sitecore.

There are two ways to address this issue.

First way is manual way which requires some excel expertise of Vlookup.

First output a csv with item names and its id by using Powershell as below.

$allItems = Get-ChildItem “master:/sitecore/content/Products” -recurse | where-object {$_.TemplateID -eq “{B0707AC2-64D8-4CA1-AED4-3A1250208295}”}

foreach($itm in $allItems){write-host $itm.Name “;” $itm.ID}

Do a vlookup with the same column values. Here Item name and Product SKU (from SAP) has same column values and we can associate the Item IDs by vlookup from two excels files (one created from Sitecore and other one from external source).

VLOOKUP to populate associate Sitecore Item IDs

Once you have Ids you can quickly get the item in Powershell and do any kind of update operation on it.

Second way is fully automated way which I recently used to handle this scenario.

First create a hashtable of item names and its Ids and while reading the csv perform the key lookup which is the Product name(Item name in Sitecore) and get the ID. Again once you got the IDs you are free to do any manipulation at item level. It was quite fast and no manual intervention required. No excel expertise required.

foreach($itm in $allItems)
{
try{$hash.Add($itm.Name.ToLower(), $itm.ID) } catch { #Write-Host $itm.Name “;” $_.Exception.Message -BackgroundColor DarkRed }

}

foreach($row in $csv){

$key=$row.”ProducNameColumn”.Trim()

$ids = $hash[$key]

$sitecoreitm= Get-Item “master:” -ID $ids -ErrorAction SilentlyContinue

$sitecoreitm.Editing.BeginEdit()
$sitecoreitm.Fields[“Value”].Value = “some value”;
$sitecoreitm.Editing.EndEdit()

}

                          

Adding a Custom Tab to the Content Item in Sitecore Client.

We can create tabs in our Sitecore content items as shown above. A tab can be created for different reasons. One of the simple reasons is to direct business users how to use that content item like adding Datasources from a specific location in content tree or using specific template, applying rules on a field and so on. Lets see how we can create it.

First open Sitecore Core Database and create and item under path “/sitecore/content/Applications/Content Editor/Editors/Items“. The Item should be based on the “/sitecore/templates/Sitecore Client/Content editor/Editor” template. Here our created item name is “About Home”. The most important field is URL field in the created item which is “TabsController\Index”  and in controller code(TabsController) we have to apply attribute routing as shown below. Here Index.cshtml is view file associated with the action method.

[System.Web.Mvc.Route("sitecore/shell/Applications/TabsController/Index")]
public ActionResult Index()
        {
            return PartialView("~/Views/Tabs/Index.cshtml");
        }

To call this route from the Sitecore content Item we need to patch our Sitecore pipeline with below class.

public class CustomMVCRoutes
    {
        public void Process(PipelineArgs args)
        {
            RouteTable.Routes.MapMvcAttributeRoutes();
            Log.Info("Sitecore is starting........test", this);
        }
}

We need to add the patch file in our Include folder to invoke CustomMVCRoutes at particular execution step.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="MyCMSSoln.CustomMVCRoutes,MyCMSSoln" patch:before="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeControllerFactory, Sitecore.Mvc']" />
      </initialize>
    </pipelines>
  </sitecore>
</configuration>

At last go the item in master Database where you want to apply the tab and go in Appearance section Editors field and apply the newly created tab that is About Home(created in core database).

Once you compile and deploy the code and dll and view is updated, newly created About Home Tab will be shown in the content tree.

Adding users in Sitecore with specific roles using Powershell

we can use Sitecore Powershell to create users in Sitecore. This is how we can create a single user in sitecore.

$username=”contentbuser”
$userpwd=”content@123″
$roles=”Author,Developer”
$email=”test@test.com”

Write-host “Creating User: $($username)”
New-User -Identity $($username) -Enabled -Password $($userpwd) -Email $($email) -FullName “$($username)”

Lets add some roles to it.

$($roles).Split(“,”) | ForEach {
Write-host “Adding user to role: $_ “
Add-RoleMember -Identity $_ -Members “$($username)”
}

If you you want to make it as an administrator

Set-User $($username) -IsAdministrator $true

Here you can assign multiple roles to it too.

Create Bulk users in Sitecore

Now Imagine a scenario where you have to create number of users where you have a csv file with the necessary information mentioned above like username, password, email and roles to be assigned. you can use below script to automate creating number of users

Upload a csv file from your local to sitecore upload folder. This is very important to note because you might get permission issue error if you want to write at some other location. This will be helpful.

$dataFolder = [Sitecore.Configuration.Settings]::DataFolder
$tempFolder = $dataFolder + “\temp\upload”
$filePath = Receive-File -Path $tempFolder -overwrite

if($filePath -eq “cancel”){
exit
}

$Usersdata = Import-Csv -Path $filePath

foreach($user in $Usersdata) {
    Write-Verbose "Creating User: $($user.Username)"
   New-User -Identity $($user.Username) -Enabled -Password $($user.Password) -Email $($user.Email) -FullName "$($user.Name)"
    
    #Set-User $($user.Username) -IsAdministrator $true
    
   $($user.Roles).Split(",")  | ForEach {
     Write-Verbose "Adding user to role: $_ "
     Add-RoleMember -Identity $_ -Members "$($user.Username)"
   }
}

here Username, Password, Email and Roles are csv fields.

Adding Rendering to Item presentation using Powershell Scripting.

Scenario: Assume a new rendering is created and we need to assign this rendering to multiple items in the Sitecore content tree. while this can be done manually it will be time consuming and boring task for content authors. Again Powershell come to the rescue.

Get Item where rendring needs to be assigned.
$item=Get-Item -Path “master:” -ID “{3512740C-8965-4E40-A082-0F528A638111}”
Get rendering which needs to be assigned on the above item
$RenderingName = Get-Item -Path “master:” -ID {209B30A5-495C-4AF0-A670-8287E78107DE}
write-host “adding rendering…”
Add-Rendering -Item $Item -PlaceHolder “content123” -DataSource “” -Instance (New-Rendering -Item $RenderingName)
write-host “add rendering completed…”

Note: Here you can provide the Placeholder and Datasource too based on the requirement.

The same Process can be automated with multiple items and multiple renderings where you are reading the item IDs from a csv file and assigning the renderings in a foreach loop.

Calling Sitecore Controller rendering dynamically on the view(cshtml) file and passing rendering parameters

We can call the Controller renderings already created on a view file. In some scenarios we can not assign the rendering on the item (for ex wildcard scenarios where we need this rendering on specific item not all the items)

@Html.Sitecore().Rendering(itemid, new { DataSource = itmds.ID})

wher Datasource is

Item itmds = Sitecore.Context.Database.GetItem(“Path or Id or some Datasource field”);

    

Passing Rendering Parameters dynamically

Lets assume we are passing orientation and Background color with the Datasource where Orientation is passed as string.

Item itorient = Sitecore.Context.Database.GetItem( “Path or Id or some Datasource field” );
Item itbccolor = Sitecore.Context.Database.GetItem(” Path or Id or some Datasource field );

string Orient = string.Format(“Orientation={0}&Background Color={1}”, itorient.Name, itbccolor.ID);

Get All items based on specific template under bucket folder which got updated x days ago.

Scenario: Let assume that due to some wrong migration from external system lot of item fields got updated under Sitecore bucket folder. If we need to fix this kind of scenario we can use the Powershell scripting.

$allItems = Get-ChildItem “master:/sitecore/content/products” -recurse | where-object {$_.TemplateID -eq “{70E9D00C-2A10-41EE-BE6D-8441FD4C8C79}” -and $_.__Updated -gt [datetime]::Now.AddDays(-10) }

How to update one of the Fields.

foreach($item in $allItems){

write-host $item.ID “;” $item.Name
$item.Editing.BeginEdit()
$item.Fields[“FieldtoUpdate”].Value = “CorrectValue”
$item.Editing.EndEdit()

}

Basic Sitecore Powershell commands

Get Item based on item id

Get-Item -Path “master:” -ID “{0DE95AE4-41AB-4D01-9EB0-67441B7C2425}

Get item id based on path

Get-Item Path “master:/sitecore/content/Sites/Site Data/ACP Components/Sample Data”

Get item properties

Get-Item -Path “master:/sitecore/content/Sites/ Site Data/Components Data/sample data” | select Name, Id, __Updated,__Created

Get item based on template name

Get-Item -Path “master:” -Query “/sitecore/content/Sites/Site Data/Components//*[@@templatename=’Component Parmaters’]”

Get item or items based on template id

Get-Item -Path “master:” -Query “/sitecore/content/Sites/Site Data/ACP Components//*[@@templateid=’{A3AEC2DA-31A8-46F8-ADB3-07697886321A}‘]”

Show list view or download the output with required properties or fields directly on the Item

Here Product is Sitecore bucket folder and items are created by code automation and we are only interested in the items with specific template ID

$allItems = Get-ChildItem “master:/sitecore/content/Sitecore/SiteA/Product/2017” -recurse | where-object {$_.TemplateID -eq “{42B5CFEF-AB2D-4E1F-A8D0-7DCD6A3A9DEH}”}
$allItems | Show-ListView -Property Name, Id, __Updated,__Created

Basics of Templates Creation in Sitecore

In general, templates basically should be defined under below categories at least. Templates are the most basic thing which is defined at the initial stage in Sitecore.

In general, templates basically should be defined under below categories at least.

  • Base templates
  • Data templates
  • Rendering parameter templates
  • Site configuration or settings templates
  • Page templates

Base templates as the name signifies that it should consists of the fields which is likely to be the part of most of the templates. For example- Title, Image and description and link fields. These fields can be part of many templates so instead of duplicating the same fields in all templates create it as a base template and inherit it.

Data templates are basically the Entities in the system. As we define entities in our code same way you can create Data templates and its fields. For example Product template in a ecommerce application.

Rendering parameter templates should be defined in a different folder and with rendering name as prefix so that one can get information of all the renderings for which rendering parameters exist.

Site configuration templates should be created in order to configure settings for Site specific data which is common on all pages. For example: enabling or disabling Banner and popups on the Site pages.

Page templates are the templates which might be inheriting data templates. Basically, these are the templates which will contain presentation (means renderings, placeholder and layouts) and are created based on number of website unique pages. For example: Page template might inherit Data templates, meta data templates.

Get single Item or multiple items in Sitecore based on different scenarios.

Get Item by ID:

Everything is an Item in sitecore and every item has an ID and Path.

If the return type of any method is Sitecore Item then we get all the properties and methods related to Item class.

Sitecore.Data.Database db = Sitecore.Configuration.Factory.GetDatabase(“master”);

string itmID={726C1CEB-46BC-483E-AAB4-44205C60773D}”);//Id of a sitecore Item
Item itmbyID=databas.GetItem(itmID);

Get Item by Path:

string itmPath=”/sitecore/content/home/ItemA”;

Item itmbyPath=databas.GetItem(itmPath);

Note: we should always try to get a item in sitecore by its Id not by its Path because path of any item can change by someone or accidentally(during Item move) but its item ID remains same.

Get Item using Sitecore query

Item item = Sitecore.Context.Database.SelectSingleItem("/sitecore/content/Site Data/Email Configuration");

Get Multiple Items using sitecore query

Item[] items = Sitecore.Context.Database.SelectItems("/sitecore/content/Site Data/Products//*[@@templateid='{B0707AB3-64C9-4CA1-AED4-3A1201208295}' ]");

Get multiple Items using Sitecore Fast query

Item[] items = Sitecore.Context.Database.SelectItems("fast://sitecore/content/Site Data/Products//*[@@templateid='{B0707AB3-64C9-4CA1-AED4-3A1201208295}']");

 Get all the descendants of the item using Sitecore API

Item item = Factory.GetDatabase(“web”).GetItem(“/sitecore/content/Site Data/Products”);
Item[] items=item.Axes.GetDescendants()

This method calls item.Children, and then for each child again child.Children recursively. And it adds all those items to an array.

There is another method which takes query as input as mentioned below:

item.Axes.Selectitems(string query) 

This method executes Sitecore query passed in the argument in the context of the current item

Get Descendents always fetch the child items recursively. It should be used carefully as it has huge performance hit if child items are large in size

Difference in UserSwitcher and SecurityDisabler

When we decide to create,update or delete items in sitecore programmatically we need to run our code in either Securitydisabler context or UserSwitcher context.

when we want to run the code in context of another user we should use Sitecore.Security.Accounts.UserSwitcher class for example there are scenarios in which only user A is allowed to create,update or delete items under a particular node in the tree and you want the code to fail if someone else tries to do the changes.

string userA = @”sitecore\userA”;
Sitecore.Security.Accounts.User sitecorecuser =Sitecore.Security.Accounts.User.FromName(userA, false);
using (new Sitecore.Security.Accounts.UserSwitcher(sitecorecuser))
{
//your code goes here
}

when we want to run the code without any security restrictions then we should use Sitecore.SecurityModel.SecurityDisabler class. Basically SecurityDisabler elevates the users permission (temporarily) to admin rights and so context user will be able to perform anything in sitecore. Any changes done with the SecurityDisabler will show up as being done by the sitecore\Anonymous role.

using (new Sitecore.SecurityModel.SecurityDisabler())
{
  //your goes code here
}