I have created some custom Roles under the "sitecore" domain, but now I want to migrate all the custom roles to another domain e.g. fancy_domain\Cool_Role. How to do it?
3 Answers
I see a few different things need to get this completed.
- Reporting: Report on all the items with a role explicitly defined. Simple approach is to find all items referencing a given domain. I wrote a report here that can help.
- Bulk Changing: Map the old role to the new role and update the security on each item. The report could either be updated to have actions to do this or write a separate script.
Reporting
Using the gist provided, you can view a report like the following:
Bulk Changing
Using the security commands provided by SPE, you can reassign the security for each item.
Example: The following lists all of the security settings applied to the item.
$item = Get-Item -Path "master:{11111111-1111-1111-1111-111111111111}"
Get-ItemAcl -Item $item
<#
Account AccessRight PermissionType PropagationType SecurityPermission
------- ----------- -------------- --------------- ------------------
Everyone item:read Access Entity AllowAccess
Everyone item:read Access Descendants AllowAccess
sitecore\Everyone item:read Access Entity AllowAccess
sitecore\Everyone item:read Access Descendants AllowAccess
#>
Check out these commands:
- Add-ItemAcl
- Get-ItemAcl
- Set-ItemAcl
- Test-ItemAcl
Turns out the script was less complex than I initially anticipated.
Example: The following updates security to items provided you have mapped the old role to a new role.
<#
.SYNOPSIS
Find all items referencing the specified domain and replace with a new domain.
.NOTES
Michael West
#>
Import-Function -Name Invoke-SqlCommand
# You'll want to update the domains and role mapping.
$oldDomain = "demo"
$newDomain = "powerful"
$roleMapping = @{
"demo\Broken Role" = "powerful\Ways Role"
}
$connection = [Sitecore.Configuration.Settings]::GetConnectionString("master")
$securityFieldId = [Sitecore.FieldIDs]::Security
# Find all the items which explicitly have security assigned.
$query = @"
SELECT [ItemId], [Value]
FROM [dbo].[SharedFields]
WHERE [FieldId] = '$($securityFieldId.ToString())'
AND [Value] <> ''
"@
$records = Invoke-SqlCommand -Connection $connection -Query $query
$matchingRecords = $records | Where-Object { $_.Value -match $oldDomain } |
ForEach-Object { Get-Item -Path "master:" -ID "$($_.ItemId.ToString())" }
foreach($matchingRecord in $matchingRecords) {
$oldacls = Get-ItemAcl -Item $matchingRecord
$newacls = @()
foreach($oldacl in $oldacls) {
$newacl = New-ItemAcl -AccessRight $oldacl.AccessRight -PropagationType $oldacl.PropagationType -SecurityPermission $oldacl.SecurityPermission -Identity ($roleMapping[$oldacl.Account.Name])
$newacls += $newacl
}
$matchingRecord | Set-ItemAcl -AccessRules $newacls
}
Note: Messages added to output for screenshot.
As far as I know this is not supported by ASP .NET membership provider. But here is a similar question: https://stackoverflow.com/questions/281891/how-do-you-rename-a-role-using-membership-in-net
public void RenameRoleAndUsers(string oldRoleName, string newRoleName)
{
string[] users = Roles.GetUsersInRole(oldRoleName);
Roles.CreateRole(newRoleName);
Roles.AddUsersToRole(users, newRoleName);
Roles.RemoveUsersFromRole(users, oldRoleName);
Roles.DeleteRole(oldRoleName);
}
The code snippet above only changes the roles of the users. You need an extra step to assign the new role for the items where the old role was used. Here is an example method which can work for 1 item (I did not try it but it is compilable):
public void ChangeItemRole(Item item, string newRole, string oldRole)
{
var oldAccessRules = item.Security.GetAccessRules();
var newAccessRules = new AccessRuleCollection();
foreach (var oldAccessRule in oldAccessRules)
{
if (oldAccessRule.Account.Name == oldRole)
{
newAccessRules.Add(
AccessRule.Create(
Role.FromName(newRole),
oldAccessRule.AccessRight,
oldAccessRule.PropagationType,
oldAccessRule.SecurityPermission));
}
else
{
newAccessRules.Add(oldAccessRule);
}
}
item.Security.SetAccessRules(newAccessRules);
}
Maybe this script also can be useful. This script copies all access rights from one identity to another indentity for selected item. So you can easy move all access rights for all items.
Copy-ItemAcl -FromIdentity 'SUPER\ROBSONAUTOMATOR' -ToIdentity 'LAZY\ONE' -Path "/sitecore/content/Home"
The full code is available on gist