Managing property patterns

This article describes how to manage property patterns using PowerShell scripts and C# code. The code samples included in this article can be used in stand-alone scripts and applications as well as in PowerShell scripts executed by business rules, custom commands, and scheduled tasks.

Creating a property pattern

To create a property pattern, first you need to bind to the container where you want to create it. All container objects support the IADsContainer interface, which provides methods and properties that manage the creation, deletion, and enumeration of child objects. To create a new property pattern, you need to call the Create method of the interface and pass adm-PropertyPattern as the first parameter of the method and the relative distinguished name (RDN) of the pattern as the second parameter. The object returned by the IADsContainer::Create method will support the IAdmPropertyPattern interface, using which you can specify the parameters of the new property pattern.

Use the IAdmPropertyPattern::ObjectType property to specify the type of directory objects the property pattern will apply to. The property must be set to a string that contains the name of an object class as defined in the directory schema (e.g. user, group, computer, organizationalUnit). Using the IAdmPropertyPattern::AdditionalObjectType property, you can specify an additional type of objects to which the property pattern will be applied.

The following code sample creates a property pattern to be applied to user 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
$propertyPatternsPath = $service.Backend.GetConfigurationContainerPath(
    "PropertyPatterns")
$propertyPatternsContainer = $service.OpenObject($propertyPatternsPath,
    $null, $null, 0)

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

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

# Save the property pattern
$pattern.SetInfo()
C#
using System;
using Interop.Adsi;
using Interop.Adsi.PropertyPatterns;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
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 propertyPatternsPath = service.Backend.GetConfigurationContainerPath(
            "PropertyPatterns");
        IADsContainer propertyPatternsContainer = (IADsContainer)service.OpenObject(
            propertyPatternsPath, null, null, 0);

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

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

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

If your script is executed by a business rule, custom command or scheduled task, you can use a predefined PowerShell variable $Context to get the ADS path of the property patterns container and bind to the container. The type of the $Context variable is ExecuteScriptContext.

# Bind to the 'Property Patterns' container
$propertyPatternsPath = $Context.GetWellKnownContainerPath("PropertyPatterns")
$propertyPatternsContainer = $Context.BindToObject($propertyPatternsPath)

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

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

# Save the property pattern
$pattern.SetInfo()
 How to create a property pattern in a specific container

The following code sample creates a property pattern in the container called 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
$propertyPatternsPath = $service.Backend.GetConfigurationContainerPath(
    "PropertyPatterns")
# Build the ADS path of the child container 'My Container'
$propertyPatternsPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath"`
    $propertyPatternsPath
$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 System;
using Interop.Adsi;
using Interop.Adsi.PropertyPatterns;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
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 propertyPatternsPath = service.Backend.GetConfigurationContainerPath(
            "PropertyPatterns");
        // Build the ADS path of the child container 'My Container'
        AdsPath propertyPatternsPathObj = new AdsPath(propertyPatternsPath);
        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.

Modifying a property pattern

To modify an existing property pattern, first you need to bind to the directory object representing the property pattern. For more information on how to bind to Adaxes-specific objects, see Binding to Adaxes-specific objects.

After you've bound to a property pattern object, you can use ADSI interfaces like IAdmPropertyPattern and IADs to modify the property pattern.

The following code sample binds to a built-in property pattern, User 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
$propertyPatternsPath = $service.Backend.GetConfigurationContainerPath(
    "PropertyPatterns")
$propertyPatternsPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" `
    $propertyPatternsPath
$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 Interop.Adsi.PropertyPatterns;
using Softerra.Adaxes.Adsi;
using Softerra.Adaxes.Interop.Adsi.PersistentObjects;
class Program
{
    static void Main(string[] args)
    {
        AdmNamespace ns = new AdmNamespace();
        IAdmService service = ns.GetServiceDirectly("localhost");

        // Build the ADS path of the 'User' property pattern
        string propertyPatternsPath = service.Backend.GetConfigurationContainerPath(
            "PropertyPatterns");
        AdsPath propertyPatternsPathObj = new AdsPath(propertyPatternsPath);
        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;
            }
        }
    }
}

Adding a property pattern item

To apply a property pattern to a specific property, you need to add a property pattern item for the property. To access the collection of property pattern items, use the Items property of the IAdmPropertyPattern interface. The Items property supports the IAdmCollection interface, using which you can create, delete, and enumerate property pattern items.

To create a new property pattern item, call the Create method of the IAdmPropertyPattern::Items property. The object returned by the method will support the IAdmPropertyPatternItem interface, using which you can specify parameters of the new property pattern item.

  1. Specify the name of the property, to which the property pattern item will apply in the PropertyName property of the IAdmPropertyPatternItem interface. The value must be a string that contains the name of a directory object property as defined in the directory schema (e.g. department, cn, displayName, manager).

  2. Set IAdmPropertyPatternItem::IsPropertyRequired to true to mark the property as required.

  3. To set the default value for a property, use the DefaultValue property of the IAdmPropertyPatternItem interface.

    If you want the property value to be automatically generated based on values of other properties, use value references in the default property value. (e.g. %title% of the %department% department).

    If you want the property value to be generated during object creation, set IAdmPropertyPatternItem::GenerateDefaultValueDuringCreating to true.

    To enable automatic generation of the property value when an object is edited, set IAdmPropertyPatternItem::GenerateDefaultValueDuringEditing to true.

  4. To define constraints for a directory object property, use GetConstraints and SetConstraints methods of the IAdmPropertyPatternItem interface. Using constraints, you can set the minimum and maximum length of values, enforce a regular expression pattern, provide a list of possible values, etc.

    The GetConstraints method returns a collection of constraints represented by the IAdmPropertyPatternConstraints interface. To create a new constraint, call the Create method of the interface and pass the constraint type as the parameter of the method. For a list of possible constraint types, see the ADM_PROPERTYCONSTRAINTTYPE_ENUM enumeration.

    The table below shows which interfaces are supported by different constraint types.

    Description Type Interface
    Text constraints (e.g. 'must start with', 'must not contain') ADM_PROPERTYCONSTRAINTTYPE_STRINGVALUE IAdmStringValueConstraint
    'Must match regexp' ADM_PROPERTYCONSTRAINTTYPE_REGEXP IAdmRegexpConstraint
    Value range constraints (e.g. 'Must be one of the following values') ADM_PROPERTYCONSTRAINTTYPE_VALUERANGE IAdmValueRangeConstraint
    Value length constraints ADM_PROPERTYCONSTRAINTTYPE_VALUELENGTH IAdmValueLengthConstraint

    To add a constraint to the list of constraints, call the Add method of the IAdmPropertyPatternConstraints interface.

    To apply constraints to a property pattern item, call the SetConstraints method of the item object.

  5. To set hint text for a property, use the Hint property of the IAdmPropertyPatternItem interface. The hint text is displayed in a tooltip when moving the mouse over the property input field. When possible, the hint text is also displayed inside the input field (as long as the field is empty).

  6. To provide custom help for a property:

    • Set IAdmPropertyPatternItem::PropertyInfoMode to ADM_PROPERTYPATTERNINFOMODE_HELP.
    • Provide the help text via the IAdmPropertyPatternItem::CustomHelpText property. You can use HTML tags in the help text.

In order to add a property pattern item to a property pattern, call the Add method of the IAdmPropertyPattern::Items property.

Example 1 – Mark the Department property as required and provide a list of possible values for the property

PowerShell
# The $pattern variable refers to a property pattern

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

$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

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

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 generation of the Web Page property during user creation

PowerShell
# The $pattern variable refers to a property pattern

$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

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

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

Example 3 – Apply a regular expression constraint to the Telephone Number property

PowerShell
# The $pattern variable refers to a property pattern

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

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

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

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

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

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

Example 4 – Add a constraint for the Employee ID property saying that values of the property must not start from zero and must contain a dash

PowerShell
# The $pattern variable refers to a property pattern

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

$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

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

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 – Set the minimum and maximum length of the Description property

PowerShell
# The $pattern variable refers to a property pattern

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

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

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

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

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

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

Example 6 – Provide custom hint and help for the Manager property

PowerShell
# The $pattern variable refers to a property pattern

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

$item.Hint = "My hint"
$item.PropertyInfoMode ="ADM_PROPERTYPATTERNINFOMODE_HELP"
$item.CustomHelpText = "<h1>My Help</h1>My Text"

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

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

IAdmPropertyPatternItem item3 = (IAdmPropertyPatternItem)item;
item3.Hint = "My hint";
item3.PropertyInfoMode =
ADM_PROPERTYPATTERNINFOMODE_ENUM.ADM_PROPERTYPATTERNINFOMODE_HELP;
item3.CustomHelpText = "<h1>My Help</h1>My Text";

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

Defining the scope of activity

The activity scope of a property pattern determines the objects affected by the pattern. Activity scope can include whole domains, members of groups and business units, objects located in specific Organizational Units, etc.

To define the scope of activity of a property pattern, you need to use the ActivityScopeItems property of the IAdmPropertyPattern interface.

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

Getting effective property patterns

To get property patterns effective for directory objects, first, you need to bind to the container where all property patterns are stored. For information on how to bind to the container, see Binding to ADSI objects.

The container for property patterns supports the IAdmPropertyPatternContainer interface, methods of which can be used to retrieve property patterns effective for objects.

Example 1 – Output property patterns effective for a user

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
$propertyPatternsPath = $service.Backend.GetConfigurationContainerPath("PropertyPatterns")
$propertyPatternsContainer = $service.OpenObject($propertyPatternsPath, $null, $null, 0)

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

# Get effective property patterns
$propertyPatternsGuidsBytes = $propertyPatternsContainer.GetEffectivePropertyPatterns($user)

Write-Host "Property patterns effective for the user:"
foreach ($guidBytes in $propertyPatternsGuidsBytes)
{
    # Bind to the property pattern
    $guid = [Guid]$guidBytes
    $patternPath = "Adaxes://<GUID=$guid>"
    $pattern = $service.OpenObject($patternPath, $null, $null, 0)

    # Output information about the property pattern
    Write-Host "`tName:" $pattern.PatternName
    Write-Host "`tDescription:" $pattern.Description
    Write-Host
}
C#
using System;
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();
        IAdmService2 service = (IAdmService2)ns.GetServiceDirectly("localhost");

        // Bind to the 'Property Patterns' container
        string propertyPatternsPath = service.Backend.GetConfigurationContainerPath("PropertyPatterns");
        IAdmPropertyPatternContainer propertyPatternsContainer =
            (IAdmPropertyPatternContainer)service.OpenObject(propertyPatternsPath, null, null, 0);

        // 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 effective property patterns
        object[] propertyPatternsGuidsBytes =
            (object[])propertyPatternsContainer.GetEffectivePropertyPatterns(user);

        Console.WriteLine("Property patterns effective for the user:");
        foreach (byte[] guidBytes in propertyPatternsGuidsBytes)
        {
            //Bind to the property pattern
            string guid = new Guid(guidBytes).ToString("B");
            string patternPath = string.Format("Adaxes://<GUID={0}>", guid);
            IAdmPropertyPattern pattern = (IAdmPropertyPattern)service.OpenObject(
                patternPath, null, null, 0);


            // Output information about the property pattern
            Console.WriteLine("\tName: " + pattern.PatternName);
            Console.WriteLine("\tDescription: " + pattern.Description);
            Console.WriteLine();
        }
    }
}

Example 2 – Output property patterns effective for multiple users

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
$propertyPatternsPath = $service.Backend.GetConfigurationContainerPath("PropertyPatterns")
$propertyPatternsContainer = $service.OpenObject($propertyPatternsPath, $null, $null, 0)

# User paths
$user1 = "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com"
$user2 = "Adaxes://CN=Bob Jones,CN=Users,DC=company,DC=com"
$userPaths = @($user1, $user2)

# Get effective property patterns
$propertyPatternsGuidsBytes = 
    $propertyPatternsContainer.GetEffectivePropertyPatternsEx($userPaths)

Write-Host "Property patterns effective for the users:"
foreach ($guidBytes in $propertyPatternsGuidsBytes)
{
    # Bint to the property pattern
    $guid = [Guid]$guidBytes
    $patternPath = "Adaxes://<GUID=$guid>"
    $pattern = $service.OpenObject($patternPath, $null, $null, 0)

    # Output information about the property pattern
    Write-Host "`tName:" $pattern.PatternName
    Write-Host "`tDescription:" $pattern.Description
    Write-Host
}
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();
        IAdmService2 service = (IAdmService2)ns.GetServiceDirectly("localhost");

        // Bind to the 'Property Patterns' container
        string propertyPatternsPath = service.Backend.GetConfigurationContainerPath(
            "PropertyPatterns");
        IAdmPropertyPatternContainer propertyPatternsContainer =
            (IAdmPropertyPatternContainer)service.OpenObject(propertyPatternsPath, null, null, 0);

        // User paths
        const string user1 = "Adaxes://CN=John Smith,CN=Users,DC=company,DC=com";
        const string user2 = "Adaxes://CN=Bob Jones,CN=Users,DC=company,DC=com";
        string[] userPaths = { user1, user2 };

        // Get effective property patterns
        object[] propertyPatternsGuidsBytes =
            (object[])propertyPatternsContainer.GetEffectivePropertyPatternsEx(userPaths);

        Console.WriteLine("Property patterns effective for the user:");
        foreach (byte[] guidBytes in propertyPatternsGuidsBytes)
        {
            // Bind to the property pattern
            string guid = new Guid(guidBytes).ToString("B");
            string patternPath = string.Format("Adaxes://<GUID={0}>", guid);
            IAdmPropertyPattern pattern = (IAdmPropertyPattern)service.OpenObject(
                patternPath, null, null, 0);

            // Output information about the property pattern
            Console.WriteLine("\tName: " + pattern.PatternName);
            Console.WriteLine("\tDescription: " + pattern.Description);
            Console.WriteLine();
        }
    }
}

See also