Question

My goal is to get all permissions of items with unique permissions which are not part of the parent folder permissions.

I actually have a script which loop through all items with unique permissions and display the item ID & Title with the role assignements (Member + Roles). Unfortunately, I didn't found out how to get the item parent folder permissions yet to compare both of them.

Using SharePoint 2013 On-Premise.

Here goes the script:

Add-PSSnapin Microsoft.SharePoint.PowerShell
CLS

##################### Description #########################
# This script loop through all items of a library in one  #
# or more departemnts and display the items which have    #
# unique permissions with their members & roles.          #
###########################################################


##################### PARAMETERS ######################

# Enter the department part url
#   e.g.: "/dept/production/"
# For all departments, enter "/dept/"
$deptUrl = "/dept/" 

# Enter library name
$libraryName = "GED / EDM"

#######################################################

# Initialize counters
$totalItemsCtr = 0
$uniqueItemsCtr = 0

Get-SPSite -Limit All | ? { $_.Url -like "*$($deptUrl)*" } | % {
    # Get Web & List
    $web = $_.OpenWeb()
    $list = $web.Lists[$libraryName]

    Write-Host "========== $($web.Title) ==========" -ForegroundColor Yellow
    $list.Items | % {
        $item = $_
        # Only loop through items with unique roles
        if ($item.hasUniqueRoleAssignments) {
            Write-Host "  $($item.ID) - $($item.Title):" -ForegroundColor Cyan

            # Loop through role assignments
            $item.RoleAssignments | % {
                $roleAssignement = $_

                # Get the member which has the roles
                $member = $roleAssignement.Member

                # Concatenate the roles in one string
                $roles = "["

                $roleAssignement.RoleDefinitionBindings | % {
                    $roles += "$($_.Name); "
                }

                if ($roles.Length -gt 1) {
                    $roles = $roles.Substring(0, $roles.Length - 2)
                }

                $roles += "]"

                # Output member & its roles
                Write-Host "    - $($member):" -ForegroundColor Green
                Write-Host "      |__ $($roles)" -ForegroundColor Magenta
            }

            # New line            
            Write-Host ""

            # Increment counter
            $uniqueItemsCtr++
        }
    }

    $totalItemsCtr += $list.Items.Count
    $web.Dispose()
}

Write-Host "There is $($uniqueItemsCtr) items with unique permissions out of $($totalItemsCtr)." -ForegroundColor Magenta

Output example:

========== Customer Service ==========
========== Production ==========
  1234 - Production Document 1 :
    - Production Owners:
      |__ [Limited Access; Contribute]
    - Production Members:
      |__ [Limited Access; Contribute - No Delete]
    - Production Visitors:
      |__ [Limited Access; Read]
    - John:
      |__ [Limited Access; Read]

  1432 - Production Document 6 :
    - Production Owners:
      |__ [Limited Access; Contribute]
    - Production Members:
      |__ [Limited Access; Contribute - No Delete]
    - Production Visitors:
      |__ [Limited Access; Contribute - No New or Delete]

There is 2 items with unique permissions out of 368.

Based on the above example, the items parent Folder "Production Documents" would have the following rights:

- Production Owners: [Limited Access; Contribute]
- Production Members: [Limited Access; Contribute - No Delete]
- Production Visitors: [Limited Access; Read]

So, the ouput should end up being the following:

========== Customer Service ==========
========== Production ==========
  1234 - Production Document 1 :
    - John:
      |__ [Limited Access; Read]

  1432 - Production Document 6 :
    - Production Visitors:
      |__ [Limited Access; Contribute - No New or Delete]
Was it helpful?

Solution

Thanks to @DubStep's answer which led me to the answer, I've remembered about SPItem.File.ParentFolder. I've found out we can get the permissions like an SPItem usingSPFolder.Item.RoleAssignments. I could finally get a script which displayed all new user & roles which the parent folder don't have. This script is not the most efficient, but get the job done.

Notes: It won't take the missing rights as I am not interested by those, but it could be easily tweaked to do so.

Here goes the script:

Add-PSSnapin Microsoft.SharePoint.PowerShell
CLS

##################### Description #########################
# This script loop through all items of a library in one  #
# or more departemnts and display the items which have    #
# unique permissions with their new members & roles.      #
###########################################################


##################### PARAMETERS ######################

# Enter the department part url
#   e.g.: "/dept/production/"
# For all departments, enter "/dept/"
$deptUrl = "/dept/cs" 

# Enter library name
$libraryName = "GED / EDM"

# Enter item title (leave blank for all items)
$itemTitle = ""

#######################################################

# Initialize counters
$totalItemsCtr = 0
$uniqueItemsCtr = 0

Get-SPSite -Limit All | ? { $_.Url -like "*$($deptUrl)*" } | % {
    # Get Web & List
    $web = $_.OpenWeb()
    $list = $web.Lists[$libraryName]

    Write-Host "========== $($web.Title) ==========" -ForegroundColor Yellow
    $list.Items | ? { $_.Title -like "*$($itemTitle)*" } | % {
        $item = $_
        # Only loop through items with unique roles
        if ($item.hasUniqueRoleAssignments) {
            Write-Host "  $($item.ID) - $($item.Title):" -ForegroundColor Magenta

            # Get folder roles
            $folderRoleAssignements = $item.File.ParentFolder.Item.RoleAssignments

            # Loop through item members
            $item.RoleAssignments | % {
                $itemRoleAssignment = $_

                # Get the member which has the roles
                $member = $itemRoleAssignment.Member
                $roles = "["

                $folderRoleAssignment = $null

                try { # If no error is thrown, it means the folder already have permissions for this member
                    $folderRoleAssignment = $folderRoleAssignements.GetAssignmentByPrincipal($member)

                    $newRoles = "["

                    # Loop through item roles
                    $itemRoleAssignment.RoleDefinitionBindings | ? {$_.Name -notlike 'Limited Access'} | % {
                        $itemRole = $_

                        $folderRole = $null

                        $folderRoleAssignment.RoleDefinitionBindings | ? {$_.Name -notlike 'Limited Access' -and $itemRole.Id -eq $_.Id} | % {
                            $folderRole = $_
                        }

                        # Folder doesn't have this permission for this member
                        if (!$folderRole) {
                            $newRoles += "$($itemRole.Name); "
                        }
                    }

                    # Remove extra space and ';', and output the new roles
                    if ($newRoles.Length -gt 1) {
                        $newRoles = $newRoles.Substring(0, $newRoles.Length - 2)
                        $newRoles += "]"

                        Write-Host "    $($itemRoleAssignment.Member.Name)  (New Roles):" -ForegroundColor Gray
                        Write-Host "        (+) $($newRoles)" -ForegroundColor Green
                    }

                } catch { # If the folder doesn't have permissions for this member
                    # Concatenate the roles in one string
                    $itemRoleAssignment.RoleDefinitionBindings | ? {$_.Name -notlike 'Limited Access'} | % {
                        $roles += "$($_.Name); "
                    }

                    # Remove extra space and ';'
                    if ($roles.Length -gt 1) {
                        $roles = $roles.Substring(0, $roles.Length - 2)
                    }

                    $roles += "]"

                    # Output member & its roles
                    Write-Host "    (+) $($member) (New Member):" -ForegroundColor Green
                    Write-Host "        (+) $($roles)" -ForegroundColor Green
                }
            }

            # Increment counter
            Write-Host ""
            $uniqueItemsCtr++
        }
    }


    $totalItemsCtr += $list.Items.Count
    $web.Dispose()
}

Write-Host "There is $($uniqueItemsCtr) items with unique permissions out of $($totalItemsCtr)." -ForegroundColor Magenta

Which output this:

========== Customer Service ==========
========== Production ==========          
  1234 - Production Document 1 :
    (+) John (New Member):
        (+) [Read]

  1432 - Production Document 6 :
    Production Visitors  (New Roles):
        (+) [Contribute - No New or Delete]

There is 2 items with unique permissions out of 368.

Hope this will answer people with the same question.

OTHER TIPS

I assume you are talking about rootweb here? You could write a loop on the web application to get all sites collection, then get rootweb for each site collection and then do stuff, where stuff would be your code for getting permissions. It will only pull back the permissions on the root web and not subsites or items. So something like the below should work. I didn't test this, so you might want to do that with some simple command first instead of the permissions code, like Write-Host $spsite.rootweb If it writes all site collection URLs in the console, then it should be good to go.

$wa = read-host "Please Enter Web Application URL"
$webapp = Get-SPWebApplication $wa
foreach ($spsite in $webapp.Sites)
{
    $spweb = Get-SpWeb $spsite.rootweb
    foreach ($spweb in $spsite.rootweb)
    {
        Insert permissions code here
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top