Local account creation

This article explains how to create local account on a device which is not managed by Active Directory. These devices are assumed using at several dozens or hundreds places like Windows kiosk mode device.

Previous article explains [DataAccessLayer] class, this class provides logging feature. So the file name modify to ‘Logging.cs’. Then Visual Studio ask you “change refer to DataAccessLayer to Logging ?”, but it is ‘NOT’ need change. But you have to change declare of the [DataAccessLayer] class to ‘partial’.

    public partial class DataAccessLayer
    {
        ...
    }

This article explain management feature of local account, so this feature is implemented at [DataAccessLayer] class too. And file name is ‘AccountManager.cs’

>> Previous article’s sample code

This figure represents creating [DataAccessLayer] partial class of ‘AccountManager.cs’ added at ‘Features’ solution folder.

・Two ways of account creation

Perhaps, the most popular way to create local accounts is using cmdlets in Windows PowerShell, in C# programming uses ‘System.DirectoryServices.DirectoryEntry’ namespace and ‘Invoke’ method of ‘DirectoryEntry’ object, or use ‘PrincipalContext’ object of ‘System.DirectoryServices.AccountManagement’ namespace and ‘save’ method of ‘UserPrincipal’ object.

These two ways are little bit different approaches. In case of ‘DirectoryEntry’ object, user object is com object and also group object is com object, it is both ‘DirectoryEntry’ object in C# aspect, and creation or deleting and so on are all using ‘Invoke’ method.

In other hands, ‘System.DirectoryServices.AccountManagement’ namespace provides ‘UserPrincipal’ object and ‘GroupPrincipal’ object. ‘UserPrincipal’ object provides [DisplayName] property, [Name] property, [Description] property, [UserCannotChangePassword] property, [SetPassword] method and [Save] method. And ‘GroupPrincipal’ object provides [Members] property, it represents members collection of the group, so use [Add] method to add an user object to the member of a group, and then, use [Save] method of the object to commit operations of the group modifying. the steps using ‘System.DirectoryServices.AccountManagement’ is easy to understand because it is similar to the management UI of Windows OS.

    user.SetPassword(string.Empty);
    user.DisplayName = "somebody name";
    user.Name = "somebody name";
    user.Description = string.Empty;
    user.UserCannotChangePassword = false;
    user.PasswordNeverExpires = true;
    user.Save();

>>sample code

・Create ‘CreateUsers’ method

Partial class ‘DataAccessLayer’ aim to provide ‘CreateUsers’ method. The method argues user collection and responds logs collection.

    public partial class DataAccessLayer
    {
        PrincipalContext context
        {
            get { return new PrincipalContext(ContextType.Machine); }
        }
        public List<Log> CreateUsers(List<Tuple<string, List<string>>> users)
        {
            List<Log> result = new List<Log>();
            Log log = null;
            UserPrincipal user = null;
            List<string> groups = null;
            try
            {
                foreach (var username in users)
                {
                    user = UserPrincipal.FindByIdentity(context, username.Item1);
                    if (user == null)
                    {
                        user 
                          = new UserPrincipal(context, username.Item1, username.Item1,true);
                    }
                    user.SetPassword(string.Empty);
                    user.DisplayName = username.Item1;
                    user.Name = username.Item1;
                    user.Description = string.Empty;
                    user.UserCannotChangePassword = false;
                    user.PasswordNeverExpires = true;
                    user.Save();
                    groups = username.Item2;
                    if (groups == null) groups = new List<string>();
                    if (groups.Where(g => g == "Users").Count() == 0) groups.Add("Users");
                    SetUserGroups(user, groups);
                }
                //log "Users created"
                return result;
            }
            catch (Exception ex)
            {
                //log "Users creation fault reason : {0}", ex.Message
                return result;
            }
        }
    }

The argument ‘users’ of above code includes a collection of ‘user’ object, this ‘user’ object has user name as key and groups name collection as value into ‘Tuple’ type, so argument ‘users’ enumelates for ‘FindByIdentity’ method to create ‘UserPrincipal’ object, then if it represents ‘null’, use ‘new’ to create target ‘UserPrincipal’. After correct ‘UserPrincipal’ object acquired, it is added to specific groups.

・Create ‘SetUserGroups’ method

The arguments of this method are ‘user’ object as ‘UserPrincipal’ type and groups name collection of the user. And responds log collection as execution result.

    public List<Log> SetUserGroups(UserPrincipal user, List<string> groups)
    {
        List<Log> result = new List<Log>();
        Log log = new Log();
        try
        {
            foreach (string groupname in groups)
            {
                log = new Log();
                GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupname);
                group.Members.Add(user);
                group.Save();
                //log "User[{0}] registered Group[{1}]", user.Name, groupname
            }
            //log "Groups of user[{0}] registering complete", user.Name
            return result;
        }
        catch (Exception ex)
        {
            //log "User[{0}] creation fault reason : {1}", user.Name, ex.Message
            return result;
        }
    }

The scenario of this article is not create new group, So if your scenario needs new group, you should check ‘null’ with ‘group’ object as ‘GroupPrincipal’ type which acquired by using ‘FindByIdentity’ method. After correct ‘group’ object acquired, add user to the members of the group use ‘Add’ method of ‘Members’ property. Then use ‘Save’ method to commit the operations of the group.

・Call account management with setting users object

The last step is call ‘CreateUsers’ method of the [DtataAccessLayer] class. The scenario of this article aim to four account.

    DataAccessLayer dataAccessLayer = new DataAccessLayer();
    ...
    List<string> groups = new List<string>();
    List<Tuple<string, List<string>>> users = new List<Tuple<string, List<string>>>();
    groups.Add("Users");
    groups.Add("Remote Desktop Users");
    groups.Add("Administrators");
    var user = new Tuple<string, List<string>>("superUser", groups);
    users.Add(user);
    groups = new List<string>();
    groups.Add("Users");
    groups.Add("Administrators");
    user = new Tuple<string, List<string>>("maintenanceOperator", groups);
    users.Add(user);
    groups = new List<string>();
    groups.Add("Users");
    groups.Add("Remote Desktop Users");
    user = new Tuple<string, List<string>>("appOperator", groups);
    users.Add(user);
    groups = new List<string>();
    groups.Add("Users");
    user = new Tuple<string, List<string>>("appUser", groups);
    users.Add(user);
    dataAccessLayer.CreateUsers(users);

About takao

I'm Microsoft MVP since June 2010.