Sunday, March 3, 2013

SharePoint Users and Groups Permission Analysis Report

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 "http://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 "http://sharepoint.crescent.com/sites/compliance"

Report output:
SharePoint Users and Groups Permission Report



You might also like:
SharePoint Usage Reports
Usage reports, collaboration and audit for SharePoint.
Document SharePoint Farm
Automatically generate SharePoint documentation.
*Sponsored


Check out these SharePoint products:

13 comments :

  1. Really nice job

    ReplyDelete
  2. 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

    ReplyDelete
    Replies
    1. 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.

      Delete
    2. 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

      Delete
    3. 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

      Delete
  3. I get an error when running powershell, cannot find path "table.htm" because it does not exist.

    ReplyDelete
    Replies
    1. Create "Table.htm" with the content provided, on the same path where this script located.

      Delete
  4. 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 "http://xxxxxxxxx" but it is not generating any file there.

    ReplyDelete
    Replies
    1. 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!

      Delete
  5. I get an error when I run your script :

    + GenerateUserAccessReport <<<< http://global
    + CategoryInfo : NotSpecified: (:) [GenerateUserAccessReport], Ta
    rgetInvocationException
    + FullyQualifiedErrorId : System.Reflection.TargetInvocationException,Gene
    rateUserAccessReport

    Have U got an idea?
    Thks.

    ReplyDelete
  6. 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?!

    ReplyDelete
    Replies
    1. Are you running this script as "Farm Administrator" with FULL control permissions? Make sure you choose "Run as Administrator" too.

      Delete
  7. 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:\Scripts\PermissionReport.ps1:220 char:69
    + $FolderURL=$folder.ParentList.ParentWeb.URL/ <<<< $folder.Url
    + CategoryInfo : InvalidOperation: (op_Division:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    ReplyDelete

Please Login and comment to get your questions answered!

You might also like:

Related Posts Plugin for WordPress, Blogger...