SharePoint 2013 / 2016: Specific User Permission Analysis Report using PowerShell

Analyzing SharePoint permissions for a particular user is often a common task in SharePoint administration. Generally, How do we check what permissions a user has on SharePoint content? By getting into the site or list settings page and checking permissions for the particular user, isn’t it? Well, You may want to analyze the particular user’s permissions for your entire SharePoint environment.  How about that? Each and every SharePoint site, list, library, folder, and list item may have unique permissions. It can even go more challenging when you have multiple SharePoint farms.

Well, PowerShell is a lifesaver! My permission reporting solution is to scan and provide a report to view a user’s permission on the SharePoint web application. With this script, you can analyze and track security effectively! Check what permissions on an account have been granted in all places in SharePoint. This PowerShell script scans the below areas to retrieve a specific user’s access rights:

  • Farm administrator’s group
  • Central administration web application policies
  • Site collection administrators 
  • Scans all site collections and sub-sites with unique permissions in which user has access.
  • Scans all lists and libraries with unique permissions in which user has access.
  • Scans all folders and list Items which has permissions in the site in which user has access.

Just change the Input variables section, provide parameters for User ID, Web Application, and Report path variables, and run the script in PowerShell.

After generating a SharePoint permissions report, this script generates a CSV file, which can be exported as an Excel file to allow further research and analysis outside of a SharePoint environment. It gets data such as: Object, Title, URL, Permission Type, Permissions, as in the below screenshot.

sharepoint User Permission Analysis Report

PowerShell Script to Generate User Permission Report in SharePoint 2013/2016

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

#Function to retrieve Permission data
Function Get-PermissionInfo([String]$UserID, [Microsoft.SharePoint.SPSecurableObject]$Object)
{
    #Object Array to hold Permission data
    $PermissionDataCollection = @()
    if($Object)
    {
       #Determine the given Object type and Get URL of it
       switch($Object.GetType().FullName)
       {
           "Microsoft.SharePoint.SPWeb"  { $ObjectType = "Site" ; $ObjectURL = $Object.URL }
           "Microsoft.SharePoint.SPListItem" 
           { 
           if($Object.Folder -ne $null)
           {
               $ObjectType = "Folder" ; $ObjectURL = "$($Object.Web.Url)/$($Object.Url)" 
           }
           else
           {
               $ObjectType = "List Item"; $ObjectURL = "$($Object.Web.Url)/$($Object.Url)" 
           }
       }
       #Microsoft.SharePoint.SPList, Microsoft.SharePoint.SPDocumentLibrary, "Microsoft.SharePoint.SPPictureLibrary",etc
       default { $ObjectType = "List/Library"; $ObjectURL = "$($Object.ParentWeb.Url)/$($Object.RootFolder.URL)" }
    }
 
   #Get Permissions of the user on given object - Such as: Web, List, Folder, ListItem
   $UserPermissionInfo = $Object.GetUserEffectivePermissionInfo($UserID)

   #Iterate through each permission and get the details
   foreach($UserRoleAssignment in $UserPermissionInfo.RoleAssignments)
   {
        #Get all permission levels assigned to User account directly or via SharePOint Group
        $UserPermissions=@()
        foreach ($UserRoleDefinition in $UserRoleAssignment.RoleDefinitionBindings)
        {
            #Exclude "Limited Accesses"
            if($UserRoleDefinition.Name -ne "Limited Access")
            {
                 $UserPermissions += $UserRoleDefinition.Name
            }
        }
 
      #Determine Permissions granted directly or through SharePoint Group
      if($UserPermissions)
      {
          if($UserRoleAssignment.Member -is [Microsoft.SharePoint.SPGroup])   
          {
              $PermissionType = "Member of SharePoint Group: " + $UserRoleAssignment.Member.Name     
          }
      else
      {
            $PermissionType = "Direct Permission"
      }
        $UserPermissions = $UserPermissions -join ";"  
 
         #Create an object to hold storage data
         $PermissionData = New-Object PSObject
         $PermissionData | Add-Member -type NoteProperty -name "Object" -value $ObjectType
         $PermissionData | Add-Member -type NoteProperty -name "Title" -value $Object.Title
         $PermissionData | Add-Member -type NoteProperty -name "URL" -value $ObjectURL  
         $PermissionData | Add-Member -type NoteProperty -name "Permission Type" -value $PermissionType
         $PermissionData | Add-Member -type NoteProperty -name "Permissions" -value $UserPermissions
         $PermissionDataCollection += $PermissionData
       }    
    }  
    Return $PermissionDataCollection
  }
}

#Function to Generate Permission Report
Function Generate-PermissionReport($UserID, $WebAppURL, $ReportPath)
{
    #Output Report location, delete the file, If already exist!
    if (Test-Path $ReportPath)
     {
        Remove-Item $ReportPath
     }
  
    #Write Output Report CSV File Headers
    "Object, Title, URL, Permission Type, Permissions" | out-file $ReportPath

    ###Check Whether the Search Users is a Farm Administrator ###
    Write-host "Scanning Farm Administrators..." 
    #Get the SharePoint Central Administration site
    $AdminWebApp = Get-SPwebapplication -includecentraladministration | where {$_.IsAdministrationWebApplication}
    $AdminSite = Get-SPWeb $AdminWebApp.Url
    $AdminGroupName = $AdminSite.AssociatedOwnerGroup
    $FarmAdminGroup = $AdminSite.SiteGroups[$AdminGroupName]
 
    #enumerate in farm adminidtrators groups
    foreach ($user in $FarmAdminGroup.users)
    {
      if($user.LoginName.Endswith($UserID,1)) #1 to Ignore Case
      {
       "Farm, $($AdminSite.Title), $($AdminWebApp.URL), Farm Administrators Group, Farm Administrator" | Out-File $ReportPath -Append
     }     
    }
 
   ### Check Web Application User Policies ###
  Write-host "Scanning Web Application Policies..." 
  $WebApp = Get-SPWebApplication $WebAppURL
 
  foreach ($Policy in $WebApp.Policies)
  {
      #Check if the search users is member of the group
      if($Policy.UserName.EndsWith($UserID,1))
      {
         #Write-Host $Policy.UserName
         $PolicyRoles=@()
         foreach($Role in $Policy.PolicyRoleBindings)
         {
            $PolicyRoles+= $Role.Name +";"
         }
          #Send Data to CSV File
          "Web Application, $($WebApp.Name), $($WebApp.URL), Web Application Policy, $($PolicyRoles)" | Out-File $ReportPath -Append
      }
  }

    #Convert UserID Into Claims format - If WebApp is claims based! Domain\User to i:0#.w|Domain\User
    if($WebApp.UseClaimsAuthentication)
    {
        $ClaimsUserID = (New-SPClaimsPrincipal -identity $UserID -identitytype 1).ToEncodedString()
    }
     else
    {
        $ClaimsUserID = $UserID
    }
 #Get all Site collections of given web app
 $SiteCollections = Get-SPSite -WebApplication $WebAppURL -Limit All

    #Loop through all site collections 
    foreach($Site in $SiteCollections)
    {
       Write-host "Scanning Site Collection:" $site.Url
       ###Check Whether the User is a Site Collection Administrator
       foreach($SiteCollAdmin in $Site.RootWeb.SiteAdministrators)
       {
          if($SiteCollAdmin.LoginName.EndsWith($ClaimsUserID,1))
          {
            "Site Collection, $($Site.RootWeb.Title), $($Site.RootWeb.Url), Site Collection Administrators Group, Site Collection Administrator" | Out-File $ReportPath -Append
          }     
      }
  
  #Get all webs
  $WebsCollection = $Site.AllWebs
  #Loop throuh each Site (web)
  foreach($Web in $WebsCollection)
  {
       if($Web.HasUniqueRoleAssignments -eq $True)
       {
          Write-host "Scanning Site:" $Web.Url
    
          #Get Permissions of the user on Web
          $WebPermissions = Get-PermissionInfo $ClaimsUserID $Web
     
          #Export Web permission data to CSV file - Append
          $WebPermissions |  Export-csv $ReportPath  -notypeinformation -Append 
       } 
    
    #Check Lists with Unique Permissions
    Write-host "Scanning Lists on $($web.url)..."
    foreach($List in $web.Lists)
    {
        if($List.HasUniqueRoleAssignments -eq $True -and ($List.Hidden -eq $false))
        {
             #Get Permissions of the user on list
             $ListPermissions = Get-PermissionInfo $ClaimsUserID $List
      
            #Export Web permission data to CSV file - Append
            $ListPermissions |  Export-csv $ReportPath -notypeinformation -Append       
        }
    
     #Check Folders with Unique Permissions
     $UniqueFolders = $List.Folders | where { $_.HasUniqueRoleAssignments -eq $True }                    
     #Get Folder permissions
     foreach($folder in $UniqueFolders)
     {
         $FolderPermissions = Get-PermissionInfo $ClaimsUserID $folder
    
         #Export Folder permission data to CSV file - Append
         $FolderPermissions |  Export-csv $ReportPath -notypeinformation -Append    
      }
    
     #Check List Items with Unique Permissions
     $UniqueItems = $List.Items | where { $_.HasUniqueRoleAssignments -eq $True }
     #Get Item level permissions
     foreach($item in $UniqueItems)
     {
         $ItemPermissions = Get-PermissionInfo $ClaimsUserID $Item
      
         #Export List Items permission data to CSV file - Append
         $ItemPermissions |  Export-csv $ReportPath -notypeinformation -Append    
     }
    }
  }
 }
 Write-Host Permission Report Generated successfully!
}

#Input Variables
$WebAppURL = "https://intranet.crescent.com"
$Userid ="Crescent\Salaudeen" 
$ReportPath = "D:\Reports\PermissionRpt.csv"

#Call the function to generate user access report
Generate-PermissionReport $Userid $WebAppURL $ReportPath

You can also download the script from TechNet Gallery: SharePoint Permission Report: Check Access Rights for a Specific User

This script is broken into two functions. So that you can use the first function: Get-PermissionInfo, to get permissions data scoped to a site collection permission report/site. The above script is scoped at a particular web application, and you can call the same function on all your web application to get the entire SharePoint permissions reports.

PowerShell Scripts to generate SharePoint Permission Reports:

Here is my list of PowerShell scripts to create various reports for SharePoint permission auditing.

3rd Party Tools:
There are many tools to analyze and audit SharePoint user permissions (and more features, naturally!). Here are some:

Salaudeen Rajack

Salaudeen Rajack - Information Technology Expert with Two-decades of hands-on experience, specializing in SharePoint, PowerShell, Microsoft 365, and related products. He has held various positions including SharePoint Architect, Administrator, Developer and consultant, has helped many organizations to implement and optimize SharePoint solutions. Known for his deep technical expertise, He's passionate about sharing the knowledge and insights to help others, through the real-world articles!

27 thoughts on “SharePoint 2013 / 2016: Specific User Permission Analysis Report using PowerShell

  • Do you have a same report for SPO? For example I’ll try to check SPO site that Mr. xxx has an access?

    Reply
  • Shall we use this for SharePoint Online?

    Reply
  • Is there a way to determine if an Active Directory user account was used versus an Active Directory group? Is there an attribute to check to see if its one or the other. I’m trying to create a report that shows me where individual user accounts are set instead of using their AD role group.

    Reply
    • Try this: https://www.sharepointdiary.com/2016/02/sharepoint-site-collection-permission-report-powershell-script.html

      Reply
  • I am unable to get this script to work on my 2010 SP farm. I am running Classic/NTLM authentication. I am not using claims.

    Can you please help me?

    All I do is change the parameters at the very bottom, the URL and the User ID, and the location of the CSV file.

    I get the following errors, (It states the user does not exist, but I know 10000% my own ID does exist)..

    GetUserEffectivePermissionInfo : Exception calling “GetUserEffectivePermissionI
    nfo” with “1” argument(s): “The user does not exist or is not unique.”
    At line:24 char:62
    + $UserPermissionInfo = $Object.GetUserEffectivePermissionInfo <<<< ($UserID) + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException Export-csv : A parameter cannot be found that matches parameter name 'Append'. At line:73 char:75 + $WebPermissions | Export-csv $ReportPath -notypeinformation -Append << << + CategoryInfo : InvalidArgument: (:) [Export-Csv], ParameterBind ingException + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Comm ands.ExportCsvCommand Scanning Lists on https://portal10a:31437... GetUserEffectivePermissionInfo : Exception calling "GetUserEffectivePermissionI nfo" with "1" argument(s): "The user does not exist or is not unique." At line:24 char:62 + $UserPermissionInfo = $Object.GetUserEffectivePermissionInfo <<<< ($UserID) + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodException Export-csv : A parameter cannot be found that matches parameter name 'Append'. At line:84 char:76 + $ListPermissions | Export-csv $ReportPath -notypeinformation -Append < <<< + CategoryInfo : InvalidArgument: (:) [Export-Csv], ParameterBind ingException + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Comm ands.ExportCsvCommand GetType : You cannot call a method on a null-valued expression. At line:6 char:27 + switch($Object.GetType <<<< ().FullName) + CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeEx ception + FullyQualifiedErrorId : InvokeMethodOnNull GetUserEffectivePermissionInfo : You cannot call a method on a null-valued expr ession. At line:24 char:62 + $UserPermissionInfo = $Object.GetUserEffectivePermissionInfo <<<< ($UserID) + CategoryInfo : InvalidOperation: (GetUserEffectivePermissionInf o:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull

    Reply
    • Having the same issue. where you able to figure it out?

      Reply
    • Same issue in SP2013 for a user that is member of the ownergroup. Did you figure it out?

      Reply
  • Hello, can import all csv information with another user but with all information included in the csv file generated??

    Example:
    Your Script Export all information to the user:contosooldUser
    I need a script to import this info to user: contosonewUser

    I need Help please!

    Thanks

    Reply
    • You mean: You want to copy OldUser’s permissions to NewUser? or Replace OldUser premissions with NewUser? Refer these posts
      https://www.sharepointdiary.com/2015/01/clone-sharepoint-user-permissions-using-powershell.html
      https://www.sharepointdiary.com/2014/12/migrate-sharepoint-users-from-one-domain-to-another.html

      Reply
  • Hi, is this script going to work on MOSS 2007?

    Reply
  • Hi Salaudeen..

    You have written a great script for SharePoint admins. I have exactly same requirements but it’s for all users including folder permissions if it’s unique folder permissions.

    I have seen comments that other user are looking for the same i.e. for all users.
    Function Get-PermissionInfo([String]$UserID, [Microsoft.SharePoint.SPSecurableObject]$Object)

    requires userID and I tried to use this function that accepts only the $Object but not able to managed all users using your script.

    Any pointer would be greatly appreciated.

    Reply
  • Is it possible to skip some groups like Style Resource Readers?

    Can I change this script to only show direct permissions and not permssions given via an ad group?

    Reply
    • Yes! Add your group name in Line#38: if($UserRoleDefinition.Name -ne “Limited Access”)

      This script doesn’t count permissions granted via AD Groups!

      Reply
  • Is this for On-Prem only?

    Reply
    • Yes! Its written for On-Prem. However, its possible to make one for O365 by leaving Farm & Web App sections.

      Reply
    • Hi,

      Could you please help me in getting the same report for O365.

      Thanks in Advance.

      Reply
  • I attempted really hard to reverse engineer this script to find out why it keeps failing for me, but I can’t figure out why. I’m even attempting to run this with the SharePoint 2010 Management shell with the full out sharepoint farm admin account and all I get is this constantly:

    You cannot call a method on a null-valued expression.
    At C:tempUserAccessReport.ps1:135 char:49
    + if($SiteCollAdmin.LoginName.EndsWith <<<< ($ClaimsUserID,1)) + CategoryInfo : InvalidOperation: (EndsWith:String) [], RuntimeE xception + FullyQualifiedErrorId : InvokeMethodOnNull Generate-PermissionReport : Exception has been thrown by the target of an invoc ation. At C:tempUserAccessReport.ps1:203 char:26 + Generate-PermissionReport <<<< $Userid $WebAppURL $ReportPath + CategoryInfo : NotSpecified: (:) [Generate-PermissionReport], T argetInvocationException + FullyQualifiedErrorId : System.Reflection.TargetInvocationException,Gene rate-PermissionReport Thoughts?

    Reply
  • Instead of finding all the sites a specific user has access to, I need to find all the sites that ‘everyone’ has access to. Is it possible to modify your script to do this?

    Reply
    • You mean get permission report for “All Users” instead of one specific user? Well, Just remove IF blocks from the script. Such as:
      If($user.LoginName.Endswith($UserID,1)),
      If($Policy.UserName.EndsWith($UserID,1))
      If($SiteCollAdmin.LoginName.EndsWith($ClaimsUserID,1))

      Reply
    • i commented the 3 IF loop you mentioned. How do i call the function to list all users ?

      like this ?
      generate-permissionreport $WebappUrl $ReportPath$

      Reply
    • This script enumerates through all users who has permission on particular object such as Farm, Web App Policy, Site collection, List, etc. These IF condition checks whether the given user account matches while enumerating. Removing IF gets you all users who has access.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *