Establishing a Basic Security and Workflow Configuration
Setting up content security and workflows in Sitecore can often feel daunting, especially when starting from scratch. While Sitecore offers granular control and flexibility, most websites only need a basic setup to get started. This post provides a PowerShell script that establishes a foundational configuration for security, workflows, and roles, covering the essentials for most scenarios.
In XM Cloud, configuring workflows is particularly crucial because publishing often includes additional items resolved through references. Without workflows, draft content may be unintentionally published, leading to incomplete or inaccurate updates. A workflow is the only reliable way to ensure that only approved content is published.
Roles: Organizing Roles for Effective Access Management
To simplify role management, we organize our roles into four distinct categories: Content, Language, Workflow, and Miscellaneous.
Content
Roles to control the access to parts in the content tree. It can be an entire site, or a section of a site.
Eg. “sitecore\Content SiteA”, “sitecore\Content News”
Language
On multi-language websites, you can define what language an author can edit. Normally, all authors edit all languages.
Eg. “sitecore\Language en_CA”, “sitecore\Language All”
Workflow
Roles to control the approval process of a page.
Eg. “sitecore\Workflow Approver”, “sitecore\Workflow Editor”
Miscellaneous
Any other role that doesn’t fall in any of the three previous categories.
Eg. “sitecore\Basic Access”, “sitecore\Can Unlock Others Items”
Users: Assigning Roles to Users by Type
Users will always be members of at least one Content, Workflow, and one Language role. This approach allows composition of roles to define what different authors can do.
Examples:
sitecore\Mario
- sitecore\Content SiteA
- sitecore\Language All
- sitecore\Workflow Editor
sitecore\Ana
- sitecore\Content SiteA
- sitecore\Language All
- sitecore\Workflow Approver
“sitecore\Basic Access” is set into the “sitecore\Workflow” roles for convenience.
Creating a user based on all the three roles type
Workflow: Basic Three States Setup
The PowerShell script below creates a copy of the out of box “Sample Workflow”. The sample workflow offers a simple three step process that is applicable for most organizations.
The name of the copy can be configured in the script, review all variables on the top before running it.
Templates: Define Default Workflow in Standard Values
After executing the script, the last step is to add templates in workflow. The field “Default Workflow” needs to be set in the standard values of all pages and components.
The script will not perform this action. You can create a script on your own targeting the correct items or assign manually.
Script: Setting Up All in a Single Run
Replace the variables and execute the script. This script can be executed multiple times safely.
#Variables
#************
$WebsitePath = "/sitecore/content/TENANT_NAME/SITE_NAME"
$WebsiteMediaLibraryPath = "/sitecore/media library/Project/TENANT_NAME/SITE_NAME"
$contentLanguagesList = @("en-CA", "fr-CA") #The languages defined here need to be already added in Sitecore.
$newWorkflowName = "Custom Workflow"
#************
#Test Variables
$path = "master:" + $WebsitePath
$test = Get-Item -Path $path -ErrorAction Ignore
if ($test -eq $null) {
Write-Host "ERROR -- $WebsitePath does not exists"
exit
}
$path = "master:" + $WebsiteMediaLibraryPath
$test = Get-Item -Path $path -ErrorAction Ignore
if ($test -eq $null) {
Write-Host "ERROR -- $WebsiteMediaLibraryPath does not exists"
exit
}
###Creating Roles
Write-Host "Creating Roles"
New-Role -Identity "Basic Access" -ErrorAction Ignore
New-Role -Identity "Workflow Editor" -ErrorAction Ignore
New-Role -Identity "Workflow Approver" -ErrorAction Ignore
New-Role -Identity "Content Main Site" -ErrorAction Ignore
New-Role -Identity "Language All" -ErrorAction Ignore
foreach ($lang in $contentLanguagesList) {
$roleName = "Language " + $lang.Replace("-", "_")
New-Role -Identity $roleName -ErrorAction Ignore
}
###Defining roles relationships
Write-Host "Defining roles relationships"
Add-RoleMember -Identity "Sitecore Client Maintaining" -Members "Basic Access"
Add-RoleMember -Identity "Designer" -Members "Basic Access"
Add-RoleMember -Identity "Sitecore Client Translating" -Members "Basic Access"
Add-RoleMember -Identity "Author" -Members "Basic Access"
Add-RoleMember -Identity "SXA\Author" -Members "Basic Access"
Add-RoleMember -Identity "Basic Access" -Members "Workflow Editor"
Add-RoleMember -Identity "Basic Access" -Members "Workflow Approver"
foreach ($lang in $contentLanguagesList) {
$roleName = "Language " + $lang.Replace("-", "_")
Add-RoleMember -Identity $roleName -Members "Language All"
}
###Setting security to language items
Write-Host "Setting security to language items"
foreach ($lang in $contentLanguagesList) {
$path = "master:/sitecore/system/Languages/" + $lang
$item = Get-Item $path -ErrorAction Ignore
if ($item -eq $null){
Write-Host "Create the language items in Sitecore and run the script again"
Write-Host "Exiting script"
exit
} else {
$securityValue = "ar|sitecore\Language " + $lang.Replace("-", "_") + "|pd|+language:write|+language:read|pe|+language:write|+language:read|ar|Everyone|pd|+item:read|!|pe|+item:read|!|"
$item.Editing.BeginEdit()
$item["__Security"] = $securityValue
$item.Editing.EndEdit()
}
}
###Creating Custom Workflow
Write-Host "Creating Custom Workflow"
$sourcePath = "master:/sitecore/system/Workflows/Sample Workflow"
$newWorkflow = "master:/sitecore/system/Workflows/" + $newWorkflowName
$sourceItem = Get-Item -Path $sourcePath -ErrorAction Ignore
$targetItem = Get-Item -Path $newWorkflow -ErrorAction Ignore
if ($sourceItem -ne $null -AND $targetItem -eq $null) {
Copy-Item -Path $sourcePath -Destination $newWorkflow -Recurse
}
###Create Action to Approve Datasources Along Pages
Write-Host "Create Action to Approve Datasources Along Pages"
$path = $newWorkflow + "/Awaiting Approval/Approve/Datasource Workflow Action"
$test = Get-Item -Path $path -ErrorAction Ignore
if ($test -eq $null) {
$path = $newWorkflow + "/Approved"
$approveStateItem = Get-Item $path
<span class="hljs-variable">$path</span> = <span class="hljs-variable">$newWorkflow</span> + <span class="hljs-string">"/Awaiting Approval/Approve"</span>
<span class="hljs-variable">$action</span> = <span class="hljs-built_in">New-Item</span> -Path <span class="hljs-variable">$path</span> -Name <span class="hljs-string">"Datasource Workflow Action"</span> -ItemType <span class="hljs-string">"{DEF0AA0D-3446-41AE-B307-EC7BA429CE50}"</span>
<span class="hljs-variable">$action</span>.Editing.BeginEdit()
<span class="hljs-variable">$action</span>[<span class="hljs-string">"Command item"</span>] = <span class="hljs-variable">$approveStateItem</span>.ID
<span class="hljs-variable">$action</span>.Editing.EndEdit()
}
###Defining access rights for content
Write-Host "Defining access rights for content"
$itemAndDescendantsAccess = "ar|sitecore\Content Main Site|pd|+item:delete|+item:write|+item:read|^|+item:rename|+item:create|pe|+item:write|+item:read|^|+item:create|ar|Everyone|pd|+item:read|!|pe|+item:read|!|"
$descendantsAccess = "ar|sitecore\Content Main Site|pd|+item:delete|+item:write|+item:read|+item:rename|+item:create|pe|+item:read|+item:create|ar|Everyone|pd|+item:read|!|pe|+item:read|!|"
###Setting Access Rights to Items
Write-Host "Setting Access Rights to Items"
#home page
$path = "master:" + $WebsitePath + "/Home"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = $itemAndDescendantsAccess
$item.Editing.EndEdit()
#data folder
$path = "master:" + $WebsitePath + "/Data"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = $descendantsAccess
$item.Editing.EndEdit()
#partial designs
$path = "master:" + $WebsitePath + "/Presentation/Partial Designs"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = $descendantsAccess
$item.Editing.EndEdit()
#partial designs placeholders
$path = "master:" + $WebsitePath + "/Presentation/Placeholder Settings/Partial Design"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = $descendantsAccess
$item.Editing.EndEdit()
#site media library folder
$path = "master:" + $WebsiteMediaLibraryPath
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = $descendantsAccess
$item.Editing.EndEdit()
###Setting Access Rights in Workflow
Write-Host "Setting Access Rights in Workflow"
$path = $newWorkflow + "/Draft"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = "ar|sitecore\Workflow Approver|pe|+workflowState:delete|+workflowState:write|+workflowCommand:execute|pd|+workflowCommand:execute|+workflowState:write|+workflowState:delete|ar|sitecore\Workflow Editor|pe|+workflowState:delete|+workflowState:write|+workflowCommand:execute|pd|+workflowState:delete|+workflowState:write|+workflowCommand:execute|"
$item.Editing.EndEdit()
$path = $newWorkflow + "/Draft/Submit"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = "ar|Everyone|pe|!|pd|!|ar|sitecore\Workflow Approver|pe|+workflowCommand:execute|+item:read|^|pd|+workflowCommand:execute|+item:read|^|ar|sitecore\Workflow Editor|pe|+workflowCommand:execute|+item:read|^|pd|+workflowCommand:execute|+item:read|^|"
$item.Editing.EndEdit()
$path = $newWorkflow + "/Awaiting Approval"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = "ar|sitecore\Workflow Approver|pe|+workflowCommand:execute|+workflowState:write|+workflowState:delete|pd|+workflowState:delete|+workflowCommand:execute|+workflowState:write|"
$item.Editing.EndEdit()
$path = $newWorkflow + "/Approved"
$item = Get-Item -Path $path
$item.Editing.BeginEdit()
$item["__Security"] = "ar|sitecore\Workflow Approver|pe|+workflowCommand:execute|+workflowState:write|+workflowState:delete|pd|+workflowCommand:execute|+workflowState:write|+workflowState:delete|ar|sitecore\Workflow Editor|pe|+workflowState:delete|+workflowCommand:execute|+workflowState:write|pd|+workflowCommand:execute|+workflowState:write|+workflowState:delete|"
$item.Editing.EndEdit()
### Fix issue in Sitecore allowing Data folder creation
#/sitecore/system/Settings/Foundation/Experience Accelerator/Local Datasources/Virtual Page Data/__Standard Values
$dataFolder = Get-Item -Path "master:" -ID "{9700DC24-8969-4638-ACC3-34D54335829E}"
$ar = "ar|sitecore\Basic Access|pe|+item:create|"
if ($dataFolder["__Security"].IndexOf($ar) -eq -1) {
$dataFolder.Editing.BeginEdit()
$dataFolder["__Security"] = $dataFolder["__Security"] + $ar
$dataFolder.Editing.EndEdit()
}
### Message to assign Default Workflow.
$path = "master:/sitecore/system/Workflows/" + $newWorkflowName
$wfItem = Get-Item -Path $path
Write-Host "-------------------------------------------"
Write-Host "To finish setting up, assign the '$newWorkflowName' to all your pages and all components." -ForegroundColor Green
Write-Host "Assign in Standard values, field 'Default Workflow' - $newWorkflowName ID: " $wfItem.ID -ForegroundColor Green
Write-Host "-------------------------------------------"