0

I want to create a user with a program (C#, .net 4.5):

String Domain =  System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
...
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain))
{
    if (UserPrincipal.FindByIdentity(pc, IdentityType.UserPrincipalName, USER) != null)
    {
        .. error message ..
    ...

At least, this works for Domains. But creating a local user (creating on a computer belonging to a domain or a stand alone computer) did not work (Executing user is am Administrator - manual adding a user works).

I've tried to set the Domain-Name to

  • System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().HostName;
  • "localhost"
  • "127.0.0.1"

But then I got the following error message at FindByIdentity:

System.DirectoryServices.AccountManagement.PrincipalServerDownException: 
Mit dem Server konnte keine Verbindung hergestellt werden. ---> 
System.DirectoryServices.Protocols.LdapException: Der LDAP-Server ist nicht verfügbar.

(German, I added line breaks) Roughly translated: "Could not connect to Server -> LDAP server is not accessible."

I also changed PrincipalContext to

using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, Domain))

(and tested all domains as above). Then I got the following error message at FindByIdentity:

System.IO.FileNotFoundException: Der Netzwerkpfad wurde nicht gefunden.

(German) Roughly translated: "Network path not found".

(All tested at Windows 10 (in a domain) and a "clean" domain-less Windows 7.)

What can I do to make this working AND a just having one code path for all cases.

(Hint I also tested removing the domain name from PrincipalContext and adding it to the user "@" + Domain.)

Edit

using (PrincipalContext pc = new PrincipalContext(ContextType.Machine))
{
    if (UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, USER) != null)
    {
        .. error message ..
    ...

works for local access on a non domain machine.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Ralph Erdt
  • 537
  • 4
  • 16
  • Please try `PrincipalContext pc = new PrincipalContext(ContextType.Machine, "127.0.0.1")`, i.e., localhost or the machine name for Machine context type(`System.Environment.MachineName`). Also make sure that your program is running with administrative privileges for creating local user on the system. I am hopeful! – Am_I_Helpful Jan 20 '19 at 14:22
  • Thanks, this works. But I've to write a branch: If the domain is a local domain ('127.*", ".", "", machine name, (I'm sure, this list can - has to - be extend)) then use as mentioned in "edit", otherwise the normal way. I doesn't like that, because this is error-prone. Is there a way this works in all circumstances? – Ralph Erdt Jan 21 '19 at 08:00
  • Hi Ralph. In my opinion, the only way left is to ask user initially where they want to create user - local system or domain, and then apply the branch logic as you stated in your previous comment. I don't think there is a common way than checking using an if-else. Please explain what do you think would be a challenge! – Am_I_Helpful Jan 21 '19 at 08:11
  • I just want so at a text box "Domain" in the program (installer / setup). Like in every other windows login. Adding a Radio / Checkbox "Local / Domain" did not look so .. "shiny". – Ralph Erdt Jan 21 '19 at 08:33
  • I get `DirectoryServices.DirectoryServicesCOMException (0x80072030): There is no such object on the server` error after create user in AD, when I try **GetGroups or modify ADProperties**. Seems not found the username created. I have *Domain*, I use `SamAccountName` (_eg. name1.surname1_), not `UserPrincipalName` (_eg. name1.surname1@domain.com_),or distinguished name. Wait until User is known? – Kiquenet Oct 26 '22 at 08:35
  • Sample: `var originalSamAccountName = samAccountName; var fixSamAccountName = samAccountName.Substring(0, samAccountName.Length > 20 ? 20 : samAccountName.Length); ...new UserPrincipal(ctx).UserPrincipalName = fixSamAccountName + "@DOMAIN.com", ...SamAccountName = fixSamAccountName` – Kiquenet Oct 26 '22 at 08:49
  • @Kiquenet: "Wait until User is known?" Yes. See my code below. "// Now Wait until User is known" – Ralph Erdt Oct 28 '22 at 07:22

1 Answers1

2

As requested my current code to create users if local or domain:

static internal bool CreateUser(String Domain, out String UserName, out String Pwd, out String error)
{
    bool localhost = (String.IsNullOrWhiteSpace(Domain) || Domain.Trim().Equals("localhost", StringComparison.InvariantCultureIgnoreCase) || Domain.Trim().StartsWith("127.") || Domain.Trim().Equals(System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().HostName.Trim(), StringComparison.InvariantCultureIgnoreCase));
    Console.WriteLine("Domain: " + Domain + (localhost ? " (localhost)" : ""));

    UserName = null;
    Pwd = null;
    try
    {
        ContextType cType = localhost ? ContextType.Machine : ContextType.Domain;
        Domain = localhost ? null : Domain;
        IdentityType iType = localhost ? IdentityType.SamAccountName : IdentityType.UserPrincipalName;

        using (PrincipalContext pc = new PrincipalContext(cType, Domain))
        {
            // Search for an non existent User
            int nr = 0;
            while (UserPrincipal.FindByIdentity(pc, iType, USER + (nr > 0 ? "" + nr : "")) != null) 
            {
                nr++;
                if (nr > 1000)
                {
                    error = "Could not create a user name - all possible names are in use. Please delete unnessesary users.";
                    return false;
                }
            } 

            UserName = USER + (nr > 0 ? "" + nr : "");
            Pwd = Membership.GeneratePassword(64, 8);

            String desciption = "User for bla!"

            using (UserPrincipal up = new UserPrincipal(pc))
            {
                up.SamAccountName = UserName;
                if (!localhost)
                {
                    up.GivenName = UserName;
                    up.UserPrincipalName = UserName;
                }
                up.DisplayName = "User";
                up.Description = desciption;
                up.SetPassword(Pwd);
                up.Enabled = true;
                up.UserCannotChangePassword = true;
                up.PasswordNeverExpires = true;
                up.Save();
            }

            int max = 600;
            // Now Wait until User is known
            while (UserPrincipal.FindByIdentity(pc, iType, UserName) == null)
            {
                Thread.Sleep(100);
                if (max-- <= 0)
                {
                    error = "User was not created in wait time.";
                    return false;
                }
            }
        }
        error = null;
        return true;
    }
    /*catch (PrincipalExistsException)
    {
        // Should not happen now
        error = null;
        return false;
    }*/
    catch (UnauthorizedAccessException e)
    {
        error = "Executeing user has insufficent permissions. Need the permission to create user in the domain: \"" + Domain + "\":\n" + e;
        return false;
    }
    catch (Exception e)
    {
        error = e.ToString();
        return false;
    }
}

Hope this helps one or two people..

Ralph Erdt
  • 537
  • 4
  • 16