Panopto API 301: Creating users and groups from AD

Return to the Panopto API index page

A Panopto problem that has existed from the beginning is

  1. Southampton has lots of information about students in Blackboard
  2. Southampton has lots of different information about students in Active Directory
  3. Panopto sees Blackboard/Student and ActiveDirectory/Student as a different person

The code for this is improved on page 401 (web based)

So this code syncs an active directory group to a Panopto internal group containing Blackboard students. Best of both worlds!

The main reason for doing this is so we can make a single folder containing all staff, which we then create a drop box for. This then makes a secure user folder for every staff member in the University using just the one Panopto folder.

Credit (although it’s hard to know who the original credit should go to) for the Active Directory looping code to marc_s from StackOverflow.

We take nearly all of the code for searching for a user

// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, adGroup);

// if found....
if (group != null)
{
    // iterate over members
    foreach (Principal p in group.GetMembers())
    {
        Console.WriteLine("{0}: {1}", p.StructuralObjectClass, p.Name);

        if (p.StructuralObjectClass == "user")
        {
            // do whatever you need to do to those members
            UserPrincipal theUser = p as UserPrincipal;

            if (theUser != null)
            {

And add some auth information and PanoptoUserManagement details in

// work with Panopto users
IUserManagement userMgr = new UserManagementClient();

// Panopto Auth
PanoptoUserManagement.AuthenticationInfo userAuth = new PanoptoUserManagement.AuthenticationInfo()
{
    UserKey = "api",
    Password = "s2ezupajePhasaP5"
};

, some constants at the top

const string instanceName = @"BBDev\";
const string adGroup = "jfStaff";
const string panAdGroupName = "ADSync-" + adGroup;

and in a minute we’re going to need to add some users to a list, so we make that

List<Guid> userList = new List<Guid>();

Running this code now will bring out all of the users in the AD group.

Panopto needs a User.ID (that’s a Guid) to add a user to a group, which means that the user must exist to add them to a group.

We check if the user exists, and if they do we remember their GUID in the list

User panUser = userMgr.GetUserByKey(userAuth, instanceName + p.Name);
if (panUser != null && !panUser.UserId.Equals(Guid.Empty))
{
    Console.WriteLine("User {0} exists in Panopto as {1}", p.Name, panUser.UserId);
    userList.Add(panUser.UserId);
}

And if they don’t, we need to make them. This should be easy as we have all their details from AD

if (String.IsNullOrEmpty(theUser.GivenName) || String.IsNullOrEmpty(theUser.Surname) ||
    String.IsNullOrEmpty(theUser.EmailAddress))
{
    Console.WriteLine("{0} doesn't have enough details to make a user account", p.Name);
}
else
{
    PanoptoUserManagement.User generatedUser = new User()
    {
        UserKey = instanceName + p.Name,
        FirstName = theUser.GivenName,
        LastName = theUser.Surname,
        SystemRole = SystemRole.None,
        UserBio = String.Empty,
        Email = theUser.EmailAddress,
        EmailSessionNotifications = false
    };

Most of these fields are required, so I’ve made sure that there are valid given names, surnames and email addresses before making the user.

Now the user exists, we can make the user and remember it’s new User.ID for the list

Guid generatedUserGuid = userMgr.CreateUser(userAuth, generatedUser, String.Empty);
panUser = generatedUser;
userList.Add(generatedUserGuid);

Console.WriteLine("User {0} added to Panopto ", instanceName + p.Name);

Once we have our users we can add them to the group. But does it exist yet?

Group[] panGroupArray = userMgr.GetGroupsByName(userAuth, panAdGroupName);
Group panGroup;

if (panGroupArray.Length == 0)
{

GetGroupsByName returns an array (as you can have duplicate group names), but in this instance we’re going to presume that the first result is right.

Warning: As I write this there is a bug that causes creating internal groups to not show. My code reflects this

if (panGroupArray.Length == 0)
{
    // WARNING: There is currently an issue that causes internal groups to not show 
    // within the Panopto UI, unless made within the Panopto UI
    // 
    // Because of this you need to create the group in the UI first and then use
    // this API to fill in the users of that group
    // http://support.panopto.com/documentation/video-management/internal-groups
    //
    //panGroup = userMgr.CreateInternalGroup(userAuth, panAdGroupName, userList.ToArray());

    Console.WriteLine("Nothing was updated. You must create the group within the Panopto UI first!");
}

Once the bug is fixed the code can be removed from the comments. If we’ve made the group manually (as the comments suggest we do) then we can just add the users to the group

else
{
    panGroup = panGroupArray[0];
    userMgr.AddMembersToInternalGroup(userAuth, panGroup.Id, userList.ToArray());
    Console.WriteLine("Group {0} updated: {1}", panGroup.Name, panGroup.Id);
}

Another warning: Running AddMemberToInternalGroup to add a user who was already in the group will cause duplicate rows. As an example, if you ran this for “All 5000 staff” as a cronjob once per hour, there would be 44 million rows in the groups database in one year. You should therefore write more code to check the user is not already in the group.

You can now use the group in the UI.

Log in as API and make a new empty folder, share it with your AD group as viewers then make a drop box. Rename the drop box something like “Your personal Panopto folder” and you now have a secure user folder for everyone in your AD group.

Full code below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using ConsolePanoptoAdToPanopto.PanoptoUserManagement;

namespace ConsolePanoptoAdToPanopto
{
    internal class Program
    {
        private static void Main(string[] args)
        {

            // Define variables
            const string instanceName = @"BBDev\";
            const string adGroup = "jfStaff";
            const string panAdGroupName = "ADSync-" + adGroup;

            List<Guid> userList = new List<Guid>();
            
            // set up domain context
            PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

            // find the group in question
            GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, adGroup);

            // work with Panopto users
            IUserManagement userMgr = new UserManagementClient();

            // Panopto Auth
            PanoptoUserManagement.AuthenticationInfo userAuth = new PanoptoUserManagement.AuthenticationInfo()
            {
                UserKey = "api",
                Password = "s2ezupajePhasaP5"
            };

            // if found....
            if (group != null)
            {
                // iterate over members
                foreach (Principal p in group.GetMembers())
                {
                    Console.WriteLine("{0}: {1}", p.StructuralObjectClass, p.Name);

                    if (p.StructuralObjectClass == "user")
                    {
                        // do whatever you need to do to those members
                        UserPrincipal theUser = p as UserPrincipal;

                        if (theUser != null)
                        {
                            User panUser = userMgr.GetUserByKey(userAuth, instanceName + p.Name);
                            if (panUser != null && !panUser.UserId.Equals(Guid.Empty))
                            {
                                Console.WriteLine("User {0} exists in Panopto as {1}", p.Name, panUser.UserId);
                                userList.Add(panUser.UserId);
                            }
                            else
                            {
                                if (String.IsNullOrEmpty(theUser.GivenName) || String.IsNullOrEmpty(theUser.Surname) ||
                                    String.IsNullOrEmpty(theUser.EmailAddress))
                                {
                                    Console.WriteLine("{0} doesn't have enough details to make a user account", p.Name);
                                }
                                else
                                {
                                    PanoptoUserManagement.User generatedUser = new User()
                                    {
                                        UserKey = instanceName + p.Name,
                                        FirstName = theUser.GivenName,
                                        LastName = theUser.Surname,
                                        SystemRole = SystemRole.None,
                                        UserBio = String.Empty,
                                        Email = theUser.EmailAddress,
                                        EmailSessionNotifications = false
                                    };

                                    Guid generatedUserGuid = userMgr.CreateUser(userAuth, generatedUser, String.Empty);
                                    panUser = generatedUser;
                                    userList.Add(generatedUserGuid);

                                    Console.WriteLine("User {0} added to Panopto ", instanceName + p.Name);
                                }
                            }
                            
                        }
                    }
                }

                // Does the Panopto group exist?
                Group[] panGroupArray = userMgr.GetGroupsByName(userAuth, panAdGroupName);
                Group panGroup;

                if (panGroupArray.Length == 0)
                {
                    // WARNING: There is currently an issue that causes internal groups to not show 
                    // within the Panopto UI, unless made within the Panopto UI
                    // 
                    // Because of this you need to create the group in the UI first and then use
                    // this API to fill in the users of that group
                    // http://support.panopto.com/documentation/video-management/internal-groups
                    //
                    //panGroup = userMgr.CreateInternalGroup(userAuth, panAdGroupName, userList.ToArray());

                    Console.WriteLine("Nothing was updated. You must create the group within the Panopto UI first!");
                }
                else
                {
                    panGroup = panGroupArray[0];
                    userMgr.AddMembersToInternalGroup(userAuth, panGroup.Id, userList.ToArray());
                    Console.WriteLine("Group {0} updated: {1}", panGroup.Name, panGroup.Id);
                }
            }

            Console.WriteLine("Press Enter to Exit");
            Console.ReadLine();
        }
    }
}

Return to the Panopto API index page

One Comment

  1. Joris Desseyn

    Dear, Do you know or there is a rename (if user had misspelled name) API function in Panopto ?
    Or if not, if you can move the conent from a misspelled user tot the correctly spelled one ?

    5 years ago

Leave a Reply

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