Sunday, May 25, 2008

Enumerate Role Assignments to retrieve Groups and Users Permissions in a Windows Sharepoint Services 3.0 or MOSS Site

Introduction:

The following .aspx page with C# in line code, enumerates all the roles assignments of a Windows SharePoint Services 3.0 or MOSS site collection and displays in DebugView Window for each web site:
  • The role member and reports if it is a Group or an User.
  • If it is a group, displays the number of users in the Group and the users list.
  • In any case, displays the Permissions list.
Why to use it?

When you want to check the users and the groups present in a Site Collection web sites and their role, it can take time doing it by browsing "People and Group" administration pages for each web site. It would be nice to display all the information in a single report. The following code sample will give you this kind of report, and it will be easier for you to reorder Users and Groups using it.

How to use it?

Copy the following code in an .aspx file.
Paste the file in the LAYOUTS diectory.
Start DebugView.
Browse the page with site administrator permissions from any site using the usual Application Page url (...myWebSite/_layouts/thisPage.aspx).
Check Report in DebugView window.

Code Sample:
<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
 
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" %>
 
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="System.Diagnostics" %>
 
<asp:Content ID="Content1" ContentPlaceHolderID="PlaceHolderMain" runat="server"> 
<asp:Label ID="lblMessage" runat="server" />
    <script runat="server">       
        protected string WriteIsRootWeb(SPWeb aWeb){
            if (aWeb.IsRootWeb)
            {
                return " (This is the Site Collection Root Web)";
            }
            else
            {
                return "";
            }
        }
 
        public void Page_load(object sender, EventArgs e)
        {
            bool isAgroup = true;
            SPGroup aGroup=null;
 
            foreach (SPWeb aWeb in SPContext.Current.Site.AllWebs)
            {
 
                Debug.WriteLine("\n******************************************");
                Debug.WriteLine("Roles Assignments Report on web site " + aWeb.Title + WriteIsRootWeb(aWeb));
                Debug.WriteLine("******************************************\n");
 
 
                Debug.WriteLine("List of " + aWeb.Title + " Groups");
 
                foreach (SPGroup Group in aWeb.Groups)
                {
                    Debug.WriteLine(Group.Name + " ID: " + Group.ID);
                }
 
                Debug.WriteLine("");
 
                foreach (SPRoleAssignment aRole in aWeb.RoleAssignments)
                {
                    isAgroup = true;
                    Debug.WriteLine("*************\n");
                    try
                    {
                        aGroup = aWeb.Groups.GetByID(aRole.Member.ID);
                    }
                    catch
                    {
                        isAgroup = false;
                    }
 
                    if (isAgroup)
                    {
                        Debug.WriteLine("Group Id : " + aRole.Member.ID.ToString() + " | " + " Principal Name : " + aRole.Member.Name);
 
                        Debug.WriteLine("Number of users:" + aWeb.Groups.GetByID(aRole.Member.ID).Users.Count);
                        aGroup = aWeb.Groups.GetByID(aRole.Member.ID);
                        Debug.WriteLine("");
                        Debug.WriteLine("List of " + aGroup.Name + " users");
 
                        foreach (SPUser aUser in aGroup.Users)
                        {
                            Debug.WriteLine("\t - " + aUser.Name);
                        }
                        Debug.WriteLine("");
                    }
                    else
                    {
                        Debug.WriteLine("User Id : " + aRole.Member.ID.ToString() + " | " + " Principal Name : " + aRole.Member.Name);
                    }
 
                    Debug.WriteLine("\nList of permissions for " + aRole.Member.Name + ":");
 
                    for (int i = 0; i < aRole.RoleDefinitionBindings.Count; i++)
                    {
                        Debug.WriteLine(aRole.RoleDefinitionBindings[i].BasePermissions.ToString());
                    }
 
                    Debug.WriteLine("");
                }
            }
            lblMessage.Text="Your report has been generated in DebugView";
        }
    </script>
</asp:Content >

if you want a much more complete report for SharePoint users and groups Permissions, Role Assignments within a SharePoint Site Collection, in HTML fomat generated inside an Application Page, see...

Enumerate Role Assignments to retrieve Groups and Users Permissions - Generating a complete report

if you want to know more about DebugView, see...

Use DebugView in Windows SharePoint Services 3.0 programming.



12 comments:

est said...

Hi Marc, I was browsing the net to research some info and found your site. I'm doing smt simliar to what you've posted, but its not by using "DebugView". I need to create a web application( a web page) for WSS 3.0 in C#, being able to retrieve all the groups in the sharepoint site, and knowing which users are in the group, also knowing their permission rights. Is it okay if you could provide some guides to that? That will be alot appreciated. Thanks in advance!

Marc Charmois said...

Hi est,
if you replace all the Debug.Writeline in the page by Response.Write, you should have a good first approach for what you want to develop... :-)

Good Luck.

Marc

est said...

Hi Marc,
I've made amendment to the codes and able to run. But the output I got doesnt seems to be the same "group" as my site.

(Central Administration > People and Groups)
These are the groups in my site:
BUILTIN\administrators
Farm Administrators
HelpGroup
Testing Group

But the one I retrieve look like:
Group Id: 3 | Principal Name : Team Site Owners
Number of users:2
List of Team Site Owners users
USERNAME : W2003EER\administrator
LIST OF PERMISSION FOR : Team Site Owners:
FullMask
Group Id: 4 | Principal Name : Team Site Visitors
Number of users:0
List of Team Site Visitors users
LIST OF PERMISSION FOR : Team Site Visitors:
ViewListItems, OpenItems, ViewVersions, and etc
Group Id: 5 | Principal Name : Team Site Members
Number of users:0
List of Team Site Members users
LIST OF PERMISSION FOR : Team Site Members:
ViewListItems, OpenItems, ViewVersions, and etc

Realised the Groups I retrieve is
Team Site Members
Team Site Owners
Team Site Visitors instead, do you have any idea why?

Please advice, thanks alot!

Marc Charmois said...

Hi est,

- Farm Administrators
- HelpGroup
are the standard groups for the Central Administration Site.
- BUILTIN\administrators
is referenced as a Group in SharePoint Central Administration but is not really a SharePoint group but an Active Directory group added to your SharePoint Central Administration site.
If you click on BUILTIN\administrators link in the page "People and Groups: All Groups " you will notice that it is actually a SharePoint User.

But be careful, Central Administration and your Site are TWO different sites, and it is normal that the Groups and Users for these sites are different.

Your site groups are:
- Team Site Owners
- Team Site Members
- Team Site Visitors

that are the standard SharePoint groups added automatically by SharePoint to a team site when you create this kind of site by using the standard "Team Site" Site Definition provided by SharePoint.

So the result you have is perfectly normal.

By the way there was a mistake in my code that made not all the groups to be recognized as groups, and I have corrected it.

Hope this helps.

Marc

est said...

Thanks Marc, you're right about that(the Central Administration part). And I amended the codes already, it work fine too.

Actually, now I'm trying to retrieve "group", user belong to after user enter their userid. From there I need to retrieve what permission rights the group have. Please advice, will appreciate it. Thanks alot!

Marc Charmois said...

hi est,

I have just published a post presenting an Application page that generates a really complete report on Users, Groups, their Roles, Permissions, at Web Site level, for all the Site Collection Web sites, plus an amazing embedding of a SharePoint control that tracks Cross-Site permissions but only for Groups.

Enumerate Role Assignments to retrieve Groups and Users Permissions - Generating a complete report Hope that helps.

Marc

est said...

Thanks for the post, really. Just a little background of what I'm trying to do. It's actually a page with 4 buttons. Upon clicking the 1st button (retrieve group) will retrieve all the groups in my site. The group name will appear in the 1st listbox. User will have to select the group name in the 1st listbox and then click on the 2nd button (retrieve user), and all the user ids for that group will appear in the 2nd listbox.

Theres also a textbox for user to input their userid to check which group they belong to and to see the permission rights for the group.
So when user enter their userid in the textbox and click the 3rd button (search). The group user belongs to, will appear in 1st listbox. User will now select the desired group and click on the 4th button (retrieve permission) to check the permission rights for that group.

This is the brief idea of what I'm trying to achieve..

But face a lil problem, cos whatever group that I select, it seems that their permission rights always remain as FULL CONTROL. Could you advice on that? Thanks

Anyway I also intend to place a hyperlink in the page in order to generate the report (which is the wonderful post of yours)

Look forward to your reply, thanks!

Marc Charmois said...

Hi est,

I have understood what you are trying to develop as a functionnality, and it is very interesting.
But there is a concern you have to pass through.
Normally you must have administrator privileges to browse all the groups and users inside for a portal.
So I am afraid that an usual user will not be authorized to execute code to populate your 1st listbox.
Maybe the best you can do with it, is to make a user able to retrieve its own groups and ID. But I am not sure it will be easy...

You are really sure you want any user to be able to see all groups and all other users inside? What is about if a user notice that a colleague has more permissions than himself... :-)

If you really want to do that you can generate the complete report in xml format using a piece of code running with administrator privileges, store it somewhere in SharePoint, and make your list boxes take data from the xml.
The xml report may have been generated by a SharePoint Job, or you can try to catch events when an administrator is changing permissions within the portal and regenerate the xml report at this time.
Lot of work...


Regarding your question about the result you are obtaining. I think you get always FULL CONTROL because there should have a piece of code in your page that is testing the current user permissions.
So as you are the current user and are the administrator of the site you get always FULL CONTROL.
It is my first explanation.

If you want to test your page as in real life, you have to create local users and assign group to them in SharePoint.
Then you have to open a New page in Internet Explorer, open your sharePoint site, and use "Sign in with a different user" link to sign in as one of the previously created local users.
You can that way open several sessions with several users and test your cases.
This does not work with FireFox because you can only open one session with FireFox while opening several pages.

last, if you could have real Active Directory User Accounts for testing, it would be much better, because sometimes results regarding authorizations, permissions, roles assignements, are different using computer local users account and real Active Directory user accounts.
(of course the computer I am talking about is the SharePoint development server and as a SharePoint developer, you are developing directly on this computer).

The best of the best is to make yourself a virtual machine with a role of Domain Controller and to install SQL Server (2005 is better in that case), then install a SharePoint Farm environment on the Virtual Machine.
And you will have the best environment to test your permissions page and all the pages involved with SharePoint authorizations, permissions, users, groups,etc. concerns
in the future.

Hope this helps.

Marc

Yahav said...

Hi, nice post, I have small tip not related to the contents.

I'm not sure how efficient is the method GetByID of the Groups collection, but calling it three times instead of once for no reason can't be good thing.

First it's called inside the try..catch block:
aGroup = aWeb.Groups.GetByID(aRole.Member.ID);

All good. However, later in the code:
Debug.WriteLine("Number of users:" + aWeb.Groups.GetByID(aRole.Member.ID).Users.Count);
Better practice is to use the existing variable:
Debug.WriteLine("Number of users:" + aGroup.Users.Count);

And yet again there is this line:
aGroup = aWeb.Groups.GetByID(aRole.Member.ID);
After writing the "Number of users:" stuff... another unnecessary call to that method.

If there is good reason for all those then I'll be glad to know, otherwise using the existing variable will improve the code efficiency and serve as better practice.

Marc Charmois said...

Hi Yahav,

thank you for having examined my code.
You are right, I should have used the previous variable in both the cases you mentioned.

I have written and posted this example too fast.

Thank you for your corrections.

cheers.

Marc

Anonymous said...

Hi guys,

I have followed the steps and once i access the URL i got:
unknown error.

please any idea ?

Marc Charmois said...

Hi,

Did you activate the displaying of errors within SharePoint?
If not open the web.config of the Web Application
Locate CallStack, and set it to true
Locate CustomError, end set it to Off
Locate the Debug attribute of Compilation, and set it to true.
You should have a more complete error message.
Hope this helps.

Marc