Good morning, Using C# we are trying to create a new windows 8 / 8.1 user on windows store application.
But the code using below is not working, because the namespace "System.DirectoryServices.AccountManagement" is not available.
public UserPrincipal CreateNewUser(string a_userName, string sPassword)
{
if (!UserExists(a_userName))
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
oUserPrincipal.Name = a_userName;
oUserPrincipal.SetPassword(sPassword);
//User Log on Name
oUserPrincipal.UserPrincipalName = a_userName;
oUserPrincipal.Save();
return oUserPrincipal;
}
// if it already exists, return null
return null;
}
private PrincipalContext GetPrincipalContext()
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Machine);
return oPrincipalContext;
}
private bool UserExists(string a_userName)
{
using (var pc = new PrincipalContext(ContextType.Machine))
{
using (var p = Principal.FindByIdentity(pc, IdentityType.SamAccountName, a_userName))
{
return p != null;
}
}
}
We donĀ“t know how to find the way to create a windows user (With or without password it doesnt matter) because all the namespaces necessaries for that are not available on Windows Store Application project.
If we try to import some dll the error is:
"A reference to "[Dll path]" could not be added. The project targets '.Net Core' while the file targets '.NetFramework'. This is no a supported sceneraio"
Is there any possible solution?
This is not possible, and shouldn't be. Windows Store apps don't have the rights to create users because it would be a huge huge security risk! Why are you even trying to do this?
Related
I've created local windows account and added it to group Users using classes from System.DirectoryServices.AccountManagement namespace. Then I tried to log into that newly created account (manually not from C#) and got error 'user profile service failed user profile cannot be loaded'. My C# code is:
try
{
// Create context for server and create new user if one not exists
string userID = GetUserID(userName, userType);
PrincipalContext serverContext = GetDefaultPrincipalContext();
if (DoesExist(userID, serverContext))
{
throw new Exception("User already exists!");
}
UserPrincipal newUser = new UserPrincipal(serverContext, userID, userID, true);
// Get description of user from its privilege and save user if everything went OK
var description = GetDescriptionFromUserType(userType);
if (null != description)
{
newUser.Description = description;
newUser.Save();
// Add user to group so it is displayed in Control Panel
GroupPrincipal group = GroupPrincipal.FindByIdentity(serverContext, USERS_GROUP);
group.Members.Add(newUser);
group.Save();
group.Dispose();
newUser.Dispose();
serverContext.Dispose();
success = true;
}
}
catch (Exception e)
{
Log.LogError(TYPE, e.Message);
DeleteUser(userName, userType);
}
What i'm missing?
I've forgot to write, GetDefaultPrincipalContext() returns new PrincipalContext(Context.Machine, null)...
UPDATE:
Just to mention that I haven't made home directory and all the stuff inside it for new user on path C:\Users\NewUser... And what is strange (in my opinion), one isn't made automatically.
I'm writing an answer in case that anyone sees this post and thinks that the code above is no good. Actually code is working nicely on every other windows machine on which I tried to run it. I don't know what is the issue on my personal computer but the problem is definitely not in code... I will ask other question to resolve my windows problem...
In a nutshell, what I'm trying to do is create a new user, which has the ability to log in.
I have plucked code from various sources, and tried to simplify it. However, I'm hitting a few stumbling blocks.
When I call UserPrincipal.Save() - it gives me an error
'The directory property cannot be found in the cache' with an
exception type of.. 'COMExceptioncrossed a native/managed boundary'.
For some reason, when I run my program directly (not through vs2010) it works fine. So I can get around that !
My main problem though, is that even though everything seems ok, when I try to log in, it comes up with the message 'loading desktop' or whatever it is, and then just says 'logging out'. So it's almost as if the profile hasn't been set up correctly.
The return value from the API 'CreateProfile' isn't 0, so maybe that's causing a problem.
Is there anything else I need to do ?
My Code is...
private void Run(string un, string pw)
{
UserPrincipal NewUP = CreateUser(un, pw);
AddGroup(NewUP, "Users");
AddGroup(NewUP, "HomeUsers");
CreateProfile(NewUP);
}
private UserPrincipal CreateUser(string Username, string Password)
{
PrincipalContext pc = new PrincipalContext(ContextType.Machine, Environment.MachineName);
UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, Username);
if (up == null)
{
up = new UserPrincipal(pc, Username, Password, true);
up.UserCannotChangePassword = false;
up.PasswordNeverExpires = false;
up.Save(); // this is where it crashes when I run through the debugger
}
return up;
}
private void AddGroup(UserPrincipal Up, string GroupName)
{
PrincipalContext pc = new PrincipalContext(ContextType.Machine, Environment.MachineName);
GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, GroupName);
if (!gp.Members.Contains(Up))
{
gp.Members.Add(Up);
gp.Save();
}
gp.Dispose();
}
private void CreateProfile(UserPrincipal Up)
{
int MaxPath = 240;
StringBuilder pathBuf = new StringBuilder(MaxPath);
uint pathLen = (uint)pathBuf.Capacity;
int Res = CreateProfile(Up.Sid.ToString(), Up.SamAccountName, pathBuf, pathLen);
}
Strangely, when this is run on a server machine (i.e. not my development machine) it works fine. I've got a feeling this is something to do with Windows 7, or my particular installation of it.
Thanks for your suggestions anyway.
I built a test Active Directory server in Window 2008 and I also run the DNS server on it. On my client machine which runs the C# application, I can authenticate the user against the Active directory server using the function below:
public static UserPrincipal GetUserPrincipal(string usrName,string pswd,string domainName)
{
UserPrincipal usr;
PrincipalContext ad;
// Enter Active Directory settings
ad = new PrincipalContext(ContextType.Domain, domainName,usrName,pswd);
//search user
usr = new UserPrincipal(ad);
usr.SamAccountName = usrName;
PrincipalSearcher search = new PrincipalSearcher(usr);
usr = (UserPrincipal)search.FindOne();
search.Dispose();
return usr;
}
In a separate logic I tried to retrieve a user back from the server using a user name. I used the functions below:
public static DirectoryEntry CreateDirectoryEntry()
{
// create AD connection
DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=rootforest,DC=com","LDAP","password");
de.AuthenticationType = AuthenticationTypes.Secure;
return de;
}
public static ResultPropertyCollection GetUserProperty(string domainName, string usrName)
{
DirectoryEntry de = CreateDirectoryEntry();
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(SamAccountName=" + usrName + ")";
SearchResult results = deSearch.FindOne();
return null;
}
However, I got no response back from the LDAP server at all, not even an exception. Am I missing certain settings on LDAP server, any of you able to see a flaw in my code (pls don't mind the hard code values, I was testing with this code).
As part of my troubleshooting, I confirmed that I can ping to the rootforest.com from the client machine. I confirmed the user with property samaccountname "LDAP" exists. My path seems to be right because when I go onto the LDAP server and type :
dsquery user -name LDAP*
I got the following:
CN=LDAP L. LDAP,CN=Users,DC=rootforest,DC=com
Any help would be greatly appreciated, I've spent most of my day troubleshooting and researching this little bugger and I think it could be something small which I overlooked.
I don't understand why you're using the new PrincipalContext / UserPrincipal stuff in your first example, but fall back to the hard to use DirectoryEntry stuff in your second example.... doesn't really make sense... also: your second function GetUserProperty seems to return null always - typo or not??
Since you're on already using the System.DirectoryServices.AccountManagement (S.DS.AM) namespace - use it for your second task, too! Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
public static ????? GetUserProperty(string domainName, string usrName)
{
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, usrName);
if(user != null)
{
// return what you need to return from your user principal here
}
else
{
return null;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD:
I think your code have a few problems:
Why do you return null in your GetUserProperty() function? You should return results instead.
The attribute you are using in your search filter is misspelled. Use sSAMAccountName instead. Furthermore extend your query to search only for user accounts. Here is an example: (&(objectCategory=person)(objectClass=user)(sAMAccountName=usrName))
You could also use the UserPrincipal class to search for an identity in Active Directory. The UserPrincipal class provides a static method called FindByIdentity() to search for a user identity.
Hope, this helps.
I am trying to determine if a user is a member of an Active Directory (AD) group for an internal ASP.NET 4.0 application. The code below throws an "Attempted to access an unloaded appdomain" exception error on the last line (return statement) in the case when the user is not a member of the AD group.
public static bool IsInADGroup(string userName, string groupName)
{
var principalContext = new PrincipalContext(ContextType.Domain);
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, userName);
if (userPrincipal == null)
return false;
GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, groupName);
if (groupPrincipal == null)
return false;
return userPrincipal.IsMemberOf(groupPrincipal);
}
Any ideas on how to fix or other workarounds?
Could this bug be your problem?
I've solved the same problems using this workaround:
using (DirectoryEntry rootDse = new DirectoryEntry("LDAP://rootdse"))
{
var dnsName = rootDse.Properties["dnsHostName"].Value.ToString();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, dnsName)) {}
Same issue here.
It appears to be a bug in ADSI that was resolved with a hotfix. Windows 7 SP1 and Windows Server 2008 R2 SP1 don't include the fix, so it will need to be manually deployed on your development machines and server environments.
http://support.microsoft.com/kb/2683913
I've been trying to create new local user accounts on windows 7 machine. I used the System.DirectoryServices.DirectoryEntry class (as in here) but it doesn't seem to work.
Here's the code in the article:
static void Main(string[] args)
{
try
{
DirectoryEntry AD = new DirectoryEntry("WinNT://" +
Environment.MachineName + ",computer");
DirectoryEntry NewUser = AD.Children.Add("TestUser1", "user");
NewUser.Invoke("SetPassword", new object[] {"#12345Abc"});
NewUser.Invoke("Put", new object[] {"Description", "Test User from .NET"});
NewUser.CommitChanges();
DirectoryEntry grp;
grp = AD.Children.Find("Guests", "group");
if (grp != null) {grp.Invoke("Add", new object[] {NewUser.Path.ToString()});}
Console.WriteLine("Account Created Successfully");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
When executing this line
DirectoryEntry NewUser = AD.Children.Add("TestUser1", "user");
I get a
System.Runtime.InteropServices.COMException with "{"Unknown error (0x80005000)"}"
as the exception message, and -2147463168 as the error code.
I assume this is probably because the article targets Windows XP and below machines, and I'm targeting windows 7 and Windows server 2008.
Any help appreciated!
Update:
For some mysterious reason, i'm no longer seeing that System.Runtime.InteropServices.COMException, however, when committing the changes here newuser.CommitChanges(), I get a "UnAuthorizedAccessException". I tried running the app as administrator, but still not working.
Update 2:
OK, after changing to the UserPrincipal class, i got the follwoing code to work:
public UserPrincipal CreateNewUser(string sUserName, string sPassword)
{
// first check that the user doesn't exist
if (GetUser(sUserName) == null)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
oUserPrincipal.Name = sUserName;
oUserPrincipal.SetPassword(sPassword);
//User Log on Name
//oUserPrincipal.UserPrincipalName = sUserName;
oUserPrincipal.Save();
return oUserPrincipal;
}
// if it already exists, return the old user
return GetUser(sUserName);
}
}
This code runs well when I run it as a console app -of course run as administrator- but when i deployed it as a windows service, with the security account set as "LocalSystem", i get an InvlaidOperationException saying "The underlying store does not support this property"
Thoughts?
OK, if you check my last update, the following snippet worked:
public UserPrincipal CreateNewUser(string sUserName, string sPassword)
{
// first check that the user doesn't exist
if (GetUser(sUserName) == null)
{
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal = new UserPrincipal(oPrincipalContext);
oUserPrincipal.Name = sUserName;
oUserPrincipal.SetPassword(sPassword);
//User Log on Name
//oUserPrincipal.UserPrincipalName = sUserName;
oUserPrincipal.Save();
return oUserPrincipal;
}
// if it already exists, return the old user
return GetUser(sUserName);
}
}
That worked as a console app, but failed to execute due to security exceptions when deployed as a windows service. A solution is to trust that assembly (the windows service assembly) so that the .net security will let it run. That's done, now everything is cool!
You need to prefix your username with CN=, like so:
DirectoryEntry NewUser = AD.Children.Add("CN=TestUser1", "user");