Managing property patterns

Property patterns can be created, edited, and deleted programmatically via the dedicated ADSI interfaces. You can apply the principles outlined in this article to write standalone scripts and programs or build custom integrations with third-party software. PowerShell scripts that manage business rules can also be executed from within Adaxes, for instance, from business rules, custom commands, and scheduled tasks.

Creating a property pattern

The following code sample creates a property pattern that applies to user accounts.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the property patterns container.
$containerPath = $service.Backend.GetConfigurationContainerPath("PropertyPatterns")
$container = $service.OpenObject($containerPath, $null, $null, 0)

# Create a new property pattern.
$pattern = $container.Create("adm-PropertyPattern", "CN=My Pattern")

$pattern.ObjectType = "user"
$pattern.Description = "My description"
$pattern.Disabled = $false

# Save the property pattern.
$pattern.SetInfo()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.PropertyPatterns;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the property patterns container.
        string containerPath = service.Backend.GetConfigurationContainerPath("PropertyPatterns");
        IADsContainer container = (IADsContainer)service.OpenObject(
            containerPath, null, null, 0);

        // Create a new property pattern.
        IAdmPropertyPattern pattern = (IAdmPropertyPattern)container.Create(
            "adm-PropertyPattern", "CN=My Pattern");

        pattern.ObjectType = "user";
        pattern.Description = "My description";
        pattern.Disabled = false;

        // Save the property pattern.
        pattern.SetInfo();
    }
}

Details

To create a property pattern, you need to connect to your Adaxes service and bind to the container where you want to create the pattern – for example, the root container for property patterns also known as the PropertyPatterns container.

If your script will be executed inside Adaxes, it becomes even simpler. You don't have to explicitly connect to your Adaxes service. Instead, you can use a predefined PowerShell variable $Context to get the ADS path of the PropertyPatterns container and bind to it.

# Bind to the property patterns container.
$containerPath = $Context.GetWellKnownContainerPath("PropertyPatterns")
$container = $Context.BindToObject($containerPath)
 How to create a property pattern in a different container

To create a property pattern in a specific container, you need to build the ADS path of that container and bind to it just like you would bind to the PropertyPatterns container. The AdsPath class contains methods that simplify manipulating ADS paths.

The following code sample creates a property pattern in the container named My Container. The property pattern will apply to Group objects.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Bind to the property patterns container.
$containerPath = $service.Backend.GetConfigurationContainerPath("PropertyPatterns")

# Build the ADS path of the nested container 'My Container' and bind to it.
$propertyPatternsPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $containerPath
$myContainerAdsPath = $propertyPatternsPathObj.CreateChildPath("CN=My Container")
$myContainer = $service.OpenObject($myContainerAdsPath, $null, $null, 0)

# Create a new property pattern.
$pattern = $myContainer.Create("adm-PropertyPattern", "CN=My Pattern")

$pattern.ObjectType = "group"
$pattern.Description = "My description"
$pattern.Disabled = $false

# Save the property pattern.
$pattern.SetInfo()
C#
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.PropertyPatterns;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Bind to the property patterns container.
        string containerPath = service.Backend.GetConfigurationContainerPath("PropertyPatterns");

        // Build the ADS path of the nested container 'My Container' and bind to it.
        AdsPath propertyPatternsPathObj = new AdsPath(containerPath);
        AdsPath myContainerAdsPath = propertyPatternsPathObj.CreateChildPath(
            "CN=My Container");

        IADsContainer myContainer = (IADsContainer)service.OpenObject(
            myContainerAdsPath.ToString(), null, null, 0);

        // Create a new property pattern.
        IAdmPropertyPattern pattern = (IAdmPropertyPattern)myContainer.Create(
            "adm-PropertyPattern", "CN=My Pattern");

        pattern.ObjectType = "group";
        pattern.Description = "My description";
        pattern.Disabled = false;

        // Save the property pattern.
        pattern.SetInfo();
    }
}

For information on how to create containers for property patterns, see Creating property pattern containers.

After binding to the container, call the Create method of the IADsContainer interface supported by all containers.

The method takes two parameters. The first one is the object type, "adm-PropertyPattern" in our case. The second one is a relative distinguished name of the new pattern.

Mandatory properties

The object returned by Create implements the IAdmPropertyPattern interface. Using this interface, you need to specify mandatory property pattern properties before you will be able to save it.

  • ObjectType – determines the type of objects the property pattern applies to. The object type name must be specified exactly as it is defined in your directory schema e.g. user, organizationalUnit.

Optional properties

You can specify optional property pattern properties before saving it.

  • Description – the pattern description.

  • Disabled – if set to true, the property pattern will be created in a disabled state.

Finally, save the property pattern by calling SetInfo.

Adding property pattern items

The following code sample adds a property pattern item for the Description property. The item includes a constraint that limits the minimum number of characters in the Description to 10.

PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "description"

# Add constraint.
$constraints = $item.GetConstraints()
$constraint = $constraints.Create("ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH")
$constraint.MinLength = 10
$constraints.Add($constraint)
$item.SetConstraints($constraints)

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)
C#
// The pattern variable refers to a property pattern.

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "description";

// Add constraint.
IAdmPropertyPatternConstraints constraints = item.GetConstraints();
IAdmValueLengthConstraint constraint = (IAdmValueLengthConstraint)constraints.Create(
    ADM_PROPERTYCONSTRAINTTYPE_ENUM.ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH);
constraint.MinLength = 10;
constraints.Add(constraint);
item.SetConstraints(constraints);

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);

Details

A property pattern item is an object that represents a directory object property and its constraints. To access the items of a particular property pattern, use the Items property of the IAdmPropertyPattern interface.

The items are stored as a collection that implements IAdmCollection, while each item implements IAdmPropertyPatternItem.

Call IAdmCollection::Create to create a new item and then use the methods and properties of IAdmPropertyPatternItem to configure it.

Mandatory properties

  • PropertyName – the name of the directory object property this item applies to. The property name must be specified exactly as it is defined in your schema, for example, title for the Job Title property.

Optional properties

  • IsPropertyRequired – set to true to mark the property as required.

  • DefaultValue – the default value of the property. To automatically generate the default value based on other properties, you can use value references. For example, "%title% of the %department% department".

  • GenerateDefaultValueDuringCreating – set to true to generate the default value during object creation.

    If an object is created manually and the property input field is present on the creation form, the default value will be generated even if this property is set to false.

  • GenerateDefaultValueDuringEditing – set to true to generate the default value when an object is edited.

    This property will take effect only if value references are used in the DefaultValue.

  • Hint – the hint text. This text will be displayed as a tooltip when hovering the mouse over the property input field, as well as inside the field when it is empty.

  • PropertyInfoMode – determines what to display when a user clicks the help button next to the property input field. For a list of possible values, see ADM_PROPERTYPATTERNINFOMODE_ENUM.

  • CustomHelpText – custom help text. HTML tags are supported in the text.

    This property will take effect only if PropertyInfoMode is set to ADM_PROPERTYPATTERNINFOMODE_HELP.

Constraints

Constraints define what is considered a valid value for the property. For example, you can set the minimum and maximum value length, enforce a regular expression pattern, allow only certain predefined values, etc.

To get the constraints of a property pattern item, call IAdmPropertyPatternItem::GetConstraints. The object returned by GetConstraints implements IAdmPropertyPatternConstraints.

To create a new constraint, call IAdmPropertyPatternConstraints::Create and pass the desired constraint type as a parameter. For a list of possible constraint types, see ADM_PROPERTYCONSTRAINTTYPE_ENUM. The object returned by Create will implement a specific interface based on the constraint type. Use its methods and properties to configure the constraint.

  • Description

  • Constraint type

  • Interface

  • Text constraints (e.g. 'must start with', 'must not contain')

  • ADM_PROPERTYCONSTRAINTTYPE_STRINGVALUE

  • IAdmStringValueConstraint

  • Must match regexp

  • ADM_PROPERTYCONSTRAINTTYPE_REGEXP

  • IAdmRegexpConstraint

  • Must be one of the following values only / Must not contain the following values

  • ADM_PROPERTYCONSTRAINTTYPE_VALUERANGE

  • IAdmValueRangeConstraint

  • Value length constraints

  • ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH

  • IAdmValueLengthConstraint

To add your new constraint back to the list, call IAdmPropertyPatternConstraints::Add and pass the constraint object as a parameter. You can create and add more constraints at this point. Note that there is a limit – a property pattern item can have one value length constraint plus one constraint of any other type.

To apply the list of constraints to the property pattern item, call IAdmPropertyPatternItem::SetConstraints and pass the list of constraints as a parameter.

Finally, save the property pattern item by calling SetInfo and add it to the property pattern using IAdmPropertyPattern::Items.Add.

Examples

 Example 1 – Mark the Department property as required and set the list of allowed values
PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "department"
$item.IsPropertyRequired = $true

# Set constraints.
$constraints = $item.GetConstraints()
$constraint = $constraints.Create("ADM_PROPERTYCONSTRAINTTYPE_VALUERANGE")
$constraint.AreValuesDenied = $false
$constraint.Values = @("IT", "HR", "Sales")
$constraints.Add($constraint)
$item.SetConstraints($constraints)

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)   
C#
// The pattern variable refers to a property pattern.

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "department";
item.IsPropertyRequired = true;

// Set constraints.
IAdmPropertyPatternConstraints constraints = item.GetConstraints();
IAdmValueRangeConstraint constraint = (IAdmValueRangeConstraint)constraints.Create(
    ADM_PROPERTYCONSTRAINTTYPE_ENUM.ADM_PROPERTYCONSTRAINTTYPE_VALUERANGE);
constraint.AreValuesDenied = false;
constraint.Values = new object[] { "IT", "HR", "Sales" };
constraints.Add(constraint);
item.SetConstraints(constraints);

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);
 Example 2 – Specify a template for generating the Web Page property during user creation
PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "wWWHomePage"
$item.DefaultValue = "http://www.example.com/Users/%username%/"
$item.GenerateDefaultValueDuringCreating = $true

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)
C#
// The pattern variable refers to a property pattern.

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "wWWHomePage";
item.DefaultValue = "http://www.example.com/Users/%username%/";
item.GenerateDefaultValueDuringCreating = true;

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);
 Example 3 – Apply a regular expression and maximum length constraints to the Telephone Number property
PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "telephoneNumber"

# Add regex constraint.
$constraints = $item.GetConstraints()
$regexConstraint = $constraints.Create("ADM_PROPERTYCONSTRAINTTYPE_REGEXP")
$regexConstraint.RegularExpression = "^([0-9\(\)\/\+ \-]*)$"
$regexConstraint.CustomErrorMessage = "Invalid phone number format!"
$constraints.Add($regexConstraint)

# Add max length constraint.
$maxLengthConstraint = $constraints.Create("ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH")
$maxLengthConstraint.MaxLength = 10
$constraints.Add($maxLengthConstraint)
$item.SetConstraints($constraints)

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)
C#
// The pattern variable refers to a property pattern.

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "telephoneNumber";

// Add regex constraint.
IAdmPropertyPatternConstraints constraints = item.GetConstraints();
IAdmRegexpConstraint regexConstraint = (IAdmRegexpConstraint)constraints.Create(
    ADM_PROPERTYCONSTRAINTTYPE_ENUM.ADM_PROPERTYCONSTRAINTTYPE_REGEXP);
regexConstraint.RegularExpression = "^([0-9\\(\\)\\/\\+ \\-]*)$";
regexConstraint.CustomErrorMessage = "Invalid phone number format!";
constraints.Add(regexConstraint);

// Add max length constraint.
IAdmValueLengthConstraint maxLengthConstraint = (IAdmValueLengthConstraint)constraints.Create(
    ADM_PROPERTYCONSTRAINTTYPE_ENUM.ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH);
maxLengthConstraint.MaxLength = 10;
constraints.Add(maxLengthConstraint);
item.SetConstraints(constraints);

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);
 Example 4 – Add a constraint for the Employee ID property so that values must not start from zero and must contain a dash
PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "employeeID"

# Set constraints.
$constraints = $item.GetConstraints()
$constraint = $constraints.Create("ADM_PROPERTYCONSTRAINTTYPE_STRINGVALUE")
$constraint.NotStartWith = "0"
$constraint.Contain = "-"
$constraints.Add($constraint)
$item.SetConstraints($constraints)

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)
C#
// The pattern variable refers to a property pattern

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "employeeID";

// Set constraints.
IAdmPropertyPatternConstraints constraints = item.GetConstraints();
IAdmStringValueConstraint constraint = (IAdmStringValueConstraint)constraints.Create(
        ADM_PROPERTYCONSTRAINTTYPE_ENUM.ADM_PROPERTYCONSTRAINTTYPE_STRINGVALUE);
constraint.NotStartWith = "0";
constraint.Contain = "-";
constraints.Add(constraint);
item.SetConstraints(constraints);

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);
 Example 5 – Provide custom hint and help for the Manager property
PowerShell
# The $pattern variable refers to a property pattern.

# Create a property pattern item.
$item = $pattern.Items.Create()
$item.PropertyName = "manager"

# Set hint and help text.
$item.Hint = "My hint"
$item.PropertyInfoMode ="ADM_PROPERTYPATTERNINFOMODE_HELP"
$item.CustomHelpText = "<h1>My Help</h1><p>My Text</p>"

# Save the changes.
$item.SetInfo()
$pattern.Items.Add($item)
C#
// The pattern variable refers to a property pattern.

// Create a property pattern item.
IAdmPropertyPatternItem item = (IAdmPropertyPatternItem)pattern.Items.Create();
item.PropertyName = "manager";

// Set hint and help text.
item.Hint = "My hint";
item.PropertyInfoMode = ADM_PROPERTYPATTERNINFOMODE_ENUM.ADM_PROPERTYPATTERNINFOMODE_HELP;
item.CustomHelpText = "<h1>My Help</h1><p>My Text</p>";

// Save the changes.
item.SetInfo();
pattern.Items.Add(item);

Defining the scope of activity

Use the ActivityScopeItems property of the IAdmPropertyPattern interface to define the activity scope for a property pattern. A pattern affects all objects within its scope. Activity scope can include domains, members of groups, business units, objects located in specific organizational units, etc.

For information on how to define the activity scope of a property pattern, see Defining the scope of activity.

Getting effective property patterns

To find out what property patterns are effective for a directory object, you need to connect to your Adaxes service and call the GetConfigurationQueries method of the IAdmService2 interface. The object returned by GetConfigurationQueries implements the IAdmConfigurationQueries interface that you can use to get effective property patterns.

Examples

The following code sample outputs the names and descriptions of all property patterns effective for the user John Smith.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object("Softerra.Adaxes.Adsi.AdmNamespace")
$service = $ns.GetServiceDirectly("localhost")

# Bind to the user.
$userDN = "CN=John Smith,CN=Users,DC=domain,DC=com"
$user = $service.OpenObject("Adaxes://$userDN", $null, $null, 0)

# Get information about effective property patterns.
$configurationQueries = $service.GetConfigurationQueries()
$effectivePropertyPatterns = $configurationQueries.GetEffectivePropertyPatterns($user)

Write-Host "Property patterns effective for the user:"
foreach ($propertyPatternInfo in $effectivePropertyPatterns)
{
    Write-Host "`tName:" $propertyPatternInfo.FullName
    Write-Host "`tDescription:" $propertyPatternInfo.Description
    Write-Host
}
C#
using System;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi;
using Softerra.Adaxes.Interop.Adsi.Management;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.PropertyPatterns;

class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService2 service = (IAdmService2)ns.GetServiceDirectly("localhost");

        // Bind to the user.
        const string userPath = "Adaxes://CN=John Smith,CN=Users,DC=domain,DC=com";
        IAdmTop user = (IAdmTop)service.OpenObject(userPath, null, null, 0);

        // Get information about effective property patterns.
        IAdmConfigurationQueries configurationQueries = service.GetConfigurationQueries();
        IAdmPropertyPatternInfo[] effectivePropertyPatterns =
            (IAdmPropertyPatternInfo[])configurationQueries.GetEffectivePropertyPatterns(user);

        Console.WriteLine("property patterns effective for the user:");
        foreach (IAdmPropertyPatternInfo propertyPatternInfo in effectivePropertyPatterns)
        {
            Console.WriteLine("\tName: " + propertyPatternInfo.FullName);
            Console.WriteLine("\tDescription: " + propertyPatternInfo.Description);
            Console.WriteLine();
        }
    }
}

The following code sample outputs the names and descriptions of all property patterns effective for multiple users.

PowerShell
$user1Path = "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com"
$user2Path = "Adaxes://CN=Bob Jones,CN=Users,DC=company,DC=com"

# Connect to the Adaxes service.
$ns = New-Object("Softerra.Adaxes.Adsi.AdmNamespace")
$service = $ns.GetServiceDirectly("localhost")

# Get information about effective property patterns.
$configurationQueries = $service.GetConfigurationQueries()
$effectivePropertyPatterns = $configurationQueries.GetEffectivePropertyPatternsEx(
    @($user1Path, $user2Path))

Write-Host "Property patterns effective for the users:"
foreach ($propertyPatternInfo in $effectivePropertyPatterns)
{
    Write-Host "`tName:" $propertyPatternInfo.FullName
    Write-Host "`tDescription:" $propertyPatternInfo.Description
    Write-Host
}
C#
using System;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.Management;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.PropertyPatterns;

class Program
{
    static void Main(string[] args)
    {
        const string user1Path = "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com";
        const string user2Path = "Adaxes://CN=Bob Jones,CN=Users,DC=company,DC=com";

        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService2 service = (IAdmService2)ns.GetServiceDirectly("localhost");

        // Get information about effective property patterns.
        IAdmConfigurationQueries configurationQueries = service.GetConfigurationQueries();
        IAdmPropertyPatternInfo[] effectivePropertyPatterns =
            (IAdmPropertyPatternInfo[])configurationQueries.GetEffectivePropertyPatternsEx(
                new string[] { user1Path, user2Path });

        Console.WriteLine("Property patterns effective for the users:");
        foreach (IAdmPropertyPatternInfo propertyPatternInfo in effectivePropertyPatterns)
        {
            Console.WriteLine("\tName: " + propertyPatternInfo.FullName);
            Console.WriteLine("\tDecription: " + propertyPatternInfo.Description);
            Console.WriteLine();
        }
    }
}

Modifying a property pattern

To modify an existing property pattern, you need to connect to your Adaxes service and bind to the directory object representing the pattern.

If your script will be executed inside Adaxes, it is even simpler. You don't have to explicitly connect to your Adaxes service. Instead, you can get the ADS path of the PropertyPatterns container and bind to a pattern using a predefined PowerShell variable $Context.

$container = $Context.GetWellKnownContainerPath("PropertyPatterns")
$patternsPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $container
$patternPath = $patternsPathObj.CreateChildPath("CN=My Pattern")
$pattern = $Context.BindToObject($patternPath)

After binding to the pattern, you can use the IAdmPropertyPattern and IADs interfaces to modify it. To save the changes, call SetInfo.

Example

The following code sample binds to the built-in User property pattern and deletes the property pattern item for the Description property.

PowerShell
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

# Connect to the Adaxes service.
$ns = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$service = $ns.GetServiceDirectly("localhost")

# Build the ADS path of the User property pattern and bind to it.
$containerPath = $service.Backend.GetConfigurationContainerPath("PropertyPatterns")
$propertyPatternsPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $containerPath
$builtinPathObj = $propertyPatternsPathObj.CreateChildPath("CN=Builtin")
$userPatternPath = $builtinPathObj.CreateChildPath("CN=User")

$pattern = $service.OpenObject($userPatternPath.ToString(),
    $null, $null, 0)

# Delete the item for the Description property.
foreach ($item in $pattern.Items)
{
    if ($item.PropertyName -ieq "description")
    {
        $pattern.Items.Remove($item)
        break
    }
}
C#
using System;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
using Softerra.Adaxes.Interop.Adsi.PropertyPatterns;
class Program
{
    static void Main(string[] args)
    {
        // Connect to the Adaxes service.
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Build the ADS path of the User property pattern and bind to it.
        string containerPath = service.Backend.GetConfigurationContainerPath("PropertyPatterns");
        AdsPath propertyPatternsPathObj = new AdsPath(containerPath);
        AdsPath builtinPathObj = propertyPatternsPathObj.CreateChildPath("CN=Builtin");
        AdsPath userPatternPath = builtinPathObj.CreateChildPath("CN=User");

        IAdmPropertyPattern pattern = (IAdmPropertyPattern)service.OpenObject(
            userPatternPath.ToString(), null, null, 0);

        // Delete the item for the Description property.
        foreach (IAdmPropertyPatternItem item in pattern.Items)
        {
            if (StringComparer.OrdinalIgnoreCase.Equals("description", item.PropertyName))
            {
                pattern.Items.Remove(item);
                break;
            }
        }
    }
}

See also