SharePoint 2010 Security Reporting using PowerShell

SharePoint makes it pretty easy to assign very granular permissions to various elements of a SharePoint site. The problem is that managing those granular permissions over the long haul can be a pretty daunting task. Sure, you start off with the best of intentions: create groups, assign permissions to groups, put users in groups. But it doesn’t take long for the number of groups to balloon, and it seems like someone’s always bound and determined to assign a specific permission to just one user (you know, it’s “easier” than making a new group for just that one person). Before long, you’ve got a mess on your hands.

Reporting on who has access to what can seem impossible. Do you actually have to go through every element in SharePoint and see who has permission? Sounds like a full-time job – and a super-boring one at that.

But SharePoint 2010, at least, is Windows PowerShell-enabled. Does Windows PowerShell make it any easier to report on those security permissions?

SharePoint and PowerShell

Everything in this article applies to SharePoint 2010; earlier versions don’t provide PowerShell support. And even within SharePoint 2010, you won’t find 100% complete PowerShell support, although it’s likely that future versions of SharePoint will offer ever-increasing coverage for what can be done with PowerShell.

I typically don’t install the SharePoint cmdlets for PowerShell on my administrative workstation, instead preferring to work directly “on” a SharePoint server via PowerShell Remoting. In a domain environment, simply run this on the SharePoint server from within its local PowerShell console:

Enable-PSRemoting

 

Then, on my computer, I open up PowerShell and run:

Enter-PSSession -computername SharePoint01

 

Assuming, of course, that’s the correct computer name for the SharePoint server. Once I’m in, I need to load the SharePoint cmdlets. That’s because I’m not able to directly access the Start menu shortcut (the “SharePoint 2010 Management Shell”) that pre-loads them for me.

Add-PSSnapin Microsoft.SharePoint.PowerShell

 

Now I’m ready to go.


Figure 1: Loading the SharePoint cmdlets

You’ll Need a Bit of Help

SharePoint’s PowerShell snapin includes cmdlets for accessing Webs, lists, list items, and so forth, and these will provide the basis for our ability to check users’ permissions. We’ll start by retrieving a specific securable object, which is simply some SharePoint element that’s capable of having security permissions applied to it. From there, we’ll execute the object’s GetUserEffectivePermissionInfo() method, which returns a permission object that we can look at to see role definition bindings, permission levels, and so forth. Once we have those details, we have to enumerate the role assignments to see which role has which permission.


Figure 2: GetUserEffectivePermissionInfo PowerShell function

Sound easy? Didn’t think so. Fortunately, Google turned me on to http://blog.falchionconsulting.com/index.php/2010/04/discovering-who-has-access-to-sharepoint-2010-securable-objects/, which includes a neat function that does all of this for us. I’ll include that function here:


function Get-SPUserEffectivePermissions([object[]]$users, [Microsoft.SharePoint.SPSecurableObject]$InputObject) {

begin { }

process {

if ($_ -isnot [Microsoft.SharePoint.SPSecurableObject]) {

throw "A valid SPWeb, SPList, or SPListItem must be provided."

}

$so = $_

foreach ($user in $users) {

# Set the users login name

$loginName = $user

if ($user -is [Microsoft.SharePoint.SPUser] -or $user -is [PSCustomObject]) {

$loginName = $user.LoginName

}

if ($loginName -eq $null) {

throw "The provided user is null or empty. Specify a valid SPUser object or login name."

}

# G et the users permission details.

$permInfo = $so.GetUserEffectivePermissionInfo($loginName)

# Determine the URL to the securable object being evaluated

$resource = $null

if ($so -is [Microsoft.SharePoint.SPWeb]) {

$resource = $so.Url

} elseif ($so -is [Microsoft.SharePoint.SPList]) {

$resource = $so.ParentWeb.Site.MakeFullUrl($so.RootFolder.ServerRelativeUrl)

} elseif ($so -is [Microsoft.SharePoint.SPListItem]) {

$resource = $so.ParentList.ParentWeb.Site.MakeFullUrl($so.Url)

}

# Get the role assignments and iterate through them

$roleAssignments = $permInfo.RoleAssignments

if ($roleAssignments.Count -gt 0) {

foreach ($roleAssignment in $roleAssignments) {

$member = $roleAssignment.Member

# Build a string array of all the permission level names

$permName = @()

foreach ($definition in $roleAssignment.RoleDefinitionBindings) {

$permName = $definition.Name

}

# Determine how the users permissions were assigned

$assignment = "Direct Assignment"

if ($member -is [Microsoft.SharePoint.SPGroup]) {

$assignment = $member.Name

} else {

if ($member.IsDomainGroup -and ($member.LoginName -ne $loginName)) {

$assignment = $member.LoginName

}

}

# Create a hash table with all the data

$hash = @{

Resource = $resource

"Resource Type" = $so.GetType().Name

User = $loginName

Permission = $permName -join ", "

"Granted By" = $assignment

}

# Convert the hash to an object and output to the pipeline

New-Object PSObject -Property $hash

}

}

}

}

end {}

}

 

I know, it’s crazy. I saved this into a script module named SPSecurity, so that I could easily load it into the shell. I copied the module to my SharePoint server, loaded it by using Import-Module, and then decided to give it a whirl.


Figure 3: Exporting User Permissions Results

What Else Can You Do?

Another option would be to check out the robust third-party market for SharePoint security utilities, with a focus on tools that can read all of SharePoint’s security into a database or something, and then quickly run reports on it.

Honestly, this is the same approach I’ve found myself using for running permissions reports on nearly anything in Windows, including Exchange Server. These products simply don’t store their permissions in a central place; instead, permissions are assigned directly on securable objects, and you have to examine every single one to see who has permissions to it. Then you have to unravel nested group memberships and the like – it’s just slow. Reporting tools tend to pull all of that information into a database (generally on a periodic basis, to keep updated), which brings all the permissions into a single location that’s easier to report from.

“SharePoint Security Reports” is a good search engine query to start with, and I think you’ll find that this offers a more practical and usable approach – especially when you start adding in capabilities like automatically-generated (and e-mail delivered) reports and other conveniences.

What are you using to keep track of SharePoint permissions? A script, or a third-party tool – or nothing at all?