Get User Roles in Sharepoint 2007

Today’s script will show how to get a report of user access to webs and/or subwebs in a Sharepoint Site Collection.  It is a good idea to know who has what access to the different areas of your Sharepoint site.  Sometimes people get added for some reason, but then no longer need that access and are never removed.  The script below will use the Sharepoint API and Powershell to generate a report that you can use to see if your role definitions are up-to-date.

I went through a couple of revisions on this script as I wrote it, partially because I started to make it more complicated than it needed to be.  I am sure that there are probably some other things that can be done to enhance this script, but for now, this will do what I need.  Perhaps in a later post I can revisit and add some features.

As with any script dealing with the Sharepoint API, you need to make sure that the Sharepoint assembly is loaded.  I use the “[void]” prefix to prevent the console from displaying the load output.  This command is located in the BEGIN block of the script so that it runs once each time the script is run.

[void][reflection.assembly]::LoadWithPartialName("Microsoft.Sharepoint")

The main part of the script is pretty simple.  All I am doing is creating the SPSite object and then sending the OpenWeb() result up to the Get-Web function.  The $site variable is an incoming parameter for the script.  This code, as well as the supporting functions in this script, are located in the PROCESS block.  Using the PROCESS block allows the script to accept pipeline input for the $site parameter and the PROCESS block will execute for each site that is passed in to the script.

$rootsite = [Microsoft.Sharepoint.SPSite]$site
Get-Web -web $rootsite.OpenWeb()

When the SPWeb object is opened, it is sent to the Get-Web cmdlet which does a lot of the heavy lifting in the script.  The Get-Web cmdlet will look at each web and then iterate through each subweb recursively until there are no more webs.

Function Get-Web
 {
  Param
   (
    [Microsoft.Sharepoint.SPWeb]$web
   )
  
  Write-Verbose "Getting webs for $($web.url)"
  foreach ($subWeb in $web.webs)
  {
   Get-Web $subWeb
   $subWeb.Dispose()
  }
  
  Write-Verbose "Sending Web to get User Access..."
  Get-UserAccess $web
  
 }

As the Get-Web recursion starts to unwind, each SPWeb object is sent to the Get-UserAccess function.  The Get-UserAccess function checks to see if a “Role” parameter was entered.  If it was entered, the function will only grab Role Assignments for a specific Role (e.g. “Full Control”) otherwise, it will grab all role assignments on the current SPWeb object.  Once it has the necessary role assignments, the function will iterate over each one.  If the role assignment is for a user, the user object is sent to the Out-User function to create the output object.  If the role assignment is a group, the function will unroll all the members of the Sharepoint group and send each member to the Out-User function.

Function Get-UserAccess
 {
  Param
   (
    [Microsoft.Sharepoint.SPWeb]$web
   )
  
  Write-Verbose "Checking if role(s) were entered"
  if ($role)
  {
   Write-Verbose "Looking for $role"
   $roleAssignments = $web.RoleAssignments | Where-Object {$_.RoleDefinitionBindings | Where-Object{$Role -contains $_.Name }}
  }
  else
  {
   Write-Verbose "No role selected..."
   $roleAssignments = $web.RoleAssignments
  }
  
  Write-Verbose "Cycle through each role assingment on the web..."
  foreach ($roleAssignment in $roleAssignments)
  {
   If ($roleAssignment.Member.Sid)
   {
    Write-Verbose "Role Assignment is a user."
    Out-User -user $roleAssignment.Member -web $web -RoleDefinition ($roleAssignment | select -expand RoleDefinitionBindings | select -expand Name)
   }
   else
   {
    Write-Verbose "Role Assignment is a group..."
    foreach ($user in $roleAssignment.Member.Users)
    {
     Out-User -user $user -web $web -RoleDefinition ($roleAssignment | select -expand RoleDefinitionBindings | select -expand Name)
    }
   }
  }
 }

Since working with Powershell means working with objects, I have designed this script to output objects as well.  I have chosen a few key fields that I think are relevant, but you can also look at the Sharepoint API documentation to find other properties that you might want to include as your output.  In my testing, I found that the output was way too wide to fit, so if you are using this, you might want to use one of the Export-* or Out-File cmdlets to get your data to a text file that can be used easier.

The Out-User function simply accepts the SPUser and SPWeb objects.  It then creates a hashtable with the values of the properties that will be in the custom object.  It creates the object with the hashtable values and then outputs the object to the pipeline.  Modifying the hashtable for your own use is where the power comes in.  You can change the values that are output on the object to grab as much or as little as you need.

Function Out-User
 {
  Param
   (
    [Microsoft.Sharepoint.SPUser]$user,
    [Microsoft.Sharepoint.SPWeb]$web,
    [string]$roleDefinition
   )
  
  Write-Verbose $user
  Write-Verbose $web
  $UserProperties = @{
   Name=$user.Name;
   LoginName=$user.LoginName;
   SiteAdmin=$user.IsSiteAdmin;
   Email=$user.email;
   Role=$roleDefinition;
   Web="$($web.url)$($web.ServerRelativeUrl)"
  }
  
  $UserObject = New-Object PSObject -Property $UserProperties
  Write-Output $UserObject
 }

I have tested this script on a Sharepoint 2007 environment and had good success with it.  Looking at the API, it would appear that this would also work on a Sharepoint 2010 installation, but I don’t have that environment to test on.  I would be interested in feedback from anyone who can try this on a 2010 with the results.  I would also be interested in hearing if this script helps you do your job better.   Here is the full source code of the script.


[CmdletBinding()]
Param(
 [Parameter(ValueFromPipeline=$true,
 ValueFromPipelineByPropertyName=$true,
 Mandatory=$true)]
 [string]$site,
 [string[]]$Role
 )
BEGIN{
 [void][reflection.assembly]::LoadWithPartialName("Microsoft.Sharepoint")
}

PROCESS{

 Function Out-User
 {
  Param
   (
    [Microsoft.Sharepoint.SPUser]$user,
    [Microsoft.Sharepoint.SPWeb]$web,
    [string]$roleDefinition
   )
  
  Write-Verbose $user
  Write-Verbose $web
  $UserProperties = @{
   Name=$user.Name;
   LoginName=$user.LoginName;
   SiteAdmin=$user.IsSiteAdmin;
   Email=$user.email;
   Role=$roleDefinition;
   Web="$($web.url)$($web.ServerRelativeUrl)"
  }
  
  $UserObject = New-Object PSObject -Property $UserProperties
  Write-Output $UserObject
 } #Function Out-User

 Function Get-UserAccess
 {
  Param
   (
    [Microsoft.Sharepoint.SPWeb]$web
   )
  
  Write-Verbose "Checking if role(s) were entered"
  if ($role)
  {
   Write-Verbose "Looking for $role"
   $roleAssignments = $web.RoleAssignments | Where-Object {$_.RoleDefinitionBindings | Where-Object{$Role -contains $_.Name }}
  }
  else
  {
   Write-Verbose "No role selected..."
   $roleAssignments = $web.RoleAssignments
  }
  
  Write-Verbose "Cycle through each role assingment on the web..."
  foreach ($roleAssignment in $roleAssignments)
  {
   If ($roleAssignment.Member.Sid)
   {
    Write-Verbose "Role Assignment is a user."
    Out-User -user $roleAssignment.Member -web $web -RoleDefinition ($roleAssignment | select -expand RoleDefinitionBindings | select -expand Name)
   }
   else
   {
    Write-Verbose "Role Assignment is a group..."
    foreach ($user in $roleAssignment.Member.Users)
    {
     Out-User -user $user -web $web -RoleDefinition ($roleAssignment | select -expand RoleDefinitionBindings | select -expand Name)
    }
   }
  }
 } #Function Get-UserAccess

 Function Get-Web
 {
  Param
   (
    [Microsoft.Sharepoint.SPWeb]$web
   )
  
  Write-Verbose "Getting webs for $($web.url)"
  foreach ($subWeb in $web.webs)
  {
   Get-Web $subWeb
   $subWeb.Dispose()
  }
  
  Write-Verbose "Sending Web to get User Access..."
  Get-UserAccess $web
  
 } #Function Get-Web

###BEGIN MAIN CODE###
 $rootSite = [Microsoft.Sharepoint.SPSite]$site
 Get-Web -web $rootSite.OpenWeb()
  
}

MSDN SPWeb Documentation
MSDN SPUser Documentation

Advertisements
This entry was posted in Advanced Function, PSObjects, Sharepoint 2007 and tagged , , , , , , , , . Bookmark the permalink.