Use PowerShell to Set Permissions on All SharePoint Libraries, Folders and Files

When you work with SharePoint permissions, you quickly figure out that you want to touch them as little as possible.  With a lot of things in SharePoint, permissions inherit top down.  So this means that it’s a best practice to always use that inheritance as much as possible. 

But invariably there will be times when you have to break that inheritance and set unique permissions.  Sooner or later, you might need to change those permissions en masse, but you have 30 libraries, and in each library you have multiple folders and files.  All with broken permissions! 

We can turn to our good friend PowerShell to make this an easy task.  This will apply to on-premise SharePoint, BUT it might be possible with SharePoint Online as well, potentially using the PnP PowerShell commands.

Our Scenario

In my case, let’s say for example you have a SharePoint site for tracking your company’s budget process.  On this site, you create document libraries for each main department, then in those libraries you create folders for each departmental code.  Inside those folders are the actual budget Excel files.  It’s critical that each granular department can only edit their own budget files. 

SharePoint Budgets structure

Well during the budget process, for a period of time we need to lock down all the permissions to read only while things are being reviewed and submitted. 

One option would be to just reset permission inheritance at the site level, then define a limited group of a few users in Finance with access.  But that would mean the users couldn’t read, they would lose all access. 

Another option is to use a 3rd-party tool to backup the permissions before we make any changes, then use a script to change them, then use this same tool to restore them.  One tool is called Dell Site Administrator, which comes with a tool called Security Explorer.  This allows us to click the site, and it will backup all the permissions of every object below it.  This has saved my bacon more than once.

Dell Security Explorer

The Script

Per our requirement, I had 2 main goals for our budget site and tons of unique permissions:

  1. In our site, for every library, folder and file in each library keep permissions the way they are, but reset the permission the existing groups had from anything to Read. 
  2. For every object with custom permission, add in a SharePoint group with Full Control called Budget Lockdown

How do we do it?  Our best friend PowerShell.

function FixPerms($permissions) {
    $FullControlRole = $web.RoleDefinitions[“Full Control”]
    $ReadRole = $web.RoleDefinitions[“Read”]
    
    foreach ($assignment in $permissions) {
        $assignment.RoleDefinitionBindings.RemoveAll()    
        $assignment.RoleDefinitionBindings.Remove($FullControlRole);
        $assignment.RoleDefinitionBindings.Add($ReadRole);
        $assignment.Update()        
    }   
    write-host "Fixed permissions"     
}

function AddGroup($thing) {
  #Add SP group with Full Control
    $FullControlRole = $web.RoleDefinitions[“Full Control”]
    $group = $web.SiteGroups["Budgets Lockdown"]
    $groupRole = New-Object Microsoft.SharePoint.SPRoleAssignment($group)
    $groupRole.RoleDefinitionBindings.Add($FullControlRole)
    $thing.RoleAssignments.Add($groupRole)  
    write-host "Added group"
}

$systemlibs =@("Converted Forms", "Customized Reports", "Documents", "Form Templates",  
                              "Images", "List Template Gallery", "Master Page Gallery", "Pages",  
                               "Reporting Templates", "Site Assets", "Site Collection Documents", 
                               "Site Collection Images", "Site Pages", "Solution Gallery",  
                               "Style Library", "Theme Gallery", "Web Part Gallery", "wfpub", "Workflows")

$web = get-spweb "http://sharepoint/Budgets"
foreach ($lib in $web.lists) {
    if ($lib.BaseType -ne "DocumentLibrary") {continue}
    if ($systemlibs -contains $lib) {continue;}
    write-host "Checking library:" $lib.title
    
    #check library permissions
    if ($lib.HasUniqueRoleAssignments -eq "True") {
        write-host "Need to fix library perms:" $lib.Title
        $permissions = $lib.RoleAssignments
        FixPerms($permissions)
        AddGroup($lib)
    }
    
    #check all subfolders
    foreach ($folder in $lib.folders) {
        if ($folder.HasUniqueRoleAssignments -eq "True") {            
            write-host "Need to fix folder perms:" $folder.Name
            $permissions = $folder.RoleAssignments
            FixPerms($permissions)
            AddGroup($folder)            
        }
    }
    
    #Check all files
    foreach ($item in $lib.items) {
        if ($item.HasUniqueRoleAssignments -eq "True") {
            write-host "Fix item perms:" $item.Name
            
        $permissions = $item.RoleAssignments
        FixPerms($permissions)
            AddGroup($item)
        }
    }
    write-host "`================"
}

 

Basically, here’s a few notes of what I have going on:

  • I use functions, one function that resets the existing permissions to Read and another function that adds the necessary SharePoint group
  • I saw someone else do this and I use it too.  You have an array of all the names of the system document libraries (libraries we want to skip / not check).  So when you check each document library, you check it to see if it’s in the list of names you want to exclude.  If it is, skip, otherwise check permissions.  Great easy way to handle that instead of doing like “if title = site pages OR if title = master page gallery”
  • The last thing I’ll call out is that instead of doing nested checking, like check the library, and for folder, check inside that folder for subfolders, then files.  If you just call the folders property of the library like $lib.folders, it returns ALL folders regardless of parent. 
    • Same thing for files, we just do $lib.items, it returns all files regardless of what folder they’re in.  That’s all we need, just check all files. 

You should get results like this:

image

So if we look at the permissions of one of the files before we run change anything:

image

After we run our script:

image

Nice, we have our new group with Full Control, and the rest are Read.  Problem solved!  I’ll admit that I was under a quick deadline to get this done at the time, so it doesn’t have robust error checking. 

If you’re having trouble writing or using PowerShell with SharePoint, or anything with SharePoint please contact us!  I’d love to try and help you out.