Managing SharePoint Site User Memberships in Multiple Groups Using SPServices

I got an email yesterday from Geoff Oliver. He said he had done something pretty useful with SPServices and wondered if I would be interested in seeing it.

I manage about 115 groups in a single site collection…and that number is expected to grow.  I found that when a new user came on board or changed duty positions, getting them into the right SP groups was slow and cumbersome through the SP interface.

Using the SPServices libraries, I was able to create a simple interface to add/remove a single user to/from multiple groups at once.  When you identify/select a user, it will show you two select lists. The right side will list all of the groups the current user is a member of while the left box shows all the groups the user is NOT a member of.  Between the two select lists are buttons to ‘move’ the groups from one side to the other for the identified user (while modifying their memberships appropriately in the process).  The select boxes are configured to allow multiple select so you can usually perform the maintenance in just a couple clicks.  The code fits neatly into a CEWP.

Of course I wanted to see it. Geoff’s code sounded exactly like the kind of thing that I think SPServices is good for: a useful solution that solves a business problem better than SharePoint out of the box without needing to deploy anything to the server.

Geoff describes himself as:

…a Civilian Project Manager for the Air Force, developing a SharePoint site to assist a large organization with information management and integration with Microsoft Office (sharing/synchronizing data between SharePoint sites and Word/Excel/Access files).  I’ve been doing MS Office automation (using VBA) for about 15 years now and SharePoint site development for 7.

The code uses a number of Users and Groups Web Service operations that are wrapped in SPServices:

  • GetUserCollectionFromSite
  • GetGroupCollectionFromUser
  • GetGroupCollectionFromSite
  • AddUserToGroup
  • RemoveUserFromGroup

Here’s Geoff’s code. It’s amazingly compact and gets the job done well.

$(document).ready(function() {
  //Populate the users pick list
  var strHTMLSiteUsers = "";
  $().SPServices({
      operation: "GetUserCollectionFromSite",
      async: false,
      completefunc: function(xData, Status) {
        $(xData.responseXML).find("User").each(function() {
          strHTMLSiteUsers += "<option value='" + $(this).attr("LoginName") + "'>" + $(this).attr("Name") + "</option>";
        });
        $("#my_SiteUsers").append(strHTMLSiteUsers);
      }
  });
  RefreshGroupLists();
});

function RefreshGroupLists(){
  var strHTMLAvailable = "";
  var strHTMLAssigned = "";
  var arrOptionsAssigned = new Array();
  var intOpts = 0;
  var booMatch;
  var booErr = "false";

  $("#my_SPGroupsAssigned").html("");
  $("#my_SPGroupsAvailable").html("");

  if($("#my_SiteUsers").attr("value") == 0){
    alert("You must select a user");
    return;
  }

  //Populate the Groups Assigned
  $().SPServices({
      operation: "GetGroupCollectionFromUser",
      userLoginName: $("#my_SiteUsers").attr("value"),
      async: false,
      completefunc: function(xData, Status) {
        $(xData.responseXML).find("errorstring").each(function() {
          alert("User not found");
          booErr = "true";
          return;
        });
        $(xData.responseXML).find("Group").each(function() {
          strHTMLAvailable += "<option value='" + $(this).attr("Name") + "'>" + $(this).attr("Name") + "</option>";
          arrOptionsAssigned[intOpts] = $(this).attr("Name");
          intOpts = intOpts + 1;
        });
        $("#my_SPGroupsAssigned").append(strHTMLAvailable);
      }
  });

  //Populate available site groups
  if(booErr == "false"){
    $().SPServices({
        operation: "GetGroupCollectionFromSite",
        async: false,
        completefunc: function(xData, Status) {
          $(xData.responseXML).find("Group").each(function() {
            booMatch = "false";
            for (var i=0;i<=arrOptionsAssigned.length;i++){
              if($(this).attr("Name") == arrOptionsAssigned[i]){
                booMatch = "true";
                break;
              }
            }
            if(booMatch == "false"){
              strHTMLAssigned += "<option value='" + $(this).attr("Name") + "'>" + $(this).attr("Name") + "</option>";
            }
          });
          $("#my_SPGroupsAvailable").append(strHTMLAssigned);
        }
    });
  }
}

function AddGroupsToUser(){
  var i;

  if($("#my_SiteUsers").attr("value") == 0){
    alert("You must select a user");
    return;
  }

  if($("#my_SPGroupsAvailable").val() == null){
    alert("You haven't selected any groups to add");
    return;
  }
  else{
    var arrGroups = $("#my_SPGroupsAvailable").val();
    for (i=0;i<arrGroups.length;i++){
      $().SPServices({
          operation: "AddUserToGroup",
          groupName: arrGroups[i],
          userLoginName: $("#my_SiteUsers").attr("value"),
          async: false,
          completefunc: null
      });
    }
    RefreshGroupLists();
  }
}

function RemoveGroupsFromUser(){
  var i

  if($("#my_SiteUsers").attr("value") == 0){
    alert("You must select a user");
    return;
  }

  if($("#my_SPGroupsAssigned").val() == null){
    alert("You haven't selected any groups to remove");
    return;
  }
  else{
    var arrGroups = $("#my_SPGroupsAssigned").val();
    for (i=0;i<arrGroups.length;i++){
      $().SPServices({
          operation: "RemoveUserFromGroup",
          groupName: arrGroups[i],
          userLoginName: $("#my_SiteUsers").attr("value"),
          async: false,
          completefunc: null
      });
    }
    RefreshGroupLists();
  }
}

and the associated markup:

<table align="center">
  <tr>
    <td colspan="3" style="text-align:center">
      <font style="font-weight:bold">Select a User:&nbsp;&nbsp;&nbsp;</font>
      <select id="my_SiteUsers" style="width:350px;" onchange="RefreshGroupLists()"></select>
    </td>
  </tr>
  <tr>
    <th class='ms-vh2'>Available Groups</th>
    <th></th>
    <th class='ms-vh2'>Assigned Groups</th>
  </tr>
  <tr>
    <td class='ms-vb2'>
      <select id="my_SPGroupsAvailable" style="width:250px;height:450px;" multiple="multiple"></select>
    </td>
    <td>
      <button id="my_AddGroupsToUser" style="width:80px;" onclick="AddGroupsToUser()">&gt;&gt;</button><br><br>
      <button id="my_RemoveGroupsFromUser" style="width:80px;" onclick="RemoveGroupsFromUser()">&lt;&lt;</button></td>
    <td class='ms-vb2'>
      <select id="my_SPGroupsAssigned" style="width:250px;height:450px;" multiple="multiple"></select>
    </td>
  </tr>
</table>

And here’s the net result. It’s a simple little form that does exactly what Geoff said it would. All I had to do to get it running in my environment was to change the references to the script files to point where I have them stored. Otherwise, it worked with no modification whatsoever.

image

This is the sort of thing that may belong in SPServices. Of course, you can simply copy and use the code above, but perhaps some more options and additional functionality would make it even more useful.  What do you think? Is this something you’d use?

And thanks for sharing, Geoff.

Similar Posts

58 Comments

  1. Hi Marc I am trying to replicate this solution in SP2013 online, but I am having issues. The lists and dropdown are populating but if I click either button to add or remove a group, the page refreshes and the change has not been applied. As well as this, the lists do not update when the user is changed in the dropdown.

    Do you know of any differences between SPServices in 2013 online vs 2010 that would be causing this?

    Thanks.

    1. Ian:

      I can’t think of any particular reason why this wouldn’t work on SharePoint Online, but I also haven’t tried it. What you’ll want to do is look at the transactions in the developer tools in your favorite browser to see if you are getting errors.

      M.

    2. Actually, I just dropped this into a page in SharePoint Online, and it looks like the is not being set properly. In Chrome I get an alert that there was an error. I think the issue is that the LoginName in SharePoint Online is claims-based (i:0#.f|membership|[email protected]), and not account-based (domain\username). The older SOAP services don’t understand these logins and that causes the error.

      M.

  2. Hi Mark, this is not working on my sharepoint online site. i am using the below references
    jquery-1.12.3.min.js
    jquery.SPServices-2014.02.js
    jquery.SPServices-2014.02.min.js

    user dropdown returns no value

    1. @Santhosh:

      As with anything you find on my blog (or anyone else’s), you mileage may vary. You may need to do some debugging and alter the script for your own particular needs and version of SharePoint.

      One obvious thing: you’re including SPServices twice; once minimized and once not.

      M.

  3. That gets the lists to all populate, but, in my experience, the same change also needed to be applied on the other lines where UserLoginName attr occurs, in order for the add/remove buttons to actually perform their function.

  4. Hi.. I need a list user in a specific group using SPservices in an array..

    List of user in a a group … Very very urgent

  5. Hi.. i want to user SPservices to upload and download file. I am using html as front end and javascript where spservices is used to add and extract data from list….

    now my challenge is i want to upload different type of document for each row of data saved in list.. I will be storing data in sperate document library .

    Can you tell me how to upload and retrieve document
    Upload will be done at specific folder in the document library

    Thanks for help..

    Need the solution urgently

    1. @Puneet:

      There are examples for most of this either here on my blog or in the SPServices docs. This is older tech and few people are using it these days – for good reason. If you’re on SharePoint 2013 or higher, you should be using REST rather than SPServices.

      M.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.