I want to create a Contact-Object in a specific OU in our AD with some Attributes:
sn, givenName, mail, description, displayname, proxyAddresses and targetaddress.
I found lots of examples how to set the Attributes for a Contact-Object in Active Directory with C# and I`m able to create the Object with all Attributes except "targetaddress".
Could someone please Point me in the right Direction for this. Thank you!
public void CreateContact2(string Vorname, string Nachname, string EmailAdresse, string Beschreibung, string myDomainPath)
{
string CN = Vorname + " " + Nachname;
string mailNickName = EmailAdresse.Remove(EmailAdresse.IndexOf("#"));
string EmailAdresse2 = "SMTP:" + EmailAdresse;
DirectoryEntry directoryEntry;
try
{
directoryEntry = new DirectoryEntry("LDAP://myDomainPath")
directoryEntry.RefreshCache();
DirectoryEntry contact = directoryEntry.Children.Add("CN=" + CN, "Contact");
contact.Properties["sn"].Value = Nachname;
contact.Properties["givenName"].Value = Vorname;
contact.Properties["mail"].Value = EmailAdresse;
contact.Properties["description"].Value = Beschreibung;
contact.Properties["displayName"].Value = Nachname + ", " + Vorname;
contact.Properties["proxyAddresses"].Add(EmailAdresse2);
contact.Properties["targetaddress"].Value = EmailAdresse2;
contact.CommitChanges();
}
catch (Exception e)
{
// Do some error processing
var msg = e.Message.ToString();
Console.WriteLine("Fehler in Funktion CreateContact():" + msg);
}
}
The Contact-Object creates fine if I create it without the targetaddress-Attribute
But with it I´m
getting System.Runtime.InteropServices.COMException: “The specified
directory service attribute or value does not exist”
failure. Any Ideas?
I had he same issue , what i did is to restart and run Visual Studio as Administrator . It may be due to not having enough privileges to run some COM Methods
Thank you so much Guys!
I had found the answer by myself and . It was my mistake. The attribute wasn´t right delegated.
I am having a problem updating user information in an Active Directory DB...
When I run the following code I get this error:
The specified directory service attribute or value does not exist
The problem is the path it is using to save the information is this:
CN=AD Test,OU=Container Name,DC=us,DC=flg,DC=int
Ad Test is the username in AD that I am trying to update.
and I believe it should be:
CN=Ad Test,OU=Container Name, OU=Server Name,DC=us,DC=flg,DC=int
I am new to Directory services so I would greatly appreciate any help in finding out why I cannot update... Thank you in advance
public bool UpdateActiveDirectory(string LdapServerName, string CustId, Employee SQLresult)
{
try
{
DirectoryEntry rootEntry = new DirectoryEntry("LDAP://" + LdapServerName, "usrename", "password", AuthenticationTypes.Secure);
DirectorySearcher searcher = new DirectorySearcher(rootEntry);
searcher.Filter = "(sAMAccountName=" + SQLresult.LogonNT + ")";
searcher.PropertiesToLoad.Add("title");
searcher.PropertiesToLoad.Add("street");
searcher.PropertiesToLoad.Add("1");
searcher.PropertiesToLoad.Add("st");
searcher.PropertiesToLoad.Add("postalCode");
searcher.PropertiesToLoad.Add("department");
searcher.PropertiesToLoad.Add("mail");
searcher.PropertiesToLoad.Add("manager");
searcher.PropertiesToLoad.Add("telephoneNumber");
SearchResult result = searcher.FindOne();
if (result != null)
{
// create new object from search result
DirectoryEntry entryToUpdate = result.GetDirectoryEntry();
entryToUpdate.Properties["title"].Value = SQLresult.Title;
entryToUpdate.Properties["street"].Value = SQLresult.Address;
entryToUpdate.Properties["1"].Value = SQLresult.City;
entryToUpdate.Properties["st"].Value = SQLresult.State;
entryToUpdate.Properties["postalCode"].Value = SQLresult.ZipCode;
entryToUpdate.Properties["department"].Value = SQLresult.Department;
entryToUpdate.Properties["mail"].Value = SQLresult.EMailID;
entryToUpdate.Properties["manager"].Value = SQLresult.ManagerName;
entryToUpdate.Properties["telephoneNumber"].Value = SQLresult.Phone;
entryToUpdate.CommitChanges();
Console.WriteLine("User Updated");
}
else
{
Console.WriteLine("User not found!");
}
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return true;
}
Maybe just a typo?
The third property you're trying to update:
entryToUpdate.Properties["1"].Value = SQLresult.City;
is that a one (1) in there? It should be a small L (l) instead.
Also: the manager's name must be the Distinguished Name of the manager - the whole
CN=Manager,CN=Ad Test,OU=Container Name, OU=Server Name,DC=us,DC=flg,DC=int
thing - not just the name itself.
If that doesn't help anything - just go back to old-school debugging technique:
update just a single property; if it fails --> that's your problem case - figure out why it's a problem.
If it works: uncomment a second property and run again
-> repeat over and over again, until you find your culprit
I got some code of a tool which does many security checks on client machines and I'm trying to understand some bug and solve it - need your help.
There is a test which checks if the user password is set to "never expire". I tried this test offline and in 3 different networks and it seems to be working. There is some WIFI guest network in my company which return exception while executing the code.
Here is the exception I'm getting:
The network path was not found.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_NativeObject()
at System.DirectoryServices.DirectoryEntry.InvokeGet(String propertyName)
at Intel.HostCheck.Engine.Checks.PasswordAge.CheckPasswordNeverExpired()
See the the following code for understanding the test implementation:
private CheckResult CheckPasswordNeverExpired()
{
try
{
DirectoryEntry de;
Logger.Debug("Password Age: isCurrentUserLocalUser - " + HelpFunction.isCurrentUserLocalUser());
if (HelpFunction.isCurrentUserLocalUser())
de = new DirectoryEntry("WinNT://" + Environment.MachineName + "/" + Environment.UserName);
else de = new DirectoryEntry("WinNT://" + Environment.UserDomainName + "/" + Environment.UserName);
object currentUser = de.InvokeGet("UserFlags");
if (currentUser != null)
{
Logger.Debug("PasswordAge: " + currentUser);
Logger.Debug("PasswordAge: " + Convert.ToBoolean((int)currentUser & UF_DONT_EXPIRE_PASSWD).ToString());
}
if (Convert.ToBoolean((int)currentUser & UF_DONT_EXPIRE_PASSWD))
{
Logger.Debug("Password Age: check result: fail ");
return CheckResult.Fail;
}
Logger.Debug("Password Age: check result: pass ");
return CheckResult.Pass;
}
catch (Exception ex)
{
Logger.LogException(ex, "Error in PasswordAge->Check()");
return CheckResult.Exception;
}
}
}
public static bool isCurrentUserLocalUser()
{
return Environment.MachineName == Environment.UserDomainName;
}
Just for clarification, it's not my code so I'm not completely sure what the code owner did.
I'm seeing that there are no responses. I will ask different question.
Is there any option to obtain password age or password last set values without be depend on network connection? Is it possible to check it locally?
I know this value also exists under "Local security policy" but I didn't find how to get it by code.
When we try to search for a user in ActiveDirectory, we get that exception - 0x8007203B.
Basically we deployed a web service, which uses DirectoryEntry & DirectorySearcher class to find a user in AD, and sometimes this exception happens. But when we do IISReset, it again works fine.
Code is very simple like this:
DirectoryEntry domainUser = new DirectoryEntry("LDAP://xxx.yyy/dc=xxx,dc=yyy", "domain\user", "pwd", AuthenticationTypes.Secure);
DirectoryEntry result = new DirectorySearcher(domainUser, filter);
Only some times this happens. I don't have much information to provide, any guess much appreciated
This is how my filter looks like
public static string BuildFilter(DirectoryEntry dirEntry, string userName, string userMail)
{
try
{
string filter = string.Empty;
if (!string.IsNullOrEmpty(userName) && string.IsNullOrEmpty(userMail))
filter = string.Format(#"(&(objectClass=user)(samaccounttype=805306368)(|(CN={0})(samaccountname={0})))", userName);
else if (string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(userMail))
filter = string.Format(#"(&(objectClass=user)(samaccounttype=805306368)(mail={0}))", userMail);
else
filter = string.Format(#"(&(objectClass=user)(samaccounttype=805306368)(|(CN={0})(samaccountname={0})(mail={1})))", userName, userMail);
return filter;
}
catch (Exception ex)
{
_logger.Error("BuildUserSearch - Failed to build LDAP search", ex);
}
return null;
}
You say that this it's just append after some time. As DirectoryEntry and DirectorySearcher are built on COM object into disposable class I would first just add some using sections to be sure that underlying objects are corectly freed.
using(DirectoryEntry root = new DirectoryEntry(ldapPath))
{
using(DirectorySearcher searcher=new DirectorySearcher(root))
{
...
}
...
}
Any guess are appreciated?
Then here's mine:
ASP.NET: DirectoryServicesCOMException [...];
Windows Error Codes: Repair 0x8007203B. How To Repair 0x8007203B.
What makes me confuse is that you say it works most of the time...
Did this help?
P.S. I'll update if I think of anything else.
How can I get the Windows user and domain from an Active Directory DirectoryEntry (SchemaClassName="user") object?
The user name is in the sAMAccountName property but where can I look up the domain name?
(I can't assume a fixed domain name because the users are from various subdomains.)
This assumes that results is a SearchResultCollection obtained from a DirectorySearcher, but you should be able to get the objectsid from a DirectoryEntry directly.
SearchResult result = results[0];
var propertyValues = result.Properties["objectsid"];
var objectsid = (byte[])propertyValues[0];
var sid = new SecurityIdentifier(objectsid, 0);
var account = sid.Translate(typeof(NTAccount));
account.ToString(); // This give the DOMAIN\User format for the account
You won't find what you're looking for in the DirectoryEntry, unfortunately.
You have the sAMAccountName which typically is something like myuser (without the domain). You have the distinguishedName which is something like LDAP://cn=joe myuser,cn=Users,dc=yourCompany,dc=com. You also have a userPrincipalName but that's usually a name in the format of joeUser#mycompany.com.
But you won't find any attribute that has the domain\MyUser in it, unfortunately. You'll have to put that together from your information about the domain name, and the sAMAccountName of the DirectoryEntry.
For more information and some excellent Excel sheets on all the LDAP and WinNT properties in System.DirectoryServices, check out the Hilltop Lab website by ADSI MVP Richard Mueller.
Marc
To get the DirectoryEntry domain name you can use recursion on
directoryEntry.Parent.
And then if directoryEntry.SchemaClassName == "domainDNS"
you can get the domain name like this:
directoryEntry.Properties["Name"].Value
I found a partitions container in CN=Partitions,CN=Configuration that contains all domains.
When you match the user to the partion you can read the real domain name from the nETBIOSName+"\"+sAMAccountName property.
public static string GetDomainNameUserNameFromUPN(string strUPN)
{
try
{
WindowsIdentity wi = new WindowsIdentity(strUPN);
WindowsPrincipal wp = new WindowsPrincipal(wi);
return wp.Identity.Name;
}
catch (Exception ex)
{
}
return "";
}
If you are using the System.DirectoryServices libraries, you should have a SearchResultsCollection from a DirectorySearcher.
Within each SearchResult's Properties collection, there is a "distinguishedname" property. That will contain all the DC parts that make up the domain your directory entry belongs to.
I'm extending a previous answer by #laktak to provide the details of what he meant.
There is a partitions container in CN=Partitions,CN=Configuration that contains all domains which gives you the cn which is the Netbios domain name and the nCName property that contains the distinguishedName prefix a user will have if they are in this domain.
So start by searching ldap for (objectClass=*) in CN=Partitions,CN=Configuration and store the (cn, nCName) pairs of each result to a map.
Next you query ldap using (sAMAccountName=USERIDHERE) and get the distinguishedName from the user. Now go through the (cn, nCName) pairs and find the nCName that prefixes the distinguishedName from the user, and the corresponding cn is your desired Domain name.
I wrote this pieces of code for my own usage (in VB.net, easy translation) :
<System.Runtime.CompilerServices.Extension()>
Public Function GetDomainFQDN(ByVal Entry As DirectoryServices.DirectoryEntry) As String
Try
While Entry.SchemaClassName <> "domainDNS"
Entry = Entry.Parent
End While
Dim DN As String = Entry.Properties("DistinguishedName").Value
Return DN.Replace("DC=", "").Replace(",", ".")
Catch ex As Exception
Debug.WriteLine(ex.ToString)
Return String.Empty
End Try
End Function
<System.Runtime.CompilerServices.Extension()>
Public Function GetDomainNetbiosName(ByVal Entry As DirectoryServices.DirectoryEntry) As String
Try
While Entry.SchemaClassName <> "domainDNS"
Entry = Entry.Parent
End While
Return Entry.Properties("Name").Value
Catch ex As Exception
Debug.WriteLine(ex.ToString)
Return String.Empty
End Try
End Function
I feel obligated to add my answer which was inspired from Nicholas DiPiazza's answer here. Hope this PowerShell code helps someone!
$hash = #{} //this contains the map of CN and nCNAME
$Filter = '(nETBIOSName=*)'
$RootOU = "CN=Partitions,CN=Configuration,DC=DOMAIN,DC=LOCAL" //Change this to your org's domain
$Searcher = New-Object DirectoryServices.DirectorySearcher
$Searcher.SearchScope = "subtree"
$Searcher.Filter = $Filter
$Searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$($RootOU)")
$Searcher.FindAll()|sort | foreach { $hash[($_.Properties.ncname).Trim()] = ($_.Properties.cn).Trim() }
$hash.GetEnumerator() | sort -Property Value
If the user details are available in $userDetails, then the you can get the correct domain with this:
$hash[[regex]::Match($userDetails.DistinguishedName, 'DC=.*').Value]
and the final username would look like this:
$hash[[regex]::Match($userDetails.DistinguishedName, 'DC=.*').Value] + "\" + $userDetails.SamAccountName
1) You can get the userPrincipalName from the DirectoryEntry.
2) Then, split the UPN up between the Username and Domain Name.
3) Then call GetNetBIOSName() on it.
public static DirectoryEntry GetDirectoryObject(string strPath)
{
if (strPath == "")
{
strPath = ConfigurationManager.AppSettings["LDAPPath"]; //YOUR DEFAULT LDAP PATH ie. LDAP://YourDomainServer
}
string username = ConfigurationManager.AppSettings["LDAPAccount"];
string password = ConfigurationManager.AppSettings["LDAPPassword"];
//You can encrypt and decrypt your password settings in web.config, but for the sake of simplicity, I've excluded the encryption code from this listing.
}
catch (Exception ex)
{
HttpContext.Current.Response.Write("user: " + username + ", LDAPAccount: "+ ConfigurationManager.AppSettings["LDAPAccount"] + ".<br /> "+ ex.Message +"<br />");
if (HttpContext.Current.User.Identity != null)
{
HttpContext.Current.Response.Write("HttpContext.Current.User.Identity: " + HttpContext.Current.User.Identity.Name + ", " + HttpContext.Current.User.Identity.IsAuthenticated.ToString() + "<br />");
HttpContext.Current.Response.Write("Windows Identity: " + WindowsIdentity.GetCurrent().Name + ", " + HttpContext.Current.User.Identity.IsAuthenticated.ToString());
}
else
{
HttpContext.Current.Response.Write("User.Identity is null.");
}
HttpContext.Current.Response.End();
}
DirectoryEntry oDE = new DirectoryEntry(strPath, username, password, AuthenticationTypes.Secure);
return oDE;
}
public static string GetNetBIOSName(string DomainName)
{
string netBIOSName = "";
DirectoryEntry rootDSE =GetDirectoryObject(
"LDAP://"+DomainName+"/rootDSE");
string domain = (string)rootDSE.Properties[
"defaultNamingContext"][0];
// netBIOSName += "Naming Context: " + domain + "<br />";
if (!String.IsNullOrEmpty(domain))
{
//This code assumes you have a directory entry at the /CN=Partitions, CN=Configuration
//It will not work if you do not have this entry.
DirectoryEntry parts = GetDirectoryObject(
"LDAP://"+DomainName+"/CN=Partitions, CN=Configuration," + domain);
foreach (DirectoryEntry part in parts.Children)
{
if ((string)part.Properties[
"nCName"][0] == domain)
{
netBIOSName += (string)part.Properties[
"NetBIOSName"][0];
break;
}
}
}
return netBIOSName;
}
public static string GetDomainUsernameFromUPN(string strUPN)
{
string DomainName;
string UserName;
if (strUPN.Contains("#"))
{
string[] ud = strUPN.Split('#');
strUPN= ud[0];
DomainName = ud[1];
DomainName=LDAPToolKit.GetNetBIOSName(DomainName);
UserName= DomainName + "\\" + strUPN;
}
else
{
UserName= strUPN;
}
return UserName;
}