SharePoint Users and Groups Security Report Based on Permission Levels
Getting insights on who has access to SharePoint sites & lists and what level of permission has been granted on all over site collection is a frequent requirement in SharePoint governance. Because out-of-the-box security reporting is very limited, I wrote this PowerShell script to generate SharePoint users and groups security reports based on permission levels.
This report helps great in auditing user access on various SharePoint sites, lists to resolve any potential security risks according to the compliance. With the report, we can quickly and accurately get insights, such as
- The report provides information about the list of users and groups who have been assigned permissions in the SharePoint site.
- It displays the list of assigned users and groups, account type (SharePoint user, AD group, or SharePoint group), owner and members of the group and permission levels.
- Analyses permissions for users and groups on any site or list. So, it’s easy to analyze what a user has access to what.
- It also lists out Site Permission Levels with their permissions defined for each one of them.
- Additionally, this report gives list Permissions information where lists are with unique permissions.
PowerShell Script to generate SharePoint users and groups security report based on permission levels
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
#Region MOSS-2007-Cmdlets
Function global:Get-SPSite($url)
{
if($url -ne $null)
{
return New-Object Microsoft.SharePoint.SPSite($url)
}
}
Function global:Get-SPWeb($url)
{
$site= Get-SPSite($url)
if($site -ne $null)
{
$web=$site.OpenWeb();
}
return $web
}
#EndRegion
Function GeneratePermissionReport()
{
#Site Collection URL - Mandatory parameter
param([Parameter(Mandatory=$true)] [string]$SiteCollectionURL)
#Get the site collection
$Site= Get-SPSite $SiteCollectionURL
$web=$site.RootWeb
#Get HTML File with CSS into the Output report
$Content=Get-Content -Path "table.htm" > PermissionReport.htm
"<h2> $($Site.RootWeb.Title) - Permission Report</h2>" | out-file "PermissionReport.htm" -Append
#Table of Contents
"<h3> List of Sites under $($Site.RootWeb.Title)</h3> <table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr><th>Site Name </th><th> URL </th></tr>" >> PermissionReport.htm
#Get Users of All Webs : Loop throuh all Sub Sites
foreach($Web in $Site.AllWebs)
{
"<tr> <td> <a href='#$($web.Title.ToLower())'>$($web.Title)</a> </td><td> $($web.URL)</td> </tr>" >> PermissionReport.htm
}
#Get Users of All Webs : Loop throuh all Sub Sites
foreach($Web in $Site.AllWebs)
{
#Check if site is using Unique Permissions or Inheriting from its Parent Site!
if($Web.HasUniqueRoleAssignments -eq $true)
{
"</table><br/><hr> <h3>Site: [ <a name='$($Web.Title.ToLower())'>$($Web.Title) </a> ] at <a href='$($web.URL)'>$($web.URL)</a> is using Unique Permissions. </h3>" >> PermissionReport.htm
}
else
{
"</table><br/><hr> <h3>Site: [ <a name='$($Web.Title.ToLower())'>$($Web.Title) </a> ] at <a href='$($web.URL)'>$($web.URL)</a> is Inheriting Permissions from its Parent Site.</h3>" >> PermissionReport.htm
}
if($Web.HasUniqueRoleAssignments -eq $true)
{
"<b>Site Users and Groups</b><table class='altrowstable' id='alternatecolor' cellpadding='5px'>" >> PermissionReport.htm
#Get the Role Assignments - (Users & Groups Granted access to the site) with each Role
foreach($RoleDefinition in $Site.RootWeb.RoleDefinitions)
{
#Write-Host $RoleDefinition.Name
#Write Table Caption
"<tr><th colspan='3'> <b>Permission Level: $($RoleDefinition.Name) <b> </th></tr>" >> PermissionReport.htm
#Write Table Header
"<tr> <td><b>Users/Groups </b></td> <td><b> Type </b></td> <td><b>User Name</b></td></tr>" >> PermissionReport.htm
foreach ($WebRoleAssignment in $web.RoleAssignments)
{
foreach($RoleDefinitionBinding in $WebRoleAssignment.RoleDefinitionBindings)
{
#If the current Role assignment contains the Site's Role Definition?
if($RoleDefinitionBinding.Name -contains $RoleDefinition.Name)
{
#**** Get User/Group Type *****#
#Is it a SharePoint Group?
if($WebRoleAssignment.Member.LoginName -eq $NULL)
{
$Type="SharePoint Group"
$UserName=$WebRoleAssignment.Member.Name
#Set Flag value for "Group Exists"
$GroupExistsFlag=$true
}
#Is it a SharePoint User Account or Domain Group?
else
{
$UserName=$WebRoleAssignment.Member.LoginName
#Is it a Domain Group?
if($WebRoleAssignment.Member.IsDomainGroup)
{
$Type="Domain Group"
}
else
{
$Type="SharePoint User"
}
}
#Send Data to Report
"<tr> <td> $($WebroleAssignment.Member.Name) </td><td> $($Type) </td><td> $($UserName) </td> </tr>" >> PermissionReport.htm
}
}
}
}
"</table></br> " >> PermissionReport.htm
if($GroupExistsFlag -eq $true)
{
#**** Get All Members Group and its users ****
"<b>Group Members</b><table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr>" >> PermissionReport.htm
foreach ($WebRoleAssignment in $web.RoleAssignments)
{
#Check if its a group
if($WebRoleAssignment.Member.GetType().FullName -eq "Microsoft.SharePoint.SPGroup")
{
"<th colspan='2'><b>Group Name: $($WebRoleAssignment.Member.Name)<b></th></tr><tr><td><b>User ID</b></td><td><b>User Name</b></td></tr>" >> PermissionReport.htm
foreach($User in $WebRoleAssignment.Member.users)
{
"<tr><td> $($User.LoginName) </td><td> $($User.Name) </td></tr>" >> PermissionReport.htm
}
}
}
"</table> " >> PermissionReport.htm
}
#Reset Group Exists Flag
$GroupExistsFlag=$false
}
#*** Get All List & Library permissions with Unique Access ***#
foreach($List in $Web.lists)
{
#Skip the Hidden Lists
if( ($List.HasUniqueRoleAssignments -eq $True) -and ($List.Hidden -eq $false))
{
"</table><br/><b>Users and Groups in List: [ $($List.Title) ] at <a href='$($List.ParentWeb.Url)/$($List.RootFolder.Url)'>$($List.ParentWeb.Url)/$($List.RootFolder.Url)</a> with Unique Permissions.</b><table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr>" | Out-File PermissionReport.htm -Append
"<td><b>Users/Groups </b></td><td> <b> Type </b></td><td><b> User Name </b></td></tr>" >> PermissionReport.htm
foreach($RoleDefinition in $site.RootWeb.RoleDefinitions)
{
"<tr><th colspan='3'> Permission Level: $($RoleDefinition.Name) </th></tr>" >> PermissionReport.htm
#Get all the users granted permissions to the list
foreach($ListRoleAssignment in $List.RoleAssignments )
{
foreach($RoleDefinitionBinding in $ListRoleAssignment.RoleDefinitionBindings)
{
if($RoleDefinitionBinding.Name -contains $RoleDefinition.Name)
{
#*** Get User/Group Name *****#
$UserGroupName=$ListRoleAssignment.Member.Name
#**** Get User/Group Type *****#
#Is it a SharePoint Group?
if($ListRoleAssignment.Member.LoginName -eq $NULL)
{
$Type="SharePoint Group"
$UserName=$ListRoleAssignment.Member.Name
}
#Is it a SharePoint User Account or Domain Group?
else
{
$UserName=$ListRoleAssignment.Member.LoginName
#Is it a Domain Group?
if($ListRoleAssignment.Member.IsDomainGroup)
{
$Type="Domain Group"
}
else #if($ListRoleAssignment.Member.LoginName)
{
$Type="SharePoint User"
}
}
#Send the Data to Log file
"<tr><td>$($UserGroupName) </td><td> $($Type) </td><td> $($UserName) </td></tr>" >> PermissionReport.htm
}
}
}
}
}
}
#Dispose web object
$web.dispose()
}
#*** Get Site Collection Permission Levels & Their base Permissions ***#
"</table> <h2> Site Collection's Permission Levels & Their Base permissions </h2><p>" >>PermissionReport.htm
$site.RootWeb.RoleDefinitions | Where-Object {$_.hidden -eq $false} | ForEach-Object {
"<b>Permission Level Name:</b> $($_.Name) <br/> <b> Permissions: </b>$($_.BasePermissions) <br/></p>" >>PermissionReport.htm
}
"</body></html>" >>PermissionReport.htm
#Dispose the objects
$Site.dispose()
}
#Call the function to Generate Report
GeneratePermissionReport "https://sharepoint.crescent.com"
Report Output:
This script uses a HTML File to apply CSS style to the report. You can refer my existing post: SharePoint Users and Groups Permission Report to get the HTML file (table.htm).
BTW, Crescent is my arbitrary domain!
dear rajack,
i get this error when execute the poweshell script, could you help me.
thanks for your help
New-Object : Exception calling “.ctor” with “1” argument(s): “The Web application at http://intranet.publicdomain.com/ could not be found. Verify that
you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping
to the intended application.”
At line:9 char:23
+ return New-Object <<<< Microsoft.SharePoint.SPSite($url)
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Hi Salaudeen after script execution I get the following error message
Get-Content: Could not find path ‘C:\Windows\system32\table.htm’ because it does not exist
The “table.htm” file defines the CSS style and template for the HTML report. You can obtain it from https://www.sharepointdiary.com/2013/03/users-and-groups-permission-report.html and save it to the same location where your script is saved.
Hi I have simple questions: where and how to run the script, Like do i copy it to notepad and run it in sharepoint farm admin shell?. Also, is the output will be generated on a site?
thank you
1. Login to any of your SharePoint On-Premises server. Open “PowerShell ISE”, Copy-paste this script and change the URL in line GeneratePermissionReport “https://sharepoint.crescent.com” to yours, Save the script!
2. Create “Table.htm” file from the table.htm content from https://www.sharepointdiary.com/2013/03/users-and-groups-permission-report.html, on the same path where you saved the script.
3. Hit Run in PowerShell ISE and the Output report will be generated on the same folder where you saved the script.
the script still works! saved me a great deal of time. thank you!
Hi Sal,
Thank you for the awesome script. is there a way to convert the report to csv?
Thank you once again
Thanks for your post,My requirement is i want power shell script to monitor user level access logs weekly/ monthly
Hi Salaudeen, I’m fairly new to SharePoint so your post is awesome. As for this script does it work on SharePoint 2013? I’m looking to extract a list for specific sites and teams. Thanks in advance. FKM
Hi There, It works perfectly in All three version of SharePoint including SharePoint 2013!
Salaudeen – Thanks for the update and your post is really awesome.
-FKM
Where do I define the URL ?
In Line#201 : GeneratePermissionReport “https://sharepoint.crescent.com” , Just replace “https://sharepoint.crescent.com” with Your SharePoint site URL.
Kim, this script targets single subsite only! You can make it run for each subsite in a site collection by slightly modifying the script.
I’m fine having a single script for each script. Like I said i’m just going to schedule it to run automatically. That being said, what do I need to change in the script to get it to run for a specific site not the main site? For example I want to see security for a site called https://mainsite/departments/ITDepartment. So the ITDepartment site sits 2 sub sites deep. Also is there a way to fine grain it deeper to give me who has access at specific folder levels in or documents in document libraries?
Instead of looping through each site in the site collection: foreach($Web in $Site.AllWebs) { }, Change that to $Web = Get-SPWeb “Your-sub-site-URL” in the script. Yes, you can dive deep into List item/document level. Use: $SPListItem.RoleAssignments.
Great I will give it a try! Thank You!!!!
Ok to get a report for a single site I added the following on line 35: #Get the Single Site
$Web = Get-SPWeb “https://MySiteName/SubSiteName” . Then replaced foreach($Web in $Site.AllWebs) with foreach($Web in $Web). Works great. Now I need to add a new section to use $SPListItem.RoleAssignments to get permissions on list item/document levels. Do you have the syntax for this?
This is great been looking for this forever! Is there a way to easily separate it out or only run it for a single subsite/site? I’d like to schedule the PS then have a link to the report posted on each subsite in my site collection. I have around 35 subsites.
Awesome script. You should post it to Spiceworks along with a write up.
If you don’t want to I can post for you and ensure linked back to your site.
The script you wrote is awesome! I’ve been looking for something like this for ever.