I have a C# windows service application that generates a log file that writes to C:\Program Files\Company\Product\log.txt. I am using the installer provided by Visual Studio 2010 and need to have the installer:
1. Create a user named ProductUser
2. Set permission for C:\Program Files\Company\Product\ to allow ProductUser to write to the directory.
Not the best solution... but only an idea: what about running the command
net user password username /ADD?
If you can do that, I can find an old vbs I used on a server to grant permissions to user on a folder.
OK, I googled a little bit and found this:
public void CreateUserAccount(string login , string password , string fullName, bool isAdmin)
{
try
{
DirectoryEntry dirEntry = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntries entries = dirEntry.Children;
DirectoryEntry newUser = entries.Add (login, "user");
newUser.Properties["FullName"].Add(fullName);
newUser.Invoke("SetPassword", password);
newUser.CommitChanges();
// Remove the if condition along with the else to create user account in "user" group.
DirectoryEntry grp;
if (isAdmin)
{
grp = dirEntry.Children.Find("Administrators", "group");
if (grp != null) {grp.Invoke("Add", new object[] {newUser.Path.ToString()});}
}
else
{
grp = dirEntry.Children.Find("Guests", "group");
if (grp != null) {grp.Invoke("Add", new object[] {newUser.Path.ToString()});}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
It's not mine: here is the link.
Let me know if it works for you
Related
I am developing a simple tool for create local user accounts on windows and add them to administrator group or guest group.
I just need to know that how to enable the "User Must Change The Password At Next Logon" option when creating a new local user account. I am using c# , windows form application to write my script. I have used below code to create the user account and set password to Pass#123 and need to enable "User Must Change The Password At Next Logon" option.
I have tried to use NewUser.Properties["pwdLastSet"].Value = 0; but this did not worked, threw an exception since this is used for ActiveDirectory.
Can someone assist me regarding this?
try
{
DirectoryEntry AD = new DirectoryEntry("WinNT://" +
Environment.MachineName + ",computer");
DirectoryEntry NewUser = AD.Children.Add(UserID, "user");
NewUser.Invoke("SetPassword", new object[] { "Pass#123" });
NewUser.Invoke("Put", new object[] { "Description", "A user account managed by system"});
NewUser.Invoke("Put", new object[] { "FullName", "Work From Home: " + UserID });
NewUser.CommitChanges();
DirectoryEntry grp;
grp = AD.Children.Find(AccountType, "group");
if (grp != null) { grp.Invoke("Add", new object[] { NewUser.Path.ToString() }); }
MessageBox.Show("Account Created Successfully","Successfull", MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
I have found how to enable User Must Change Password At Next Logon in a local user account with c# script
NewUser.Properties["PasswordExpired"].Value = 1;
This one worked successfully.
Thank You so much !
Been a while since i had to try to manage a local AD directly from .net code so this might be outdated.
Try: NewUser.Properties["pwdLastSet"][0] = 0;
If I'm not mistaken ["pwdLastSet"] is in itself and ICollection :).
Otherwise i would recommend you look into System.DirectoryServices.AccountManagement. Then you could simply use UserPrincipal.Current.ExpirePasswordNow();
Or something equivalent once you have defined your PrincipalContext. Here is the documentation https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices.accountmanagement?view=dotnet-plat-ext-7.0
`
Found a documentation (here) in an answer thread on this site but i can´t get an connection to an AD. When i use a program like Active Directory Explorer i can connect. I think, because i am trying to connect to a LDAPS i need a different approach?
I have the server IP, a domain, username/pwd and the port 636.
I tried various combinations # new DirectoryEntry but couldn´t get it to connect. Always get a COMException Domain is not existing .
static DirectoryEntry createDirectoryEntry()
{
DirectoryEntry ldapConnection = new DirectoryEntry("LDAP://192.168.2.59", USER, PWD);
ldapConnection.AuthenticationType = AuthenticationTypes.SecureSocketsLayer;
return ldapConnection;
}
Background Infos:
User places his card to a Card Reader Unit. Porgram gets ID from card and searches the DB for this ID and returns the eMail address belonging to the ID/User
.
And here the working solution:
private string getEmail(string userID)
{
try
{
string ldapfilter = "(&(otherPager=" + userID + "))";
DirectoryEntry myLdapConnection = new DirectoryEntry("LDAP://" + SERVER, USER, PWD);
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.Filter = ldapfilter;
/*search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();*/
string[] requiredValue = new String[] { "mail" };
foreach (String value in requiredValue)
search.PropertiesToLoad.Add(value);
SearchResult result = search.FindOne();
if (result != null)
{
foreach (String value in requiredValue)
foreach (Object myCollection in result.Properties[value])
{
return myCollection.ToString();
}
}
else
{
return "No Entry fround";
}
}
catch (Exception e)
{
Console.WriteLine("Exception Problem: " + e.ToString());
return null;
}
return null;
}
private void cmdClose_Click(object sender, EventArgs e)
{
Close();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
label1.Text = getEmail(textBox1.Text);
}
You need to specify the port, since 636 is the default LDAPS port.
new DirectoryEntry("LDAP://192.168.2.59:636", USER, PWD)
I do this in some of my code, and using "LDAP://" (not "LDAPS://") is what works.
If that doesn't work, then there may be a certificate error. You can test this with a browser. If you use Chrome, open Chrome with this (so it lets you use port 636):
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --explicitly-allowed-ports=636
Then go to https://192.168.2.59:636. If you get a big fancy certificate error, then the problem is that the certificate is not trusted. View the certificate from Chrome and see what the problem is. It could be issued by an authority that is not in the Windows cert store.
I am developing a web application that authenticate the user against an Active Directory Server. Now if I run my code from the development PC under the domain of that AD server, my code is running smoothly. We need to run the code from a totally different network using VPN and here the development PC is not into that AD. I am getting following error while trying to access the AD server.
The specified domain either does not exist or could not be contacted.
My VPN is working fine. I could access remote desktops using this VPN. I know a little tweak is required to solve the problem but could not find it. I went through following links but could not find any solution.
Domain Authentication from .NET Client over VPN
How do I get the Current User identity for a VPN user in a Windows forms app?
Following is my settings in web.config
<appSettings>
<add key="LDAPPath" value="LDAP://DC=MYSERVER,DC=COM" />
<add key="ADGroupName" value="Analyst"/>
</appSettings>
and here is my code
public class LdapAuthentication
{
private string _path;
private string _filterAttribute;
public LdapAuthentication()
{
_path = System.Configuration.ConfigurationManager.AppSettings["LDAPPath"].ToString();
}
public bool IsAuthenticated(string username, string pwd)
{
try
{
DirectoryEntry entry = new DirectoryEntry(_path, username, pwd);
entry.Path = _path;
entry.Username = username;
entry.Password = pwd;
// Bind to the native AdsObject to force authentication.
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory.
_path = result.Path;
_filterAttribute = (string)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
}
Any help would be appreciated. Thank you.
I had a similar, though simpler problem. I had success in using the following code:
private bool DoLogin(string userName, string password)
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "DomainName.com")) {
bool isValid = pc.ValidateCredentials(userName, password);
if (isValid) {
// authenticated
...
return true;
}
else {
// invalid credentials
...
return false;
}
}
}
Using the ".com" at the end of the domain name was important to get it working for me. Without it I got the same symptoms you describe.
I've just been grappling with this for a couple of hours. No problems when on the network, lots of problems when connecting via VPN. It seems that when you are connecting over a VPN, the 'connection string' for DirectoryEntry has to be a lot more precise. I finally got it to work with an LDAP address/connection string like this:
LDAP://ip_of_primary_domain_controller/fully qualified path of the container object where the binding user is located
So for example something like this worked for me:
DirectoryEntry directoryEntry = new DirectoryEntry(
"LDAP://192.168.0.20/OU=Service Accounts,OU=Admin Accounts,DC=myserver,DC=com",
"username#myserver.com", "password");
... where "username#myserver.com" is located in OU=Service Accounts,OU=Admin Accounts,DC=myserver,DC=com. If you use SysInternals ADExplorer (or similar) to search for your username, it will tell you the correct fully qualified path for the container.
See here for a long answer about exactly whats should be in the 'connection string': https://serverfault.com/a/130556
Is there any sample that deletes computer account from AD using C#?
I have searched many sources, but all are about user account.
added my code here, i always got errors for some reason.
public static bool checkExistingPC(string compName,string userName,string userPwd )
{
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://test.com",userName,userPwd,AuthenticationTypes.Secure);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=computer)(|(cn=" + compName + ")(dn=" + compName + ")))";
foreach (SearchResult result in mySearcher.FindAll())
{
if (result != null)
{
MessageBox.Show("computer GetDirectoryEntry():" + result.Path+"\n"+"computer path: "+result.Path);
DirectoryEntry entryToRemove = new DirectoryEntry(result.Path,userName,userPwd);
entry.Children.Remove(entryToRemove);
return true;
}
else
{
return false;
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return false;
}
If you're on .NET 3.5 and up (if you're not - time to upgrade!), you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. 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:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find the computer in question
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(ctx, "NAME");
// if found - delete it
if (computer != null)
{
computer.Delete();
}
The new S.DS.AM makes it really easy to play around with users, computers and groups in AD!
Using ADSI which is under System.DirectoryServices use a commit mechanism, here is a working sample :
/* Retreiving RootDSE infos
*/
string ldapBase = "LDAP://WM2008R2ENT:389/";
string sFromWhere = ldapBase + "rootDSE";
DirectoryEntry root = new DirectoryEntry(sFromWhere, "dom\\jpb", "PWD");
string defaultNamingContext = root.Properties["defaultNamingContext"][0].ToString();
/* Retreiving the computer to remove
*/
sFromWhere = ldapBase + defaultNamingContext;
DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "dom\\jpb", ".biènèsph^r^.1966");
DirectorySearcher dsLookForDomain = new DirectorySearcher(deBase);
dsLookForDomain.Filter = "(&(cn=MACHSUPR))"; // MACHSUPR is the computer to delete
dsLookForDomain.SearchScope = SearchScope.Subtree;
dsLookForDomain.PropertiesToLoad.Add("cn");
dsLookForDomain.PropertiesToLoad.Add("distinguishedName");
SearchResultCollection srcComputer = dsLookForDomain.FindAll();
foreach (SearchResult aComputer in srcComputer)
{
/* For each computer
*/
DirectoryEntry computerToDel = aComputer.GetDirectoryEntry();
computerToDel.DeleteTree();
computerToDel.CommitChanges();
}
Use WMI and or System.DirectoryServices namespace (http://msdn.microsoft.com/en-us/library/system.directoryservices.aspx).
It may not be exactly what you are looking for, but this site provides a number of code examples for working with AD in C#, including deleting a security group and removing a user from a group
I'm using DirectoryServices to authenticate a user against an ADLDS (the lighteweight Active Directory). After I pass authentication. How can I determine the DN or SID of the currently logged in user?
using (DirectoryEntry entry = new DirectoryEntry(<a>LDAP://XYZ:389</a>,
userName.ToString(),
password.ToString(),
AuthenticationTypes.Secure))
{
try
{
// Bind to the native object to force authentication to happen
Object native = entry.NativeObject;
MessageBox.Show("User authenticated!");
}
catch (Exception ex)
{
throw new Exception("User not authenticated: " + ex.Message);
}
...
Thanks
Update:
I get an exception at
src = search.FindAll()
There is no such object on the server.
I realized the user logging in has a class type "foreignSecurityPrincipal" in the Active Directory lightweight so I figured perhaps I can just modify your filter to be:
search.Filter = "(&(objectclass=foreignSecurityPrincipal)" + "(sAMAccountName=" + userName + "))";
But that gave me the same exception. Any idea what I am missing?
To my knowledge you will have to do an LDAP Search for the user and get the distinguishedName property from AD. See below:
// you can use any root DN here that you want provided your credentials
// have search rights
DirectoryEntry searchEntry = new DirectoryEntry("LDAP://XYZ:389");
DirectorySearcher search = new DirectorySearcher(searchEntry);
search.Filter = "(&(objectclass=user)(objectCategory=person)" +
"(sAMAccountName=" + userName + "))";
if (search != null)
{
search.PropertiesToLoad.Add("sAMAccountName");
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("distinguishedName");
log.Info("Searching for attributes");
// find firest result
SearchResult searchResult = null;
using (SearchResultCollection src = search .FindAll())
{
if (src.Count > 0)
searchResult = src[0];
}
if (searchResult != null)
{
// Get DN here
string DN = searchResult.Properties["distinguishedName"][0].ToString();
}
When I add a new user manually in the active directory, the 'distinguished Name' cannot be define manually but the convention seems to be the first name + ' ' + the last name. In this case, why not trying to get the 'distinguished name' following this pattern. I also found that if I just specified a first name to create a non-human user, the 'distinguihed name' is the equal to the first name without space after.
I follow this pattern in my application and it works and it's much simple than trying to create custom query to search user.