Update a custom Permission Level using CSOM

Today I was busy with a lot of SharePoint 2013 C# CSOM code, and PowerShell and one of the things I had to do was to update an existing permission level. I only had data on the permission kinds that this update should contain, so I needed to figure out a way to update the permission level without removing and recreating a new one with the same name. Removing and recreating the level could lead to a lot of trouble.

So that was the most frustrating part of my day, because initially it didn't seem possible. But I didn't want to give up the fight just yet, and started messing about, and gradually saw things I could work with. At the end I finally got there. So tonight I worked out an example using PowerShell with CSOM to show you how this can be done.

One note, I think that when changing Permission Levels, you are probably best off not changing the default SharePoint permission levels. Instead you would be better off creating your own copy, and to edit and use that copy. You then still have the default permission levels as a reference in your site. This is what I do in the PowerShell sample.

To update the PermissionKinds in the Permission level, you basicly have to follow 3 steps in the following order (the order is very important):

  • Create a new BasePermissions object, and add the PermissionKinds you like to this BasePermissions
  • Set the BasePermissions of your Permission Level/RoleDefinition to the object created above
  • Update the Permission Level/RoleDefinition

Below a working sample of creating and changing a Permission Level in PowerShell with CSOM:


# the path below depends on the location of the Client assembly on your system 
# the 15 root is for on premise, the 16 root for Office 365, I use on premise here
$path = "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\ISAPI"
Add-Type -Path "$path\Microsoft.SharePoint.Client.dll"
Add-Type -Path "$path\Microsoft.SharePoint.Client.Runtime.dll"


# your dev/demo environment site collection url
$url = "http://demo.dev.local/" 

#-------------------------
# Functions
#-------------------------

function CopyBasePermissionLevel([Microsoft.SharePoint.Client.BasePermissions] $source)
{
    $copy = New-Object Microsoft.SharePoint.Client.BasePermissions
    foreach($permission in [Enum]::GetValues([Microsoft.SharePoint.Client.PermissionKind]))
    {
        if ($source.Has($permission))
        {
            $copy.Set($permission)
        }
    }
    return $copy
}

#-------------------------
# Code
#-------------------------

$context = New-Object Microsoft.SharePoint.Client.ClientContext($url)
try 
{

    $rootWeb = $context.Site.RootWeb
    $context.Load($rootWeb)
    $context.Load($rootWeb.RoleDefinitions)
    $context.ExecuteQuery()

    $roleDefinitions = $rootWeb.RoleDefinitions

    $custom = $roleDefinitions | Where-Object { $_.Name -eq "ReadAndMore" } 

    if ($custom -eq $null)
    {
        # add custom permission level
        # english or dutch language
        $read = $roleDefinitions | Where-Object { $_.Name -eq "Read" -or $_.Name -eq "Lezen" } 

        $newPermissionLevel = New-Object Microsoft.SharePoint.Client.RoleDefinitionCreationInformation
        $newBasePermission = CopyBasePermissionLevel $read.BasePermissions
        $newBasePermission.Set([Microsoft.SharePoint.Client.PermissionKind]::AddListItems)
        $newBasePermission.Set([Microsoft.SharePoint.Client.PermissionKind]::EditListItems)

        $newPermissionLevel.Name = "ReadAndMore"
        $newPermissionLevel.Description = "Read with add and update item"
        $newPermissionLevel.BasePermissions = $newBasePermission   
        $custom = $rootWeb.RoleDefinitions.Add($newPermissionLevel)

        $context.ExecuteQuery()
    }

   
    Write-Host "Please check the Permission level:"
    Write-Host "Site settings => Site permissions => Permission Levels (Ribbon)"
    Read-Host "Press enter to continue..."


    Write-Host "Updating permission level..."

    # 1st get a new base permission with the permissions you want, I copy the old ones and add some more
    $updatedBasePermission = CopyBasePermissionLevel $custom.BasePermissions
    $updatedBasePermission.Set([Microsoft.SharePoint.Client.PermissionKind]::DeleteListItems)
    $updatedBasePermission.Set([Microsoft.SharePoint.Client.PermissionKind]::DeleteVersions)

    # 2nd set the newly created base permissions object on the BasePermissions of your RoleDefinition object
    $custom.BasePermissions = $updatedBasePermission
    $custom.Description = "Read with add, update and delete item"

    # 3rd update your RoleDefinition
    $custom.Update()
    $context.ExecuteQuery()
}
finally 
{
    if ($context -ne $null) {
        $context.Dispose()
    }
}

Write-Host "Updated permission level..."
Write-Host "Please check the Permission level:"
Write-Host "Site settings => Site permissions => Permission Levels (Ribbon)"
Read-Host "Press enter to finish..."

If you put this in a .ps1 file and execute this, you will get prompted to check the newly created permission level. Please check and see the permissions in this permission level. See screenshot below (Dutch language):

Permission level screenshot after creation

Then press enter to continue, you will be asked again to check the permission level, you will now see you also have delete permissions, the Dutch word 'verwijderen' means (to) remove/delete:

Permission level screenshot after update

For more info on working with permission levels see:
Office 365 - Create Permissions Level and Groups using CSOM

Isn't that cool, you also learned some Dutch today ;-)