Question

like it said in the title, I would like to add custom permissions on folders and subfolder in a document library on SharePoint online using PowerShell? I've tried this code but only works for the 1st level folder, not for subfolders.

Can anyone help me?

<#
The sample scripts are not supported under any Microsoft standard support 
program or service. The sample scripts are provided AS IS without warranty  
of any kind. Microsoft further disclaims all implied warranties including,  
without limitation, any implied warranties of merchantability or of fitness for 
a particular purpose. The entire risk arising out of the use or performance of  
the sample scripts and documentation remains with you. In no event shall 
Microsoft, its authors, or anyone else involved in the creation, production, or 
delivery of the scripts be liable for any damages whatsoever (including, 
without limitation, damages for loss of business profits, business interruption, 
loss of business information or other pecuniary loss) arising out of the use 
of or inability to use the sample scripts or documentation, even if Microsoft 
has been advised of the possibility of such damages.
#>


#requries -Version 2.0

<#
    .SYNOPSIS
        This script will Set Folder Permission in a library of SharePoint Online.
    .DESCRIPTION
        This script could be used to set a folder which could be only accessed by a security group. And this folder must have the same name of the security group. Otherwise, the script will create a new folder
    .PARAMETER  userName
        This parameter specified the username to login into SharePoint Online
    .PARAMETER  Password
        This parameter specifies the password to login into SharePoint Online 
    .PARAMETER  siteURL
        This parameter specifies the URL of the SharePoint site
    .PARAMETER  ListName
        This parameter specifies library/list name of the site
    .PARAMETER  FolderName
        This parameter specifies the parenet folder name/url. 
    .PARAMETER  PrincipalName
        This parameter specifies the security group or user who will be assigned the permission
    .PARAMETER  RoleType
        This parameter specifies the permission level to be assigned             
    .EXAMPLE
    SPOSetFolderPermissioninLibrary.ps1 –userName admin@tenant.onmicrosoft.com –siteURL https://tenant.sharepoint.com/sites/wroking -PrincipalName SecuirtyA -Roletype Editor
    The folder SecurityA in library ‘Demofile’ of site https://tenant.sharepoint.com/sites/working can only be edited by security group “SecuirtyA”
#>


Param
(
    [Parameter(Mandatory=$true)]
    [string] $userName,
    [Parameter(Mandatory=$True)]
    [Security.SecureString]$Password,
    [Parameter(Mandatory=$true)]
    [string] $siteURL,
    [Parameter(Mandatory=$true)]
    [string] $ListName,
    [Parameter(Mandatory=$false)]
    [string] $FolderName,
    [Parameter(Mandatory=$true)]
    [string] $PrincipalName,
    [Parameter(Mandatory=$true)][ValidateSet('None','Guest','Reader','Contributor','WebDesigner','Administrator','Editor')]
    [string] $RoleType


)

Begin
{
    $SPClientDirRegKey = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SharePoint Client Components\15.0" -PSProperty "Location" -ErrorAction:SilentlyContinue
    if ($SPClientDirRegKey -ne $null) 
    {
        $moduleFilePath1 = $SPClientDirRegKey.'Location' + 'ISAPI\Microsoft.SharePoint.Client.dll'
        $moduleFilePath2 = $SPClientDirRegKey.'Location' + 'ISAPI\Microsoft.SharePoint.Client.Runtime.dll'
        Import-Module $moduleFilePath1
        Import-Module $moduleFilePath2
    }
    else 
    {
        $errorMsg = "Please install SharePoint Server 2013 Client Components SDK"
        throw $errorMsg
        Exit
    }
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $Password)
    $context = New-Object Microsoft.SharePoint.Client.ClientContext($siteURL)
    $context.Credentials = $credentials
    $web = $context.Web
    $site = $context.Site
    $context.Load($web)
    $context.Load($site)
    try
    {
        $context.ExecuteQuery()
    }
    Catch
    {
        Write-Error $Error[0]
        Exit
    }
    Write-host "Conntect To Sharepoint Site $siteURL"
}

Process
{ 
    $web = $context.web
    $folderurl = $Web.ServerRelativeUrl + "/" + $ListName + "/" + $FolderName
    $folder = $web.GetFolderByServerRelativeUrl($folderurl)
    $context.Load($folder)

    $folderExist = $false

    try
    {
        $Context.ExecuteQuery();

        if ($folder.Path)
        {
            $folderExist = $true;
        }
    }
    catch { }

    if(!$folderExist)
    {
        $parentFolderUrl = $folderUrl.Replace('/' + $folderName,'')

        $newItemInfo = new-object Microsoft.SharePoint.Client.ListItemCreationInformation
        $newItemInfo.UnderlyingObjectType = [Microsoft.SharePoint.Client.FileSystemObjectType]::Folder
        $newItemInfo.LeafName = $folderName
        $newItemInfo.FolderUrl = $parentFolderUrl

        $listurl = $context.web.ServerRelativeUrl + "/" + "demofile"

        write-host $listurl

        $method = [Microsoft.SharePoint.Client.ClientContext].GetMethod("Load")
        $loadMethod = $method.MakeGenericMethod([Microsoft.SharePoint.Client.List])

        $parameter = [System.Linq.Expressions.Expression]::Parameter(([Microsoft.SharePoint.Client.List]), "list")
        $expression = [System.Linq.Expressions.Expression]::Lambda([System.Linq.Expressions.Expression]::Convert(
                        [System.Linq.Expressions.Expression]::PropertyOrField(
                            [System.Linq.Expressions.Expression]::PropertyOrField($parameter, "RootFolder"),
                            "ServerRelativeUrl"
                            ),
                        [System.Object]),
                    $($parameter)
                    )
        $expressionArray = [System.Array]::CreateInstance($expression.GetType(), 1)
        $expressionArray.SetValue($expression, 0)

        $lists = $web.Lists

        $Context.Load($lists)
        $Context.ExecuteQuery()

        $list = $null

        foreach ($listfinder in $lists) 
        {
            $loadMethod.Invoke($Context, @($listfinder, $expressionArray))
            $Context.ExecuteQuery()

            if ($listfinder.RootFolder.ServerRelativeUrl -eq $listUrl)
            {
                $list = $listfinder
            }
        }

        $newListItem = $list.AddItem($newItemInfo)

        $newListItem.Update()
        $context.load($list)
        $context.ExecuteQuery()
    }


    $roleTypeObject = [Microsoft.SharePoint.Client.RoleType]$roleType
    $roledefs = $web.RoleDefinitions
    $context.Load($roledefs)
    $Context.ExecuteQuery()
    $role = $roleDefs | where {$_.RoleTypeKind -eq $roleTypeObject}

    $principal = $context.Web.EnsureUser($PrincipalName)

    $Context.Load($principal)
    Try
    {
        $Context.ExecuteQuery()
    }
    Catch
    {
        Write-Error $Error[0]
        Exit
    }

    $list = $web.Lists.GetByTitle($listname)

    $camlQuery = new-object Microsoft.SharePoint.Client.CamlQuery
    $camlQuery.ViewXml = "<View><Query><Where><Eq><FieldRef Name='FileLeafRef' /><Value Type='Text'>$FolderName</Value></Eq></Where></Query></View>"

    $listItems = $list.GetItems($camlQuery)

    $Context.Load($listItems)
    $Context.ExecuteQuery()

    $listitem = $listItems[0]

    $method = [Microsoft.Sharepoint.Client.ClientContext].GetMethod("Load")
    $loadMethod = $method.MakeGenericMethod([Microsoft.Sharepoint.Client.ListItem])

    $parameter = [System.Linq.Expressions.Expression]::Parameter(([Microsoft.SharePoint.Client.ListItem]), "x")
    $expression = [System.Linq.Expressions.Expression]::Lambda([System.Linq.Expressions.Expression]::Convert(
                    [System.Linq.Expressions.Expression]::Property(
                    $parameter, ([Microsoft.SharePoint.Client.ListItem]).GetProperty("HasUniqueRoleAssignments")), 
                    ([System.Object])), $($parameter))
    $expressionArray = [System.Array]::CreateInstance($expression.GetType(), 1)
    $expressionArray.SetValue($expression, 0)

    $loadMethod.Invoke( $Context, @( $listItem, $expressionArray ) )

    $Context.ExecuteQuery()
    if (-not $listItem.HasUniqueRoleAssignments)
    {
        $listItem.BreakRoleInheritance($false, $true)
    }

    $rdb = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($Context)

    $rdb.Add($role)

    $ra = $listItem.RoleAssignments.Add($principal, $rdb)

    $Context.ExecuteQuery()
}

Mr @Rajiv

I have now this script, it works for users but i changed it for groups but i have an error, any help ?

Here is the error: Impossible d’appeler une méthode dans une expression Null. in line 86

### Get the user credentials
$credential = Get-Credential
$username = $credential.UserName
$password = $credential.GetNetworkCredential().Password
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force


### Input Parameters
$url = 'https://xxx.sharepoint.com/sites/Demo-
test/Interne/'
$ListName = 'Infrastructure'
$GroupName = 'TestPemissions'
$RootFolder = 'TestPermissions'

### References
# Specified the paths where the dll's are located.
Add-Type -Path 'c:\Program Files\Common Files\microsoft shared\Web Server 
Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll'
Add-Type -Path 'c:\Program Files\Common Files\microsoft shared\Web Server 
Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll'


### AddPermission Function
function AddPermission()
{

# Connect to SharePoint Online and get ClientContext object.
$clientContext = New-Object Microsoft.SharePoint.Client.ClientContext($url)
$credentials = New-Object 
Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, 
$securePassword)
$clientContext.Credentials = $credentials



# Get the SharePoint web
$web = $clientContext.Web
$clientcontext.Load($web)
$groups = $web.SiteGroups
$clientcontext.Load($groups)
$clientcontext.ExecuteQuery()  
$folderurl = $web.ServerRelativeUrl + "/" + $ListName + "/" + $RootFolder
Write-Host "group : " $group
Write-Host "relative url : " $web.ServerRelativeUrl
Write-Host "folderurl : " $folderurl
$root = $web.GetFolderByServerRelativeUrl($folderurl)
$clientcontext.Load($root.Folders)
$clientcontext.ExecuteQuery()
Write-Host "folders : " $root

$group=$GroupName

Function GetRole
    {
        [CmdletBinding()]
        param
        (
            [Parameter(Mandatory = $true, Position = 1)]
            [Microsoft.SharePoint.Client.RoleType]$rType
        )

        $web = $clientContext.Web
        if ($web -ne $null)
        {
            $roleDefs = $web.RoleDefinitions
            $clientContext.Load($roleDefs)
            $clientContext.ExecuteQuery()
            $roleDef = $roleDefs | Where-Object { $_.RoleTypeKind -eq $rType  }
           return $roleDef
       }
       return $null
   }

foreach($folder in $root.Folders){

       #Break inheritance and remove existing permissions
       $folder.ListItemAllFields.BreakRoleInheritance($false, $true)

       #Get the role required and load it 
       write-host "folder : " $folder
       $roleType = Read-Host "None, Guest, Reader, Contributor, WebDesigner, 
Administrator, Editor"
       $roleTypeObject = [Microsoft.SharePoint.Client.RoleType]$roleType
       $roleObj = GetRole $roleTypeObject

       $gpRDBC = New-Object 
Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($clientContext)
       $gpRDBC.Add($roleObj)

       $gpRoleAssign = $folder.RoleAssignement

line 86           $RoleAssign = $gpRoleAssign.Add($group,$gpRDBC)
       $clientcontext.ExecuteQuery()
              Write-Host $gpRDBC.Description

              # Display the folder name and URL
              Write-Host -ForegroundColor Green 'Folder Name: ' $folder.Name 
' URL: '$folder1.ServerRelativeUrl;
       }

}
#Execute the function
AddPermission
Was it helpful?

Solution 2

Here is the solution, but you need to adapt it. ;)

<#
Ce sript permet d'ajouter les droits à un groupe sur un dossier.
#>


$Username = "email address"
$Site = "https://yousite.sharepoint.com/sites/x/"
$Password = Read-Host -Prompt "Entrez votre mot de passe" -AsSecureString

$ListName = 'Your library'
$RootFolder = 'Your folder'


#Add references to SharePoint client assemblies and authenticate to Office 365 site
Add-Type -Path 'c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll'
Add-Type -Path 'c:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll'

# Connect to SharePoint Online and get Context object.
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($Site)
$Creds = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username,$Password)
$Context.Credentials = $Creds
$Web = $Context.Web
$Context.Load($web)

#Retrieve Groups
$group = $Context.Web.SiteGroups.getByName("Group name");
$Context.Load($group)
$Context.ExecuteQuery()

#Retrieve Folder
$folderurl = $web.ServerRelativeUrl + "/" + $ListName + "/" + $RootFolder
$root = $web.GetFolderByServerRelativeUrl($folderurl)
$Context.Load($root.Folders)
$Context.ExecuteQuery()

Function GetRole
    {
        [CmdletBinding()]
        param
        (
            [Parameter(Mandatory = $true, Position = 1)]
            [Microsoft.SharePoint.Client.RoleType]$rType
        )

        $web = $Context.Web
        if ($web -ne $null)
        {
            $roleDefs = $web.RoleDefinitions
            $Context.Load($roleDefs)
            $Context.ExecuteQuery()
            $roleDef = $roleDefs | Where-Object { $_.RoleTypeKind -eq $rType }
            return $roleDef
        }
        return $null
    }


foreach($folder in $root.Folders){

    #Break inheritance and remove existing permissions
    $folder.ListItemAllFields.BreakRoleInheritance($false, $true)

    #Get the role required and load it 
    $roleType = "Editor"
    write-host  -ForegroundColor Green "Ajout des droits " $roleType "sur le dossier " $folder.Name "Pour le groupe " $group.LoginName
    $roleTypeObject = [Microsoft.SharePoint.Client.RoleType]$roleType
    $roleObj = GetRole $roleTypeObject

    #Bind Permission Level to Group
    $RoleDefBind = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($Context)
    $RoleDefBind.Add($roleObj)
    $Assignments = $Context.Web.RoleAssignments

    #Apply the permission roles to the list.
       $Context.Load($folder.ListItemAllFields.RoleAssignments.Add($group, $RoleDefBind))
       $folder.Update()
       $Context.ExecuteQuery()

} 

OTHER TIPS

Use (edit as per your requirement ) the following powershell script:

Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue
 $site = new-object Microsoft.SharePoint.SPSite("http://yourserver/")
 $web = $site.OpenWeb()
 function GrantGroupPermission($groupName)
 {
  [Microsoft.SharePoint.SPGroupCollection]$spgroups = $web.SiteGroups
  [Microsoft.SharePoint.SPGroup]$spgroup = $spgroups[$groupName]
  $sproleass=new-object Microsoft.SharePoint.SPRoleAssignment([Microsoft.SharePoint.SPPrincipal]$spgroup)
  $folder.BreakRoleInheritance("true")
  $sproleass.RoleDefinitionBindings.Add($web.RoleDefinitions["Contribute"])
  $folder.RoleAssignments.Add($sproleass);
  Write-Host "Permission given to the group ", $groupName
 }
 function GrantUserpermission($userName)
 {
  [Microsoft.SharePoint.SPUserCollection]$spusers=[Microsoft.SharePoint.SPUserCollection]$web.SiteUsers
  [Microsoft.SharePoint.SPUser]$spuser=$spusers[$userName]
  $sproleass=new-object Microsoft.SharePoint.SPRoleAssignment([Microsoft.SharePoint.SPPrincipal]$spuser)
  $folder.BreakRoleInheritance("true")
  $sproleass.RoleDefinitionBindings.Add($web.RoleDefinitions["Contribute"])
  $folder.RoleAssignments.Add($sproleass);
  Write-Host "Permission given to  user ", $userName
 }
 $doclib=[Microsoft.SharePoint.SPDocumentLibrary]$web.Lists["Shared Documents"]
 $foldercoll=$doclib.Folders;
 foreach($folder in $foldercoll)
 {
  Write-Host $folder.Name
  if($folder.Name.Equals("office"))
  {
   GrantUserPermission("rajiv")
  }

 }
 Write-Host "Done!"
 $web.Close()
 $site.Dispose()
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top