1

I have a document libray with structure like given below: FolderA->Subfolder1->item1 Subfolder2-->item2 They have folder level permissions . now i want to create the same folder structure and permissions with different Folder Parent name for example:

Once we copy the folder structure should be FOLDER B-->Subfolder1->item1 Subfolder2-->item2

This is for sharepointonline CSOM powershell.

I was able to copy the folder structure but unable to get permissions is anything missing

       Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll"

Function Copy-SPOFolder([String]$SiteURL, [String]$SourceFolderURL, [String]$TargetFolderURL)
{
    $Host.Runspace.ThreadOptions = "ReuseThread"
    Try{
        #Copy the Folder
        $MoveCopyOpt = New-Object Microsoft.SharePoint.Client.MoveCopyOptions
        [Microsoft.SharePoint.Client.MoveCopyUtil]::CopyFolder($ctx, $SourceFolderURL, $TargetFolderURL, $MoveCopyOpt)
        $ctx.ExecuteQuery()
        Write-host -f Green "Folder Copied Successfully!" }
    Catch {
        write-host -f Red "Error Copying the Folder!" $_.Exception.Message
    }
}
function Connect-SPO()
{
    param ([Parameter(Mandatory=$true,Position=1)][string]$Username,[Parameter(Mandatory=$true,Position=2)][string]$Url,[Parameter(Mandatory=$true,Position=3)]$AdminPassword)
    $global:ctx=New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $AdminPassword)
    $ctx.Load($ctx.Web)
    $ctx.ExecuteQuery()
}
#Function to Get Folder Permissions
Function Get-SPOFolderPermission([String]$SiteURL, [String]$FolderRelativeURL)
{
    $Host.Runspace.ThreadOptions = "ReuseThread"
    Try{


        #Get the Folder
        $Folder = $ctx.Web.GetFolderByServerRelativeUrl($FolderRelativeURL)
        $ctx.Load($Folder)
        $ctx.ExecuteQuery()

        #Get permissions assigned to the Folder
        $RoleAssignments = $Folder.ListItemAllFields.RoleAssignments
        $ctx.Load($RoleAssignments)
        $ctx.ExecuteQuery()

        #Loop through each permission assigned and extract details
        $PermissionCollection = @()
        Foreach($RoleAssignment in $RoleAssignments)
        {
            $ctx.Load($RoleAssignment.Member)
            $ctx.executeQuery()

            #Get the User Type
            $PermissionType = $RoleAssignment.Member.PrincipalType

            #Get the Permission Levels assigned
            $ctx.Load($RoleAssignment.RoleDefinitionBindings)
            $ctx.ExecuteQuery()


                    $PermissionLevels = ($RoleAssignment.RoleDefinitionBindings | Select -ExpandProperty Name) -join ","
                    #Get the User/Group Name
                     $Name = $RoleAssignment.Member.Title # $RoleAssignment.Member.LoginName

                        #Add the Data to Object
                        $Permissions = New-Object PSObject
                        $Permissions | Add-Member NoteProperty Name($Name)
                        $Permissions | Add-Member NoteProperty Type($PermissionType)
                        $Permissions | Add-Member NoteProperty PermissionLevels($PermissionLevels)
                        $PermissionCollection += $Permissions

        }
        Return $PermissionCollection
    }
    Catch {
        write-host -f Red "Error Getting Folder Permissions!" $_.Exception.Message
    }
}
#variables

$admin="santosh.sandy@micrososft.sharepoint.com"
$pass= ConvertTo-SecureString "TSDTD" -AsPlainText -Force
$SiteURL="https://sandy.sharepoint.com/sites/hgs_demo/"
$LibraryName="FolderTest";
$SrcFolderName="RootLibrary"
$NewFolderName="RootLibrary1"
$global:ctx
Try {
    Connect-SPO -Username $admin -Url $SiteURL -AdminPassword $pass
    $Library=$ctx.Web.Lists.GetByTitle($LibraryName);
    $Folders = $Library.RootFolder.Folders
    $ctx.Load($Library);
    $ctx.Load($Folders)
    $ctx.ExecuteQuery()        
    #Get existing folder names
    $FolderNames = $Folders | Select -ExpandProperty Name 
    if($FolderNames -contains $NewFolderName)
    {
        write-host "Folder Exists Already!" -ForegroundColor Yellow
    }
    else{


        $SourceFolderURL= $SiteURL + $LibraryName +"/" + $SrcFolderName
        $TargetFolderURL= $SiteURL + $LibraryName +"/" + $NewFolderName 
        Copy-SPOFolder $SiteURL $SourceFolderURL $TargetFolderURL
        $ctx.Load($Library);
        $ctx.Load($Folders)
        $ctx.ExecuteQuery()
        $FolderNames = $Folders | Select -ExpandProperty Name 
        if($FolderNames -contains $NewFolderName)
        {
            $FolderRelativeURL= "/sites/hgs_demo/"+ $LibraryName +"/" + $NewFolderName
            # write-host "Folder Exists Already!" -ForegroundColor Yellow
            $cFolder = $ctx.Web.GetFolderByServerRelativeUrl($FolderRelativeURL)
            $ctx.Load($cFolder)
            $ctx.ExecuteQuery()

            #Break Permission inheritence - Remove all existing list permissions & keep Item level permissions
            $cFolder.ListItemAllFields.BreakRoleInheritance($False,$True)
            $ctx.ExecuteQuery()
            Write-host -f Yellow "Folder's Permission inheritance broken..."
            $copyfolderRetaltiveurl= "/sites/hgs_demo/"+ $LibraryName +"/" + $SrcFolderName
            $PermissionCopy=  Get-SPOFolderPermission $SiteURL $copyfolderRetaltiveurl
            foreach($Permission in $PermissionCopy)
          {

           Write-Host $Permission.Name +".." $Permission.Type +"..." $Permission.PermissionLevels

           if($Permission.Type -eq "User")
           {
             $UserAccount =$Permission.Name
           }
           else{

           $GroupName = $Permission.Name

           }
            #Get the SharePoint Group & User
            $Group =$ctx.Web.SiteGroups.GetByName($GroupName)
            $User = $ctx.Web.EnsureUser($UserAccount)
            $ctx.load($Group)
            $ctx.load($User)
            $ctx.ExecuteQuery()

            #Grant permission
    #Get the role required
    $Role = $ctx.Web.RoleDefinitions.GetByName($Permission.PermissionLevels)
    $RoleDB = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
    $RoleDB.Add($Role)

    #Assign permissions
    $GroupPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($Group,$RoleDB)
    $UserPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($User,$RoleDB)
    $cFolder.Update()
    $ctx.ExecuteQuery()

    Write-host "Permission Granted Successfully!" -ForegroundColor Green 

          }#end of for each loop     
        }
    }
}
Catch {
    write-host -f Red "Error Granting permission to  Folder!" $_.Exception.Message
}
  • Hi Sandy, I'm writing this as a comment rather than an Answer because I think you need a coding solution to this. But it is possible to do this through the List Settings > Save Document Library As Template. You'd need to test whether the folder-level permissions are preserved. This works for SP 2013, I've not used SPO. – Tally May 20 at 9:43
  • Already done .Folder Level Permissions are preserved . As you said i need it through code – santosh kondapalli May 20 at 14:39
  • I changed the code but I am unable to get the folder permission copied – santosh kondapalli May 22 at 3:02
0

I was able to achieve this below is the code.Can any one help me in making my code small.

Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll" 
Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Taxonomy.dll"
########################################
#### Connection Funtions  #############
########################################

function Connect-SPO()
{
    param ([Parameter(Mandatory=$true,Position=1)][string]$Username,[Parameter(Mandatory=$true,Position=2)][string]$Url,[Parameter(Mandatory=$true,Position=3)]$AdminPassword)
    $global:ctx=New-Object Microsoft.SharePoint.Client.ClientContext($Url)
    $ctx.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($Username, $AdminPassword)
    $ctx.Load($ctx.Web)
    $ctx.ExecuteQuery()
}

########################################
#### Recurse Function  #################
########################################      
function Recurse($Folder) 
{
$Host.Runspace.ThreadOptions = "ReuseThread"

    $folderName = $Folder.Name
    $folderItemCount = $folder.ItemCount
    Write-Host "Folder Name ->'$folderName'"
    Write-Host "Number of List Items->'$folderItemCount'"


    if($Folder.name -eq $SrcFolderName)
    {

          $Rootfolderurl= $Folder.ServerRelativeUrl
          $NewRootFolder=$RootfolderURl.Replace($SrcFolderName,$NewFolderName)
          Write-Host $Rootfolderurl -ForegroundColor Magenta
          Write-Host $NewRootFolder -ForegroundColor Magenta


          ###########################
          #Create the new Root Folder
          ##########################
          ###Create-Folder -LibraryName $LibraryName -FolderName $NewFolderName -RootPermissionCol $RootPermissionCopy


          #Create the Folder
          $CreateNewFolder=$ctx.Web.Folders.Add($NewRootFolder)
          $ctx.ExecuteQuery()
          Write-Host "Folder Created"

          #############################
          ###Get Security on RootFolder
          #############################

          $RootPermissionCopy=  Get-SPOFolderPermission -FolderRelativeURL $Rootfolderurl

          #############################
          ###Break Inheritence on New Root Folder
          #############################

          $cFolder = $ctx.Web.GetFolderByServerRelativeUrl($NewRootFolder)
          $ctx.Load($cFolder)
          $ctx.ExecuteQuery()

           #Break Permission inheritence - Remove all existing list permissions & keep Item level permissions
           $cFolder.ListItemAllFields.BreakRoleInheritance($False,$True)
           $ctx.ExecuteQuery()


          foreach($Permission in $RootPermissionCopy)
          {
              Write-Host "Name " $Permission.Name
              Write-Host "Type " $Permission.Type
              Write-Host "Permission Levels" $Permission.PermissionLevels



              #Check and Skip if Permission are only "Limited Access"
              If ($Permission.PermissionLevels -eq "Limited Access") {
              Write-Host "Skipping because there is only Limited Access"
              Write-Host ""
              }
              Else {
                if($Permission.Type -eq "User"){
                    $PermLevelArray=$Permission.PermissionLevels -split ","
                    $UserAccount =$Permission.Name
                    $User = $ctx.Web.EnsureUser($UserAccount)
                    $ctx.load($User)
                    $ctx.ExecuteQuery()

                        Foreach($PermLevel in $PermLevelArray){
                            write-host $PermLevel
                            if($PermLevel -eq "Limited Access") {
                                Write-Host "Skipping Limited Access"
                            }
                            Else {
                                $Role = $ctx.Web.RoleDefinitions.GetByName($PermLevel)
                                $RoleDB = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
                                $RoleDB.Add($Role)
                                $UserPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($User,$RoleDB)
                                Write-Host "Applied " $PermLevel
                                $cFolder.Update()
                                    try {
                                        $ctx.ExecuteQuery()
                                    }
                                    Catch {
                                        Write-host "User cannot be found"
                                    }
                            }
                        }
                }
                else{
                    Write-host $Permission.Name
                    $PermLevelArray=$Permission.PermissionLevels -split ","
                    $GroupName = $Permission.Name
                    $Group =$ctx.Web.SiteGroups.GetByName($GroupName)
                    $ctx.load($Group)
                    $ctx.ExecuteQuery()

                    Foreach($PermLevel in $PermLevelArray){
                        write-host $PermLevel
                        if($PermLevel -eq "Limited Access") {
                            Write-Host "Skipping Limited Access"
                        }
                        Else {
                            $Role = $ctx.Web.RoleDefinitions.GetByName($PermLevel)
                            $RoleDB = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
                            $RoleDB.Add($Role)
                            $GroupPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($Group,$RoleDB)
                            Write-Host "Applied " $PermLevel
                            $cFolder.Update()
                            Try {
                                $ctx.ExecuteQuery()
                            }
                            Catch {
                                Write-host "Group Cannot be Found"
                            }
                       }
                    }
                }

              }

          }

          Write-Host "Permissions Retrieved"


    }

    Else
    {
    ################################
    ##Create New SubFolder
    ################################

       Write-Host "Copy this folder as a none root folder!!" -ForegroundColor Cyan

       #Get Relative Url of the Folder to Copy
       $CurrentFolderUrl= $Folder.ServerRelativeUrl
       Write-Host $CurrentFolderUrl -ForegroundColor Green

       #Create Url of the Folder to Create based on the Current Folder - Replace Folder Path
       $FolderToAdd = $CurrentFolderUrl.Replace($SrcFolderName,$NewFolderName)
       Write-Host "Add===> "$FolderToAdd -ForegroundColor Cyan



       #Create the Folder
       $CreateNewFolder=$ctx.Web.Folders.Add($FolderToAdd)
       $ctx.ExecuteQuery()
       Write-Host "Folder Created"

       #############################
       ###Get Security on Current Folder
       #############################
       $CurrentPermissionCopy=  Get-SPOFolderPermission -FolderRelativeURL $CurrentFolderUrl

       #############################
       ###Break Inheritence on New Root Folder
       #############################

       $cFolder = $ctx.Web.GetFolderByServerRelativeUrl($FolderToAdd)
       $ctx.Load($cFolder)
       $ctx.ExecuteQuery()

       #Break Permission inheritence - Remove all existing list permissions & keep Item level permissions
       $cFolder.ListItemAllFields.BreakRoleInheritance($False,$True)
       $ctx.ExecuteQuery()


          foreach($Permission in $CurrentPermissionCopy)
          {
              Write-Host "Name " $Permission.Name
              Write-Host "Type " $Permission.Type
              Write-Host "Permission Levels" $Permission.PermissionLevels



              #Check and Skip if Permission are only "Limited Access"
              If ($Permission.PermissionLevels -eq "Limited Access") {
              Write-Host "Skipping because there is only Limited Access"
              Write-Host ""
              }
              Else {
                if($Permission.Type -eq "User"){
                    $PermLevelArray=$Permission.PermissionLevels -split ","
                    $UserAccount =$Permission.Name
                    $User = $ctx.Web.EnsureUser($UserAccount)
                    $ctx.load($User)
                    $ctx.ExecuteQuery()

                        Foreach($PermLevel in $PermLevelArray){
                            write-host $PermLevel
                            if($PermLevel -eq "Limited Access") {
                                Write-Host "Skipping Limited Access"
                            }
                            Else {
                                $Role = $ctx.Web.RoleDefinitions.GetByName($PermLevel)
                                $RoleDB = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
                                $RoleDB.Add($Role)
                                $UserPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($User,$RoleDB)
                                Write-Host "Applied " $PermLevel
                                $cFolder.Update()
                                    try {
                                        $ctx.ExecuteQuery()
                                    }
                                    Catch {
                                        Write-host "User cannot be found"
                                    }
                            }
                        }
                }
                else{
                    Write-host $Permission.Name
                    $PermLevelArray=$Permission.PermissionLevels -split ","
                    $GroupName = $Permission.Name
                    $Group =$ctx.Web.SiteGroups.GetByName($GroupName)
                    $ctx.load($Group)
                    $ctx.ExecuteQuery()

                    Foreach($PermLevel in $PermLevelArray){
                        write-host $PermLevel
                       if($PermLevel -eq "Limited Access") {
                            Write-Host "Skipping Limited Access"
                        }
                        Else {
                            $Role = $ctx.Web.RoleDefinitions.GetByName($PermLevel)
                            $RoleDB = New-Object Microsoft.SharePoint.Client.RoleDefinitionBindingCollection($ctx)
                            $RoleDB.Add($Role)
                            $GroupPermissions = $cFolder.ListItemAllFields.RoleAssignments.Add($Group,$RoleDB)
                            Write-Host "Applied " $PermLevel
                            $cFolder.Update()
                            Try {
                                $ctx.ExecuteQuery()
                            }
                            Catch {
                                Write-host "Group Cannot be Found"
                            }
                       }
                    }
                }

              }

          }

       }



    #Write-Host $folder.ListItemAllFields.HasUniqueRoleAssignments
    $thisFolder = $ctx.Web.GetFolderByServerRelativeUrl($Folder.ServerRelativeUrl)
    $ctx.Load($thisFolder)
    $ctx.Load($thisFolder.Folders)
    $ctx.ExecuteQuery()

    foreach($subfolder in $thisFolder.Folders)
        {
           Write-Host $subfolder.ServerRelativeUrl -ForegroundColor Gray
            Recurse $subfolder  
        }       
}

##########################################
#### Function to Get Folder Permissions ## 
##########################################
Function Check-SPOFolderExists()
{
  param
    ( [Parameter(Mandatory=$true)] [string] $FolderRelativeURL)

    $Host.Runspace.ThreadOptions = "ReuseThread"
       $checkfolderExists="False"

    Try {
          #Check Folder Exists
          $checkfolder= $ctx.web.GetFolderByServerRelativeUrl($FolderRelativeURL)
          $ctx.Load($Folder)
          $ctx.ExecuteQuery()
          $checkfolderExists="True";
          #Write-host -f Green "Folder Exists!"
        }

    catch{
           Write-host -f Yellow "Folder Doesn't Exist!"
            #Write-Host "Error in Check-SPoFolder Function with Message" $_.Exception.Message
        }

    return $checkfolderExists

 }


##########################################
#### Function to Get Folder Permissions ## 
##########################################

Function Get-SPOFolderPermission([String]$FolderRelativeURL)
{
    $Host.Runspace.ThreadOptions = "ReuseThread"
    Try{


        #Get the Folder
        $pFolder = $ctx.Web.GetFolderByServerRelativeUrl($FolderRelativeURL)
        $ctx.Load($pFolder)
        $ctx.ExecuteQuery()

        #Get permissions assigned to the Folder
        $RoleAssignments = $pFolder.ListItemAllFields.RoleAssignments
        $ctx.Load($RoleAssignments)
        $ctx.ExecuteQuery()

        #Loop through each permission assigned and extract details
        $PermissionCollection = @()
        Foreach($RoleAssignment in $RoleAssignments)
       {
            $ctx.Load($RoleAssignment.Member)
            $ctx.executeQuery()

            #Get the User Type
            $PermissionType = $RoleAssignment.Member.PrincipalType

            #Get the Permission Levels assigned
            $ctx.Load($RoleAssignment.RoleDefinitionBindings)
            $ctx.ExecuteQuery()


                    $PermissionLevels = ($RoleAssignment.RoleDefinitionBindings | Select -ExpandProperty Name) -join ","
                    #Get the User/Group Name
                     $Name = $RoleAssignment.Member.LoginName # $RoleAssignment.Member.LoginName

                        #Add the Data to Object
                        $Permissions = New-Object PSObject
                        $Permissions | Add-Member NoteProperty Name($Name)
                        $Permissions | Add-Member NoteProperty Type($PermissionType)
                        $Permissions | Add-Member NoteProperty PermissionLevels($PermissionLevels)
                        $PermissionCollection += $Permissions

        }
        Return $PermissionCollection
    }
    Catch {
        write-host -f Red "Error Getting Folder Permissions!" $_.Exception.Message
    }
}

##################################
#### Parmeters and start script ## 
##################################

$admin=""
$pass= ConvertTo-SecureString "" -AsPlainText -Force
$SiteURL="https://micrososft.sharepoint.com/sites/hgs_demo/"
$LibraryName="FolderTest";
$SrcFolderName="mytest"
$NewFolderName="cmytesst"
$global:ctx
Try {
     Connect-SPO -Username $admin -Url $SiteURL -AdminPassword $pass
    $Library=$ctx.Web.Lists.GetByTitle($LibraryName);
    $Folders = $Library.RootFolder.Folders
    $ctx.Load($Library);
    $ctx.Load($Folders)
    $ctx.ExecuteQuery()   

    foreach ($Folder in $Library.RootFolder.Folders)
        {

        if($Folder.ItemCount -gt 0 -and $Folder.Name -eq $SrcFolderName)
         {
              $CurrentRootfolderurl= $Folder.ServerRelativeUrl
            $NewRootFolderUrl=$CurrentRootfolderurl.Replace($SrcFolderName,$NewFolderName)
          #CheckIfFolderExists
           $CheckRootFolderExists= Check-SPOFolderExists -FolderRelativeURL $NewRootFolderUrl
           if( $CheckRootFolderExists -eq "True")
           {

               Write-Host "A folder with name "$NewFolderName "already Exists and its url " $NewRootFolderUrl -ForegroundColor Green
           }
           else{
            #Calling Recursive Function with
                Recurse $Folder
             }
           }
        }



    }

    catch{

    Write-Host  $_.Exception.Message

    } 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.