I'm trying to search for users in an instance of AD LDS (ADAM) where a property is not set, for example where the "company" property is not set to a value in the ADAM store (or AD for that matter).
When I use a PrincipalSearcher
and a custom UserPrincipal
with a custom AdvancedSearchFilters
object, I get the error:
An unhandled exception of type 'System.ArgumentException' occurred in System.DirectoryServices.dll Additional information: The (&(objectClass=user)(!(company=))) search filter is invalid.
Here is my sample code:
using System;
using System.DirectoryServices.AccountManagement;
using System.Security.Permissions;
using System.Linq;
namespace AdamDump
{
class Program
{
static void Main(string[] args)
{
PrincipalContext context = new PrincipalContext(ContextType.ApplicationDirectory, "MyAdamInstance:50000", "OU=Adam Users,dc=apps01,dc=mydomain", "queryaccount", "password");
// initialize a Query By Example
using (MyUserPrincipal myUserPrincipal = new MyUserPrincipal(context))
{
myUserPrincipal.MyAdvancedFilters.WhereCompanyNotSet();
PrincipalSearchResult<Principal> principals = null;
// do the search...
using (PrincipalSearcher principalSearcher = new PrincipalSearcher(myUserPrincipal))
{
principals = principalSearcher.FindAll();
}
var myUsers = principals.Select(principal => principal as MyUserPrincipal).ToList();
foreach (var user in myUsers)
Console.WriteLine("Name: {0}, Account{1}", user.DisplayName, user.SamAccountName);
Console.WriteLine("Total found: {0}", myUsers.Count);
}
}
}
[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
public class MyUserPrincipal : UserPrincipal
{
private MyAdvancedFilters _myAdvancedFilters;
/// <summary>
/// Initializes a new instance of the <see cref="MyUserPrincipal"/> class.
/// </summary>
/// <param name="context">A <see cref="PrincipalContext"/> to associate this instance with.</param>
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted=true)]
public MyUserPrincipal(PrincipalContext context)
: base(context) { }
public MyAdvancedFilters MyAdvancedFilters
{
get
{
return this.AdvancedSearchFilter as MyAdvancedFilters;
}
}
public override AdvancedFilters AdvancedSearchFilter
{
get
{
if (_myAdvancedFilters == null)
{
_myAdvancedFilters = new MyAdvancedFilters(this);
}
return _myAdvancedFilters;
}
}
}
public class MyAdvancedFilters : AdvancedFilters
{
/// <summary>
/// Initializes a new instance of the <see cref="MyAdvancedFilters"/> class.
/// </summary>
/// <param name="principal">The source <see cref="Principal"/></param>
public MyAdvancedFilters(Principal principal) : base(principal) { }
public void WhereCompanyNotSet()
{
this.AdvancedFilterSet("company", "", typeof(string), MatchType.NotEquals);
}
}
}
Modifying my AdvanceFilters class to the following gets the results I need.
public class MyAdvancedFilters : AdvancedFilters
{
/// <summary>
/// Initializes a new instance of the <see cref="MyAdvancedFilters"/> class.
/// </summary>
/// <param name="principal">The source <see cref="Principal"/></param>
public MyAdvancedFilters(Principal principal) : base(principal) { }
public void WhereCompanyNotSet()
{
this.AdvancedFilterSet("company", "*", typeof(string), MatchType.NotEquals);
}
}
It is the "*" for the value part in the AdvancedFilterSet.
Thanks to Sean for leading to the right trail to come up with the answer appropriate for the AccountManagement objects.