MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Wednesday, September 19, 2007

Add Site Administrator

Have you ever found yourself in a situation where you are the Farm administrator and you need to add a user (perhaps yourself) as a site collection administrator but you don't want to be the site collection owner because you need a business user for that, you just want to be added as a site collection administrator? Well, if you've tried to use the stsadm command adduser or tried to use the browser to add yourself (or someone else) as the site collection administrator you probably quickly found out that you can't do it.

For some reason Microsoft chose to not allow farm administrators to be able to add a user as a site administrator - now, this makes no sense because as a farm administrator I have the rights to set any user (including myself) as the site owner, at which point that user is now a site administrator who can now add other users as site administrators. So why didn't Microsoft make it so that a farm administrator can add users as site administrators even if they themselves are not listed as site administrators?

This was really annoying to me and prevented me from being able to set the security on our site collections without having to go through a lot of hoops. So, in order to get around this issue I decided to create a new command called gl-addsiteadmin. The command is pretty simple, it just takes in a user login, user name, and email and then adds the user as a site admin to the specified site collection. If the user you are trying to add as a site admin is not yourself then I just go ahead and temporarily assign your account as a site owner, add the specified user as a site admin, and then reset the site owner (of course if you are already a site admin then I just simply set the user as a site admin - but that scenario can be handled by the adduser command that already exists).

If you are attempting to add yourself as a site admin (and you don't want to be a site owner) then I have to use an internal method called AdministratorOperationMode which sets the SPSite object into a special mode that allows administrative functions to be performed. If you are familiar with the SPSiteAdministration object and have ever disassembled it you would see that the constructor of this object calls this internal method so that it can perform admin functions on the SPSite object. What's really strange is that Microsoft doesn't expose the resultant SPSite object via the SPSiteAdministration object and the AdministratorOperationMode method is not public.

I hope that one day this changes as the only way to perform admin level functions on the SPSite object is to use reflection to call the method manually (unless of course the SPSiteAdministration object already exposes the require property, which, in this case it does not). Because I'm calling an internal method directly via reflection use of this command could put your environment into an unsupported state according to Microsoft so make sure that you understand what the command is doing and what your support options with Microsoft are.

That being said, I feel that you are very safe with this command as the internal method still preserves all the security checks (it makes sure you are in fact a farm administrator) and it is exactly what the SPSiteAdministration object is doing so I can't see the use of this as causing any issues (and the reflection call only comes into play if you are attempting to add your own account as a site admin - if you used a different account to run the command to add your account then you'll never hit the reflection call). The code to do all this is detailed below:

   1: public override int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  output = string.Empty;
   4:  
   5:  InitParameters(keyValues);
   6:  
   7:  if (Params["role"].UserTypedIn && Params["group"].UserTypedIn)
   8:   throw new ArgumentException(SPResource.GetString("IncompatibleParametersSpecified", new object[] { "role", "group" }));
   9:  
  10:  string url = Params["url"].Value.TrimEnd('/');
  11:  string login = Params["userlogin"].Value;
  12:  string email = Params["useremail"].Value;
  13:  string username = Params["username"].Value;
  14:  
  15:  SPWeb web = null;
  16:  
  17:  using (SPSite site = new SPSite(url))
  18:  using (SPSiteAdministration adminSite = new SPSiteAdministration(url))
  19:  try
  20:  {
  21:   web = site.OpenWeb();
  22:  
  23:   login = Utilities.TryGetNT4StyleAccountName(login, web.Site.WebApplication);
  24:  
  25:   if (SPFarm.Local.CurrentUserIsAdministrator() || web.CurrentUser.IsSiteAdmin)
  26:   {
  27:    // First lets get our user object.
  28:    SPUser user = null;
  29:    try
  30:    {
  31:     user = web.AllUsers[login];
  32:    }
  33:    catch (SPException) { }
  34:  
  35:    if (user == null)
  36:    {
  37:     web.SiteUsers.Add(login, email, username, string.Empty);
  38:     user = web.AllUsers[login];
  39:    }
  40:    if (user == null)
  41:     throw new SPException("User cannot be found.");
  42:  
  43:  
  44:    if (web.CurrentUser.IsSiteAdmin)
  45:    {
  46:     // This is the easy part - the calling user is a site admin so we can simply add the user
  47:     user.IsSiteAdmin = true;
  48:     user.Update();
  49:    }
  50:    else
  51:    {
  52:     // This is the hard part - we need to trick the system to allow us to add the user
  53:     // (not sure why Microsoft didn't allow farm administrators to add site admins when 
  54:     // they can change site owners which produces the same affect but what if you don't
  55:     // want to change the site owner?).
  56:  
  57:     try
  58:     {
  59:      // Give it a try first (shouldn't work but what the heck)
  60:      user.IsSiteAdmin = true;
  61:      user.Update();
  62:     }
  63:     catch (SPException)
  64:     {
  65:      if (web.CurrentUser.ID != user.ID)
  66:      {
  67:       // If we are adding a user that is not ourselves then we can simply temporarily set
  68:       // ourselves as a site owner, add the user, and then remove ourselves as the site owner.
  69:       // The reason why we can't use this approach if we are setting ourselves as a site admin
  70:       // is that as soon as we attempt to remove ourselves as an owner it will also make it so
  71:       // we are not longer a site admin.
  72:  
  73:       // Note that we only do this to avoid the reflection call to the internal method at all costs (see below).
  74:  
  75:       string originalSiteOwner = adminSite.OwnerLoginName;
  76:       adminSite.OwnerLoginName = web.CurrentUser.LoginName;
  77:  
  78:       // We've changed the properties of the site object so we need to close and re-open our SPWeb object.
  79:       web.Close();
  80:       web.Dispose();
  81:  
  82:       web = site.OpenWeb();
  83:  
  84:       // Now that we have a new SPWeb object we can re-retrieve the SPUser object which we now know will exist
  85:       // so no need for null checks as the above already certified that it exists.
  86:       user = web.AllUsers[login];
  87:  
  88:       user.IsSiteAdmin = true;
  89:       user.Update();
  90:  
  91:       // Now we need to reset the original owner.
  92:       adminSite.OwnerLoginName = originalSiteOwner;
  93:      }
  94:      else
  95:      {
  96:       // It didn't work because we're not a site admin and we are trying to set ourselves
  97:       // as a site admin which means we can't use the site owner trick from above.
  98:       // Fortunately, Microsoft provides a method that you can call to put the site object
  99:       // into an Admin mode (AdministratorOperationMode).  This is what is called by the
 100:       // SPSiteAdministration object's constructor so that farm administrators can set
 101:       // the owner and other information.  Unfortunately Microsoft doesn't expose the
 102:       // site object via the SPSiteAdministration object nor do they make the AdministratorOperationMode
 103:       // method public (it's marked internal).  So, we have to use reflection to set this flag.
 104:       // In my opinion this is a safe call to make as the property re-checks all the security
 105:       // to make sure that you have appropriate rights to administer the site.  If Microsoft
 106:       // would have made the SPSite object available from the SPSiteAdministration object
 107:       // this would not be necessary.
 108:       
 109:       PropertyInfo adminOpModeProp = site.GetType().GetProperty("AdministratorOperationMode",
 110:                     BindingFlags.NonPublic |
 111:                     BindingFlags.Instance |
 112:                     BindingFlags.InvokeMethod |
 113:                     BindingFlags.GetProperty);
 114:       adminOpModeProp.SetValue(site, true, null);
 115:  
 116:       // We've changed the properties of the site object so we need to close and re-open our SPWeb object.
 117:       web.Close();
 118:       web.Dispose();
 119:  
 120:       web = site.OpenWeb();
 121:  
 122:       // Now that we have a new SPWeb object we can re-retrieve the SPUser object which we now know will exist
 123:       // so no need for null checks as the above already certified that it exists.
 124:       user = web.AllUsers[login];
 125:  
 126:       user.IsSiteAdmin = true;
 127:       user.Update();
 128:  
 129:      }
 130:     }
 131:    }
 132:  
 133:    if (Params["role"].UserTypedIn)
 134:    {
 135:     SPRoleDefinition roleDefinition = null;
 136:     try
 137:     {
 138:      roleDefinition = web.RoleDefinitions[Params["role"].Value];
 139:     }
 140:     catch (ArgumentException) {}
 141:  
 142:     if (roleDefinition == null)
 143:      throw new SPException("The specified role does not exist.");
 144:  
 145:     SPRoleDefinitionBindingCollection roleDefinitionBindings = new SPRoleDefinitionBindingCollection();
 146:     roleDefinitionBindings.Add(roleDefinition);
 147:     SPRoleAssignment roleAssignment = new SPRoleAssignment(user);
 148:     roleAssignment.ImportRoleDefinitionBindings(roleDefinitionBindings);
 149:     web.RoleAssignments.Add(roleAssignment);
 150:    }
 151:    else if (Params["group"].UserTypedIn)
 152:    {
 153:     SPGroup group = null;
 154:     try
 155:     {
 156:      group = web.SiteGroups[Params["group"].Value];
 157:     }
 158:     catch (ArgumentException) {}
 159:  
 160:     if (group == null)
 161:      throw new SPException("The specified group does not exist.");
 162:  
 163:     group.AddUser(user);
 164:    }
 165:   }
 166:   else
 167:   {
 168:    throw new Exception("You need to be a site collection administrator or farm administrator to set this user as a site administrator.");
 169:   }
 170:  }
 171:  finally
 172:  {
 173:   if (web != null)
 174:    web.Dispose();
 175:  }
 176:  
 177:  return 1;
 178: }

The command I created is detailed below.

Using the command is reasonably similar to using the adduser command. The only real difference is that I'm not requiring a role or group name to be specified and you don't have to specify the siteadmin switch (naturally). The syntax of the command can be seen below:

C:\>stsadm -help gl-addsiteadmin

stsadm -o gl-addsiteadmin

Adds a user as a site admin (must be a farm administrator or a current site admin).

Parameters:
        -url <url of site collection>
        -userlogin <DOMAIN\user>
        -useremail <someone@example.com>
        -username <display name>
        [-role <role name> / -group <group name>]

Here’s an example of how to set a user as a site administrator and put them in the "Full Control" role (note that it's usually better to put users in groups then it is to assign roles directly to them):

stsadm –o gl-addsiteadmin -url "http://intranet/" -userlogin "domain\user" -useremail "someone@example.com" -username "Gary Lapointe" -role "Full Control"

25 comments:

Aritz said...

Can I add a group as a site admin? I can add a group as a site owner, I don't understand why I cannot add a group as a site admin.... Thanks.

Gary Lapointe said...

Aritz - sorry for not responding sooner, your comment got lost in my email and I just now found it - to answer your question, you cannot add a group as a site admin - I'm curious as to how you are adding a group as a site owner because you shouldn't be able to do that either. SharePoint needs the primary and secondary owner accounts as well as any other site admins to be users so that it can email use confirmation notices. Now, there is an "Owners" group that gets created and you can add groups to that but that groups is just named owners and is given full control but beyond that there's no signficance to the group name.

Anonymous said...

Can I add a group as a site admin? I can add a group as a site owner, I don't understand why I cannot add a group as a site admin.... Thanks

Anonymous said...

Can't a farm admin add site collection administrators using Central Admin?

Gary Lapointe said...

You can add site owners (which equate to site admins) via central admin and site administrators via the site collection settings pages.

Jay said...

Gary-

When I go to central admin, under Application Management the option is pretty clear that you're editing the site collection administrators, not the owners, and making a change in CA updates the site collection admins viewable from the site settings page of the actual site collection. Since "owners" is simply a SP group that has been granted "Full Control" and since there can actually be many "owners" groups, it would be very misleading to imply there's only one site owners group from within CA. There's more accurately a one or more groups that may or may not be named "owners" that have "full control" permissions in the site (and subsites if permissions inheritance isn't broken).

This isn't to say the value of the extension isn't there, it's just I believe there is a way in the UI to do what you implied there isn't. Updating the site collection admins from within CA doesn't do anything to the "owners" group(s) present in the site collection.

Gary Lapointe said...

You're mis-understanding what I mean by owner (or rather I'm not being very clear about it) - I'm not talking about the Owners group or otherwise giving someone Full Control by setting them as a site admin via the site collections site administrators optoin - the primary and secondary administrators (which is what I'm calling owners) is a "special" role which not only gives the users full control but also makes these particular users the users who receive site usage notifications and quota notifications. There can be only one primary and one secondary owner but there can be many site administrators and many users in the owners group - these are three separate things. Hope that clarifies though I feel I'm probably forgetting something (it was quite a while ago that I worked on all this stuff).

Anonymous said...

Could you zip up the bin or extension and post it so that people can download it and use it?

I think this would be very useful when trying to add large numbers of admins (creating bat files and scriptlets that use stsadm)

Gary Lapointe said...

All of my commands are available via the links at the top of the page. You can download the WSP as well as all the source code.

Anonymous said...

Hello again,

Thank you for your help, I didn't notice the links at the top. I downloaded the moss version and tried to add the solution to my solution store using stsadm -o addsolution.

It returns an object reference not set to an instance of an object error.

Have you tested adding the wsp file?

Gary Lapointe said...

Yes - I deploy using the WSP almost every day. I don't know why are you are getting this error using addsolution.

Anonymous said...

Thank you for your immediate responses. I will continue to investigate on my side, and I appreciate knowing that it should work appropriately.

Gary Lapointe said...

Sorry I can't be of more help for you on this - I'm just really slammed right now and don't have any free time to research it on my end.

DotNetSi said...

Gary, I just used this to change the site admin on a deployment where the content database had been restored from one SharePoint install to another.

Thanks for this excellent add-on - Works very well

Ravi said...

Hi Gary,

Can we add a user to site administrator but provide them less privilege than a regular site administrator.

Gary Lapointe said...

Unfortunately you can't do that.

Sweet Sparky said...

Hi Gary,
Dumb question. What should I download to have these commands run.
Do I need to compile the code for each one. For Ex Add Site Admin one

Thx

Gary Lapointe said...

Go to my downloads page and download the appropriate WSP (MOSS or WSS). Follow the install instructions on the download page.

Thanh-Nữ said...

Hi Gary,
When I execute gl-addsiteadmin as a Farm Administrator, I got the following error: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
Since I am a member from the Farm Administrator group, I don't know why I cannot have access to the site collection. If I have to go to each site collection to insert myself before being able to execute this command, it would take me age, and the paradox is just I would like to use your command to write the script to add myselft as a site admin in all site collections in the farm. I thought I could run this command as a Farm admin, or did I misunderstood something?
Thank you in advance, and kind regards,
TN Leroy

Gary Lapointe said...

Use the built in adduser command to add yourself as a farm admin - then you can use my command to add yourself as a site administrator (you'd be better off just giving yourself full control at the web app level). Here's an example of using the adduser command:
stsadm -o adduser -url "http://localhost:%CENTRALADMIN_PORT%" -userlogin %ACCT_SPADMIN% -group "Farm Administrators" -username %ACCT_SPADMIN_NAME% -useremail %ACCT_SPADMIN_EMAIL%

Chels said...

This may be a bit of a redundant question, but I'm still getting a handle on Moss 2007.

Anyway, I've been tasked with overhauling the mess that is the SharePoint site at my new job. This includes moving documentation, checking in what may end up being 100+ files, as well as various other organizing tasks. I've found I can do mostly everything I need by just having full control on the various team sites, etc. Except any useful kind of checked out document management.

After some research, it has been brought to my attention that being a site administrator might be the best bet for me, since I will basically be in charge of all content and structure once I start the re-org work (that, plus some of the other abilities that come with being the administrator).

The thing is, I have no idea how you would change someone's access to be an admin for all of the sub sites. Unfortunetly, I'm the most "advanced" user in my area, so I'd basically need to provide step-by-steps in order to change my access.

Sorry for the long-winded, round-about question, but access issues have been stymieing me for a while, and it's getting frustrating. Any thoughts?

Gary Lapointe said...

Have yourself made as owner of the site collection or have a current site collection administrator make you a site collection administrator (either action will give you full control over the entire site collection).

Sean said...

Hi Gary,

Do you have a command that would remove an account from the site collection admin group? We have to remove 3 or 4 accounts from 90 site collections so doing it manually would be...time consuming.

Daniel said...

Hi, I also want to know how to remove a site collection administrator with script. Not the first and second site administors. The users that are added in the site collection settings.

Gary Lapointe said...

Your best bet will be to use powershell to remove users from groups.