SharePoint Users and Groups Permission Analysis Report for Site Collection
Requirement: For security audit purpose, had to generate a comprehensive users and groups security report for entire site collection. Some of the sub-sites, some of the lists & libraries are with unique permission.
Solution: Lets use PowerShell with little HTML & CSS to generate a users and groups permission Report!
On executing the PowerShell script, will generate a HTML file as in the below screen with:
- Table of content for all Sub-sites in the site collection
- List of site collection administrators
- Users who has access on the site
- Site’s Groups granted access
- Members of each group which has access to the site.
- Lists with unique permissions and its users & groups.
To get all users and permissions (Roles granted directly and their groups), We can simply use this PowerShell code:
Get-SPWeb "https://sharepoint.crescent.com/sites/operations" | Get-SPUser | select LoginName, @{name="Exlicit Permissions";expression={$_.Roles}}, @{name="Permissions given via Groups";Expression={$_.Groups | %{$_.Roles}}} ,Groups | format-Table -Wrap -AutoSize
But to fetch few more details and to generate report, I use the below code:
SharePoint Users and Permission Analysis Report:
Here goes our HTML template Code: In run time, The data being generated will be merged with the HTML code to get a formatted report in HTML format. Â
Save the below content as “Table.htm” file in the same path where you save PowerShell script.
<html>
<head>
<!-- Javascript goes in the document HEAD -->
<script type="text/javascript">
function altRows(id){
if(document.getElementsByTagName){
var table = document.getElementById(id);
var rows = table.getElementsByTagName("tr");
for(i = 0; i < rows.length; i++){
if(i % 2 == 0){
rows[i].className = "evenrowcolor";
}else{
rows[i].className = "oddrowcolor";
}
}
}
}
window.onload=function(){
altRows('alternatecolor');
}
</script>
<!-- CSS goes in the document HEAD or added to your external stylesheet -->
<style type="text/css">
body{
font-family: Calibri;
height: 12pt;
}
table.altrowstable {
border-collapse: collapse;
font-family: verdana,arial,sans-serif;
font-size:11px;
color:#333333;
border-width: 1px;
border-color: #a9c6c9;
border: b1a0c7 0.5pt solid;
}
table.altrowstable th {
border-width: 1px;
padding: 5px;
background-color:#8064a2;
border: #b1a0c7 0.5pt solid;
font-family: Calibri;
height: 15pt;
color: white;
font-size: 11pt;
font-weight: 700;
text-decoration: none;
}
table.altrowstable td {
border: #b1a0c7 0.5pt solid; font-family: Calibri; height: 15pt; color: black; font-size: 11pt; font-weight: 400; text-decoration: none;
}
.oddrowcolor{
background-color: #e4dfec;
}
.evenrowcolor{
background-color:#FFFFFF;
}
</style>
</head>
<body>
PowerShell Script to Generate Users and Groups Permission Report:
[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 GenerateUserAccessReport()
{
#Site Collection URL - Mandatory parameter
param( [Parameter(Mandatory=$true)] [string]$SiteCollectionURL)
#Get the site collection
$Site= Get-SPSite $SiteCollectionURL
#Append the HTML File with CSS into the Output report
$Content=Get-Content -Path "table.htm" > PermissionReport.htm
"<h2> $($Site.RootWeb.Title) - Users & Groups Permission Report</h2>" >> PermissionReport.htm
#Table of Contents
"<h3> List of Sites</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
}
#Site Collection Administrators Heading
"</table><br/><b>Site Collection Administrators</b>" >> PermissionReport.htm
"<table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr>" >> PermissionReport.htm
#Write CSV (TAB Separated File) Header
"<th>User Account ID </th> <th>User Name </th></tr>" >> PermissionReport.htm
#Get All Site Collection Administrators
$Site.RootWeb.SiteAdministrators | sort $_.Name | ForEach-Object {
"<tr><td> $($_.LoginName) </td> <td> $($_.Name)</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
}
#Get the Users & Groups from site which has unique permissions - TOP sites always with Unique Permissions
if($Web.HasUniqueRoleAssignments -eq $True)
{
#*** Get all the users granted permissions DIRECTLY to the site ***
"<b>Site Users and Groups</b><table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr>" >> PermissionReport.htm
"<th>Users/Groups </th> <th> Type </th><th> User Name </th> <th>Permissions</th></tr>" >> PermissionReport.htm
foreach($WebRoleAssignment in $Web.RoleAssignments )
{
#*** Get User/Group Name *****#
$UserGroupName=$WebRoleAssignment.Member.Name
#**** Get User/Group Type *****#
#Is it a SharePoint Group?
if($WebRoleAssignment.Member.GetType() -eq [Microsoft.SharePoint.SPGroup])
{
$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 #if($WebRoleAssignment.Member.LoginName)
{
$Type="SharePoint User"
}
}
#Get the Permissions assigned to Group/User
$WebUserPermissions=@()
foreach ($RoleDefinition in $WebRoleAssignment.RoleDefinitionBindings)
{
$WebUserPermissions += $RoleDefinition.Name +";"
}
#Send the Data to Log file
" <tr> <td> $($UserGroupName) </td><td> $($Type) </td><td> $($UserName) </td><td> $($WebUserPermissions)</td></tr>" >> PermissionReport.htm
}
#****** Get the Group members *********#
"</table></br> " >>PermissionReport.htm
if($GroupExistsFlag -eq $true)
{
"<b>Group Users</b><table class='altrowstable' id='alternatecolor' cellpadding='5px'><tr>" >>PermissionReport.htm
foreach($WebRoleAssignment in $Web.RoleAssignments )
{
#Is it a SharePoint Group?
if($WebRoleAssignment.Member.GetType() -eq [Microsoft.SharePoint.SPGroup])
{
"<th>Group: $($WebRoleAssignment.Member.Name)</th></tr> " >> PermissionReport.htm
foreach($user in $WebRoleAssignment.member.users)
{
#Send the Data to Log file
" <tr><td></td> <td> $($user.Name) </td><td> $($user.LoginName) </td><td> $($user.Email)</td><tr>" >> PermissionReport.htm
}
}
}
}
#Reset Group Exists Flag
$GroupExistsFlag=$false
}
#******** Check Lists with Unique Permissions ********/
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>" >> PermissionReport.htm
"<th>Users/Groups </th><th> Type </th><th> User Name </th><th> Permissions</th></tr>" >> PermissionReport.htm
#Get all the users granted permissions to the list
foreach($ListRoleAssignment in $List.RoleAssignments )
{
#*** Get User/Group Name *****#
$UserGroupName=$ListRoleAssignment.Member.Name
#**** Get User/Group Type *****#
#Is it a SharePoint Group?
if($ListRoleAssignment.Member.GetType() -eq [Microsoft.SharePoint.SPGroup])
{
$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"
}
}
#Get the Permissions assigned to Group/User
$ListUserPermissions=@()
foreach ($RoleDefinition in $ListRoleAssignment.RoleDefinitionBindings)
{
$ListUserPermissions += $RoleDefinition.Name +";"
}
#Send the Data to Log file
"<tr><td>$($UserGroupName) </td><td> $($Type) </td><td> $($UserName) </td><td> $($ListUserPermissions)</td></tr>" >> PermissionReport.htm
}
"</table>" >>PermissionReport.htm
}
}
}
"</body></html>" >>PermissionReport.htm
}
#Call the function to Get Users & groups Report
GenerateUserAccessReport "https://sharepoint.crescent.com/sites/compliance"
Report output:
For SharePoint Online Permission report, use: SharePoint-Online Site Collection Permission Report using PowerShell
Getting error PermissionReport.htm file is being used by another process.
out-file : The process cannot access the file ‘XXXXScriptPermissionReport.htm’ because it is being used by another process.
At XXXScriptGetUserAccessReportSP13.ps1:190 char:9
+ CategoryInfo : OpenError: (:) [Out-File], IOException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Make sure the permissionreport.htm file is not opened in Browser!
Team,
can you please help me out with audiences home page content
because we have different web parts associated and how will pull all audiencing report
Thanks,
Venkat
Hello, I desire to subscribe for this weblog to get most up-to-date
updates, thus where can i do it please assist.
Will this script work with SP 2013? Thx!
Yes, It works on SharePoint 2010, SharePoint 2013 and SharePoint 2016.
Hi Salaudeen,
Is this script able to be easily modified to run on SharePoint Online / 365? I’ve tried to run this and I’m given the following error.
New-Object : Cannot find type [Microsoft.SharePoint.SPSite]: verify that the assembly containing this type is loaded.
At line:9 char:13
+ return New-Object Microsoft.SharePoint.SPSite($url)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
Hi Paul,
No, this script isn’t written for SharePoint Online. I’ll publish the script for SharePoint Online soon.
Hi, thanks for sharing, im looking for script to generate permission matrix for SharePoint Online too!
Here is the Permission Report script for SharePoint Online: SharePoint Online: Site Collection Permissions Report using PowerShell
Thank you very much
This is an AMAZING piece of work. You saved me days of work.
thanks!
In the function, GenerateUserAccessReport, I’m getting an error when it tries to pull the Site Collection Administrators.
The variable ‘$_’ cannot be retrieved because it has not been set.
At line:55 char:46
+ $Site.RootWeb.SiteAdministrators | sort $_.Name | ForEach-Object {
+ ~~
+ CategoryInfo : InvalidOperation: (_:String) [], RuntimeException
+ FullyQualifiedErrorId : VariableIsUndefined
The line referenced in the error is
$Site.RootWeb.SiteAdministrators | sort $_.Name | ForEach-Object {
The script continued and finished, but the Site Collection Administrator section of the report was empty. I changed
sort $_.Name
to
sort $Site.RootWeb.SiteAdministrators.Name
and it ran with no errors and the Site Collection Admin section was filled in.
Any idea why it’s not taking the piped input for $_? I’m running it from ISE started with Run as Administrator, and I’m running SP 2013 & PS 5.0, if that makes any difference.
For Folders which have unique permission its not able to get the URL and throwing error as below
Method invocation failed because [System.String] doesn’t contain a method named ‘op_Division’.
At E:ScriptsPermissionReport.ps1:220 char:69
+ $FolderURL=$folder.ParentList.ParentWeb.URL/ <<<< $folder.Url + CategoryInfo : InvalidOperation: (op_Division:String) [], RuntimeException + FullyQualifiedErrorId : MethodNotFound
I’m sorry for double post but I found solution to the error message. Now, I’ve got a repport file, but it’s empty. I have only cells with color and title, but i’ve no entry, and no powershell error message…
An idea?!
Are you running this script as “Farm Administrator” with FULL control permissions? Make sure you choose “Run as Administrator” too.
I get an error when I run your script :
+ GenerateUserAccessReport <<<< https://global + CategoryInfo : NotSpecified: (:) [GenerateUserAccessReport], Ta rgetInvocationException + FullyQualifiedErrorId : System.Reflection.TargetInvocationException,Gene rateUserAccessReport Have U got an idea? Thks.
Nothing is generated for me, I saved the files into two parts one is Table.htm and another one is GenerateUserAccessReport.ps1 , I ran the command as GenerateUserAccessReport “https://xxxxxxxxx” but it is not generating any file there.
Try Changing these lines: Instead of: >>PermissionReport.htm, change it to: >>c:PermissionReport.htm or something like that. Also, Make sure you are running this script from a SharePoint WFE as a Farm Admin!
I get an error when running powershell, cannot find path “table.htm” because it does not exist.
Create “Table.htm” with the content provided, on the same path where this script located.
Saluadeen-
This is a great report and it covers everything I am looking for. I’m very familiar with PowerShell however I’m have no experience with HTML. How do I get these scripts to work together?
Thanks in advance
Hi there,
The html code applies formating to the report here. Just save the html code as “table.htm” on the same path where you save the script, and execute the script.
Great…I did save the script in the path.
I ran the GenerateUserAccessReport along with the site URL but nothing happened. The SP2010 Mgmt did not error out. I checked the directory where the PowerShell script and the table.htm are located and did not see any new files.
Here are some more question..
Where to I go to see the report? Am I suppose to go to a particular URL or local path?
Does the PowerShell script need to be update with my site collection URL?
I did not see anywhere in the script that required to be update.
Thank you again
mmjr,
You will get the Output report PermissionReport.htm on the same path where you save this script.
Only thing you need to change is the Site collectin URL passed to function:GenerateUserAccessReport
Really nice job