Case sensitivity problem in using the Contains method in ResultPropertyValueCollection

C

Chris Noble

I need to check whether a particular user is already a member of an Active
Directory Security Group.

The following code extract works but only if the user distinguished name is
exactly the same as that returned from Active Directory. For example using
'cn=' in the userdn string instead of 'CN=' does not work.

As far as I am aware Active Directory is not case sensitive and it is
therefore difficult to predict the case of a string.

Before I write code to extract all the strings (converted into either upper
or lower case) into a sorted list to be able to search for the user is there
a way to make the Contains method work more predictably?

The ResultPropertyValueCollection (result.Properties["member"]) contains
objects of type String.

DirectoryEntry parententry = new DirectoryEntry(LDAPParentPath);
DirectoryEntry groupentry = parententry.Children.Find(user.Group);
DirectorySearcher ds = new DirectorySearcher(groupentry);
SearchResult result;
ds.PropertiesToLoad.Add("member");
result = ds.FindOne();
if (result != null)
{
String userdn = String.Format("CN={0},{1}", user.User_logon_name,
user.Ldap_container);
if (!result.Properties["member"].Contains(userdn)) // NB Case Sensitive
{
// add user to group
groupentry.Properties["member"].Add(userdn);
groupentry.CommitChanges();
}
}
 
L

Luke Zhang [MSFT]

Hello,

The obkect result.Properties["member"] is actually a ArryList object, its
Contains() method is Case sensitive here. Instead of the Contains method, I
think you may loop very items in this arraylist and compare lowercase value
of the items with your "userdn"'s lower case value.

Sincerely,

Luke Zhang

Microsoft Online Community Support
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
W

Willy Denoyette [MVP]

Chris Noble said:
I need to check whether a particular user is already a member of an Active Directory
Security Group.

The following code extract works but only if the user distinguished name is exactly the
same as that returned from Active Directory. For example using 'cn=' in the userdn string
instead of 'CN=' does not work.

As far as I am aware Active Directory is not case sensitive and it is therefore difficult
to predict the case of a string.

Before I write code to extract all the strings (converted into either upper or lower case)
into a sorted list to be able to search for the user is there a way to make the Contains
method work more predictably?

The ResultPropertyValueCollection (result.Properties["member"]) contains objects of type
String.

DirectoryEntry parententry = new DirectoryEntry(LDAPParentPath);
DirectoryEntry groupentry = parententry.Children.Find(user.Group);
DirectorySearcher ds = new DirectorySearcher(groupentry);
SearchResult result;
ds.PropertiesToLoad.Add("member");
result = ds.FindOne();
if (result != null)
{
String userdn = String.Format("CN={0},{1}", user.User_logon_name,
user.Ldap_container);
if (!result.Properties["member"].Contains(userdn)) // NB Case Sensitive
{
// add user to group
groupentry.Properties["member"].Add(userdn);
groupentry.CommitChanges();
}
}


result.Properties["member"] returns the RDN in a directory attribute in upper case form, so
you need to use uppercased RDN's when comparing.
Howevr, there is no need to make it that complicated.

DirectoryEntry groupentry = parententry.Children.Find(user.Group);
String userdn = String.Format("CN={0}", user.User_logon_name);
DirectoryEntry tmpEntry;
try
{
tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find is case
agnostic, userdn may look like cn=...
}
finally
{
if(tmpEntry == null)
// no such entry found, add entry to container.
else
tmpEntry.Dispose();
}
.....

Willy.

RDN = "relative distinguished name" like DC, NC, E etc...
 
C

Chris Noble

Thanks Willy


Willy Denoyette said:
Chris Noble said:
I need to check whether a particular user is already a member of an Active
Directory Security Group.

The following code extract works but only if the user distinguished name
is exactly the same as that returned from Active Directory. For example
using 'cn=' in the userdn string instead of 'CN=' does not work.

As far as I am aware Active Directory is not case sensitive and it is
therefore difficult to predict the case of a string.

Before I write code to extract all the strings (converted into either
upper or lower case) into a sorted list to be able to search for the user
is there a way to make the Contains method work more predictably?

The ResultPropertyValueCollection (result.Properties["member"]) contains
objects of type String.

DirectoryEntry parententry = new DirectoryEntry(LDAPParentPath);
DirectoryEntry groupentry = parententry.Children.Find(user.Group);
DirectorySearcher ds = new DirectorySearcher(groupentry);
SearchResult result;
ds.PropertiesToLoad.Add("member");
result = ds.FindOne();
if (result != null)
{
String userdn = String.Format("CN={0},{1}", user.User_logon_name,
user.Ldap_container);
if (!result.Properties["member"].Contains(userdn)) // NB Case
Sensitive
{
// add user to group
groupentry.Properties["member"].Add(userdn);
groupentry.CommitChanges();
}
}


result.Properties["member"] returns the RDN in a directory attribute in
upper case form, so you need to use uppercased RDN's when comparing.
Howevr, there is no need to make it that complicated.

DirectoryEntry groupentry = parententry.Children.Find(user.Group);
String userdn = String.Format("CN={0}", user.User_logon_name);
DirectoryEntry tmpEntry;
try
{
tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find
is case agnostic, userdn may look like cn=...
}
finally
{
if(tmpEntry == null)
// no such entry found, add entry to container.
else
tmpEntry.Dispose();
}
....

Willy.

RDN = "relative distinguished name" like DC, NC, E etc...
 
C

Chris Noble

Willy

I have had a go with this but I am having a problem with the code you
provided in testing for a null instance of tmpEntry.
The line if(tmpEntry == null) will not compile without producing a 'use of
unassigned local variable' error


DirectoryEntry groupentry = parententry.Children.Find(user.Group);
String userdn = String.Format("CN={0}", user.User_logon_name);
DirectoryEntry tmpEntry;
try
{
tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find
is case agnostic, userdn may look like cn=...
}
finally
{
if(tmpEntry == null)
// no such entry found, add entry to container.
else
tmpEntry.Dispose();
}

Any suggestions

Chris


Willy Denoyette said:
Chris Noble said:
I need to check whether a particular user is already a member of an Active
Directory Security Group.

The following code extract works but only if the user distinguished name
is exactly the same as that returned from Active Directory. For example
using 'cn=' in the userdn string instead of 'CN=' does not work.

As far as I am aware Active Directory is not case sensitive and it is
therefore difficult to predict the case of a string.

Before I write code to extract all the strings (converted into either
upper or lower case) into a sorted list to be able to search for the user
is there a way to make the Contains method work more predictably?

The ResultPropertyValueCollection (result.Properties["member"]) contains
objects of type String.

DirectoryEntry parententry = new DirectoryEntry(LDAPParentPath);
DirectoryEntry groupentry = parententry.Children.Find(user.Group);
DirectorySearcher ds = new DirectorySearcher(groupentry);
SearchResult result;
ds.PropertiesToLoad.Add("member");
result = ds.FindOne();
if (result != null)
{
String userdn = String.Format("CN={0},{1}", user.User_logon_name,
user.Ldap_container);
if (!result.Properties["member"].Contains(userdn)) // NB Case
Sensitive
{
// add user to group
groupentry.Properties["member"].Add(userdn);
groupentry.CommitChanges();
}
}


result.Properties["member"] returns the RDN in a directory attribute in
upper case form, so you need to use uppercased RDN's when comparing.
Howevr, there is no need to make it that complicated.

DirectoryEntry groupentry = parententry.Children.Find(user.Group);
String userdn = String.Format("CN={0}", user.User_logon_name);
DirectoryEntry tmpEntry;
try
{
tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find
is case agnostic, userdn may look like cn=...
}
finally
{
if(tmpEntry == null)
// no such entry found, add entry to container.
else
tmpEntry.Dispose();
}
....

Willy.

RDN = "relative distinguished name" like DC, NC, E etc...
 
W

Willy Denoyette [MVP]

Chris Noble said:
Willy

I have had a go with this but I am having a problem with the code you provided in testing
for a null instance of tmpEntry.
The line if(tmpEntry == null) will not compile without producing a 'use of unassigned
local variable' error


DirectoryEntry groupentry = parententry.Children.Find(user.Group);
String userdn = String.Format("CN={0}", user.User_logon_name);
DirectoryEntry tmpEntry;
try
{
tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find is case
agnostic, userdn may look like cn=...
}
finally
{
if(tmpEntry == null)
// no such entry found, add entry to container.
else
tmpEntry.Dispose();
}

Any suggestions

Sorry my OE compiler did not catch this one ;-).

Make it ...
....
DirectoryEntry tmpEntry = null;;
try
{
...

Willy.
 
C

Chris Noble

Willy
I spent too long writing C and C++ code and still assume unassigned
variables are automatically null.

My original method worked despite the case sensitivity problem but I am
still having problems with your suggestion.
The problem appears to be in using the line
' tmpEntry = container.Children.Find(userdn , user.Ldap_container); //Find
is case agnostic, userdn may look like cn=...'

No problems with the userdn but looking at the syntax for the Find method
the second parameter should be a schemaClassName.
container is the DirectoryEntry for a Security Group. I have tried "user" as
the schemaClassName but this does not work.
I can't see how this could work as the security group is not really a
container but it has properties one of which is 'members' that contains an
array of user names.
Am I missing something or do I need to back to my original approach and
solve the case problem

Chris
 
C

Chris Noble

Willy

Problem solved now. I used the Find method (case insensitive) to find the
security group directoryentry.

DirectoryEntry groupentry==null;
try
{
groupentry = parententry.Children.Find(GroupName); // case insensitive
}
finally
{
if (groupentry != null)
{
etc ......

If the groupentry is valid, then to check whether the user is already member
of the security group I can read the distinguishedName property for the user
and then search the member properties of the security group directoryentry

DirectorySearcher ds = new DirectorySearcher(groupentry);
SearchResult result;
ds.PropertiesToLoad.Add("member");
result = ds.FindOne();
if (result != null)
{
String userdn = entry.Properties["distinguishedName"].Value.ToString();
// Correct Case as stored in Active Directory
if (!result.Properties["member"].Contains(userdn)) // NB Case Sensitive
{
// add user to group
groupentry.Properties["member"].Add(userdn);
groupentry.CommitChanges();
}
}

Thanks for your help

Chris
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top