Management Agent Rules Extensions

Applies To: Windows Server 2003 with SP1

Previous Sections in This Guide

Generally, you prepare one rules extension .dll for each management agent with rules that are defined as extension implemented. Your rules extension .dll must include rule logic for all rules defined as extension implemented.

Creating a Management Agent Rules Extension Project

This section tells you how to set up a management agent rules extension project. To create a project, you must be a member of the MIISAdmins security group. Because MIIS 2003 prepopulates your project template with code stubs for the rules extensions that are defined in the user interface, it is useful to specify the rules extensions in the user interface before creating the rules extension project. Subsequent modifications to rules extensions through the MIIS 2003 UI are not reflected in your project, so you have to make these changes manually.

To create a management agent rules extension project from within MIIS 2003

  1. In the MIIS 2003 UI, select Management Agents.

  2. Select the management agent for which you wish to create an extension project.

  3. In the Actions pane, click Create Rules Extension. The rules extension project defaults to Visual Basic .NET 2003 as a programming language.

  4. Select Visual C# .NET 2003, if desired.

  5. Give your project a different name from all other extension projects within the solution. MIIS 2003 supplies a default project name based on the name of the management agent you select; you can change this if you wish. By default, Visual Studio .NET 2003 builds a .dll with the same name as your project, and the .dll is created in the MIIS 2003 Extensions folder. A valid rules extension name can contain uppercase and lowercase letters A through Z, dashes (-), underscores (_), and spaces. Other characters are not permitted, and the name of your rules extension cannot be a reserved system file name.

  6. If you want to change the default folder in which the project is created, click Browse….

  7. Select the Launch in Visual Studio .NET IDE checkbox to launch a Visual Studio .NET 2003 project in the integrated development environment (IDE).

  8. If necessary, create your controlling XML file.

  9. Create a folder within your rules extension’s project (source) folder (not within the MIIS 2003 Extensions folder). Use this folder to store copies of files that relate to your project, such as template files for file-based management agents or XML control files.

  10. Consider creating a single Visual Studio .NET 2003 solution to contain all of your MIIS 2003 projects, because MIIS 2003 creates a new Visual Studio .NET 2003 solution and project each time you build a rules extension through the UI. This single-solution approach facilitates debugging across projects, as well as it increases the manageability of your projects. Also consider adding any related files (from step 9) to your new Visual Studio .NET 2003 solution.

Using the Management Agent Rules Extension Initialize and Terminate Methods

A connector filter can be defined for each object type and determines whether an object should remain, or be converted to, a disconnector object, (which can either be a normal or explicit disconnector) in the connector space. The connector filter prevents these objects from being further processed by the synchronization and rules engines. It also disconnects objects that are already connected. The only exception is explicit connectors, which have been manually joined.

If a filter rule has been defined as extension implemented, the FilterForDisconnection function is called, and you must provide appropriate code in place of the default code. FilterForDisconnection returns True if the object is to become a disconnector.

FilterForDisconnection Parameters

csentry

It is passed a CSentry object; you can use this to examine the connector space object’s attribute values and properties.

Object Scope

In the UI, a management agent might handle multiple object types, and the filter rule can be defined as extension implemented for each object type. Because there is only one FilterForDisconnection function per management agent rules extension .dll, you must allow for object scope in your code. You can determine the object type from the ObjectType property of csentry.

Example

The following code disconnects a connector space object if the ObjectType is “person” and the DateTerminated attribute is less than 1990/01/01, assuming that the DateTerminated attribute is a string in the format yyyy/MM/dd.

Public Function FilterForDisconnection(ByVal csentry As CSEntry) As Boolean _ 
Implements IMASynchronization.FilterForDisconnection
   If csentry("DateTerminated").IsPresent AndAlso
csentry.ObjectType.Equals("person") Then  
       FilterForDisconnection = csentry("DateTerminated").Value < "1990/01/01"    End If
End Function

Using the Join Conditions Method

A join rule is made of a number of conditions. Each direct condition, or condition that is configured in the UI, tests the single value held in the specified connector space object attribute against the value held in the specified attribute of every metaverse object. You can specify that any condition is extension implemented. If a rules extension has been specified for a join, MapAttributesForJoin is called, and you must provide code that returns a collection of match requests.

MapAttributesForJoin Parameters

FlowRuleName

This parameter is used to decide which section of code to run. Generally, you have a number of rules.

csentry

From this parameter you can only use those attributes in read-only mode that are selected in the UI during rule definition.

values

This is a value collection that returns the values that are to be tested against the metaverse attribute that is selected in the UI during rule definition

The main purpose of rules extensions is to fill Values with all the values you would like to be used in the join.

Example

The following code provides a list of possible alternative values for matching a title attribute in the metaverse. If the connector space title attribute is “Doctor,” “Doc,” or “Dr,” or any combination of upper and lower case characters that combine to match the strings “doctor,” “doc,” or “dr,” when converted to lower case, MIIS 2003 should consider any metaverse objects that match “Doctor,” “Doc,” or “Dr,” as potential matches. MIIS 2003 also uses any other join conditions that have been specified in the UI to refine the matching process.

Public Sub MapAttributesForJoin(ByVal FlowRuleName As String, _ 
ByVal csentry As CSEntry, _ 
ByRef values As ValueCollection) Implements _
IMASynchronization.MapAttributesForJoin
   Select Case FlowRuleName
      Case "FindTitle"
         Select Case CSEntry("title").Value.ToLower
             Case "doctor","doc","dr"
                 values.Add("Doctor")
                 values.Add("Doc")
                 values.Add("Dr")
             Case Else
                 values.Add(CSEntry("title").Value)
          End Select
      Case Else
            Throw New UnexpectedDataException("Unexpected join flow rule name:"
& FlowRuleName)
   End Select
End Sub

In the discussion and code above, whatever rules have been used for building the metaverse have not enforced the consistency of this data; a best practice is to aim for a reliable and consistent metaverse, in which case the above rule could be greatly simplified.

Using the Join Resolution Function

A join rule might return a collection of join candidates unless a join for an attribute can be relied upon to hold a unique attribute. You can use a join resolution rule to provide final resolution for the join. Even if only one candidate is produced, further analysis might still be required. Join resolution rules are always extension implemented. The ResolveJoinSearch function is called if it has been enabled in the MIIS 2003 UI and if the associated join rule finds at least one match.

ResolveJoinSearch returns True if the join has been resolved. This function can be used to log information about a failed join, which can be acted upon by a manual process (in which case a False is returned). This strategy might well be preferable to an imperfect attempt to resolve the join programmatically.

ResolveJoinSearch Parameters

joinCriteriaName

This is a rule name that you provide and that is used to decide which code to run. Generally, you have a number of rules.

Csentry

All attributes can be used when ResolveJoinSearch is invoked (in read-only mode).

rgmventry()

This parameter limits the collection of candidate metaverse objects used in the function.

Imventry

This parameter returns the index number of the chosen rgmventry, or -1 if there is no join.

MVObjectClass

This returns the type of metaverse object, such as Person, to which the metaverse object should be changed (if necessary). If not provided, then the metaverse object type is not changed.

Example

The following code attempts to resolve a potential join list by checking if the City attribute of the connector space object matches the l(location) attribute of the metaverse object.

  Public Function ResolveJoinSearch(ByVal joinCriteriaName As String, _
            ByVal csentry As CSEntry, _
            ByVal rgmventry() As MVEntry, _
            ByRef imventry As Integer, _
            ByRef MVObjectType As String) As Boolean _ 
Implements IMASynchronization.ResolveJoinSearch
        Dim mventry As MVEntry
        Dim i As Int16
        imventry = -1
        ResolveJoinSearch = False

        For Each mventry In rgmventry
            If mventry("l").Value.Equals(csentry("city").Value) Then
                ResolveJoinSearch = True
                imventry = i
    Exit For
            End If
            i += 1
        Next
    End Function

This code does not check for another match for city. In a real implementation, you would probably want to perform additional tests and not just join to the first object that matched your criteria.

Using the Projection Function

When any join rules have been applied, if none was successful, or if there were no join rules, the synchronization process applies any projection rules to disconnectors (connector space objects that are not currently connected to a metaverse object). Projection rules are only run if any join rules have failed to resolve a single join candidate. A declared (UI) projection rule simply creates a new metaverse object of the selected type and links it to the connector space object being processed. If a projection rule has been configured as extension implemented, the ShouldProjectToMV function is called. This function analyzes the information available and decides whether a new object should be projected.

ShouldProjectToMV returns True if the object should be projected.

ShouldProjectToMV Parameters

Csentry

From this parameter all attributes can be used (in read-only mode).

MVObjectType

This parameter returns the object name to be projected into the metaverse.

Example

The following code projects a person object into the metaverse if the employeeType attribute contains either employee or contractor. A contact object is created for ExternalContractors, and temporary staff members are not projected into the metaverse. An error is thrown if an invalid employee type is provided. This error message is displayed in the MIIS 2003 UI if an attempt is made to synchronize an object that does not have an employee type that matches one of the permitted values.

Public Function ShouldProjectToMV(ByVal csentry As CSEntry, _ 
ByRef MVObjectType As String) As Boolean Implements _
IMASynchronization.ShouldProjectToMV
   Select Case csentry("employeeType").Value.ToLower
      Case "employee", "contractor"
         MVObjectType = "person"
         ShouldProjectToMV = True
      Case "externalcontractor"
         MVObjectType = "contact"
         ShouldProjectToMV = True
      Case "temporary"
         ShouldProjectToMV = False
      Case Else
         Throw New UnexpectedDataException("Unexpected employeeType=" _ 
& csentry("employeeType").Value)
   End Select
End Function

Using the Import Attribute Flow Method

An import attribute flow rule is used during inbound synchronization to flow the value of one or more connector space object attributes, a constant value, or a component of a distinguished name (DN) to a metaverse object attribute. For example, a rules extension flow rule enables you to generate a value based on a number of connector space object attributes, and assign it to a metaverse object attribute. If an import attribute flow rule has been specified as extension implemented, the MapAttributesForImport method is called.

MapAttributesForImport Parameters

FlowRuleName

This parameter is used to decide which section of code to run. Generally, you have a number of rules.

csentry

Only the attributes that were selected in the UI can be accessed (these are read-only).

mventry

All attributes can be read, but only the attribute selected in the UI can be written to.

Example

The following example shows a simple implementation of an attribute flow rule:

Public Sub MapAttributesForImport(ByVal FlowRuleName As String, ByVal csentry _
    As CSEntry, ByVal mventry As MVEntry) Implements _
    IMASynchronization.MapAttributesForImport
    Select Case FlowRuleName.ToUpper
        Case "SWAPNAMES"
            If csentry("displayName").IsPresent Then
                Dim pos As Integer = csentry("displayName").Value.IndexOf(",")
                mventry("displayName").Value = csentry("displayName").Value. _
                    Substring(pos + 2) + " " + csentry("displayName"). _
                    Value.Substring(0, pos)
            End If
        Case Else
            Throw New EntryPointNotImplementedException()
    End Select
End Sub
Hints and Tips for Import Attribute flow

Precedence

Any number of rules can provide the same metaverse attribute within the same management agent or in different ones. In these circumstances, precedence must be established. Through the UI, a simple order or precedence can be established between rules, whether the rules are extension implemented or not.

However, if all import attribute flow rules are extension implemented, you can override MIIS 2003’s precedence rule by selecting “Use manual precedence” in the UI. Then, your MapAttributesForImport code must determine which management agent flows a value to the metaverse attribute. For example, the following code only flows a title attribute if one is provided and there is no title already in the metaverse or if this management agent was the last one to provide a value for the attribute. The first management agent to flow a value to the metaverse attribute “owns” the attribute, and only that management agent is able to change the attribute. This code uses the LastContributingMA property for an MVEntry.

Public Sub MapAttributesForImport(ByVal FlowRuleName As String, _ 
ByVal csentry As Microsoft.MetadirectoryServices.CSEntry,_ 
ByVal mventry As Microsoft.MetadirectoryServices.MVEntry) Implements _ Microsoft.MetadirectoryServices.IMASynchronization.MapAttributesForImport
  Select Case FlowRuleName
  ' other cases here
  Case "title"
     If Not mventry("title").IsPresent OrElse _ 
 csentry.MA.Name.Equals(mventry("title").LastContributingMA.Name) then
            If csentry("JobTitle").IsPresent Then
                 mventry("title").Value = csentry("JobTitle").Value
            Else
                 Throw New UnexpectedDataException("JobTitle missing")
            End If
     End If
  Case Else
     Throw New UnexpectedDataException("Unexpected import flow rule name:"
& FlowRuleName)

  End Select
End Sub

Checking for Attribute Presence

In the example above, check for the presence of both the metaverse title attribute and connector space JobTitle attribute before attempting to use them. Always check your assumptions about data that you cannot guarantee to be valid or even present. It might seem obvious that you should check an attribute from a connected data source when you know that a user could have manually entered data into it, but also consider the validity of any metaverse attributes that have not come from a trusted source. A trusted source is direct flow that comes only from connector space attributes that is known to be correct or from a well written set of management agent rule extensions that checks the data and won’t permit the creation of invalid objects or attributes.

AndElse and OrElse

VB .NET now has these two conditional operators that help you optimize your code for performance and robustness. There is a difference between the OrElse operator and the Or operator. The Or operator evaluates both expressions before returning a True or False value; OrElse does not evaluate the second expression if the first part returns True. If the code sample above uses Or, and if the title is not present, the code throws an error. Similarly, the AndAlso operator behaves differently than the And operator. The And operator always causes the evaluation of both expressions while AndAlso does not evaluate the second expression if the first expression returns False.

Using the Export Attribute Flow Method

A declarative export attribute flow rule is used during outbound synchronization to flow the value of one or more metaverse object attributes, or a constant value, to a connector space object attribute. For example, a rules extension flow rule enables you to generate a value based on a number of metaverse attributes and assign it to a connector space object attribute. If an export attribute flow rule has been defined as extension implemented, the MapAttributesForExport method is called.

MapAttributesForExport Parameters

FlowRuleName

This parameter is used to decide which section of code to run. Generally, you have a number of rules.

csentry

Only the attribute selected in the UI and all attributes accessed as read-only can be written.

mventry

Only the attributes that were selected in the UI can be accessed. These are read-only.

Example

In the example below, Active Directory user accounts are enabled or disabled depending on the value contained in the metaverse attribute employeeStatus. If employeeStatus = “active,” the account is enabled. Otherwise, it is disabled.

Public Sub MapAttributesForExport(ByVal FlowRuleName As String, _ 
ByVal mventry As Microsoft.MetadirectoryServices.MVEntry, _ 
ByVal csentry As Microsoft.MetadirectoryServices.CSEntry) Implements _
Microsoft.MetadirectoryServices.IMASynchronization.MapAttributesForExport
    Const UF_ACCOUNTDISABLE = &H2
    Const UF_NORMAL_ACCOUNT = &H200
    Select Case FlowRuleName
    Case "userAccountControl"
        Dim currentValue As Long
        If mventry("employeeStatus").IsPresent Then
            If csentry("userAccountControl").IsPresent Then
               currentValue = csentry("userAccountControl").IntegerValue
            Else
               currentValue = UF_NORMAL_ACCOUNT
            End If
            Select Case mventry("employeeStatus").Value.ToLower
            Case "active"
                csentry("userAccountControl").IntegerValue = (currentValue Or _
                          UF_NORMAL_ACCOUNT)  And (Not UF_ACCOUNTDISABLE)
            Case Else
                csentry("userAccountControl").IntegerValue = currentValue Or _
                          UF_ACCOUNTDISABLE
            End Select
        End If
    Case Else
      Throw New UnexpectedDataException("Unexpected export flow rule name:"
& FlowRuleName)
    End Select
End Sub

Using the Deprovisioning Function

Deprovisioning is the process of managing connector space objects after they are disconnected from a metaverse object because the metaverse object has been deleted or the provisioning (or other) code has used a disconnect method.

You can:

  • remove the connector space object permanently, which results in a deletion being exported to the connected data source, which in turn typically results in an actual deletion, or

  • keep the connector space object as a normal disconnector, in which case it takes part in future synchronizations, with the potential to project or join to a metaverse object in future, depending on the rules defined, or

  • keep the connector space object as an explicit disconnector, in which case it takes no further part in future synchronizations.

If a deprovisioning rule has been defined as extension implemented, the Deprovision function is called. This function evaluates the connector space object and decides on one of the above outcomes by setting Deprovision to one of these three values:

  • Deprovision.Disconnect

  • Deprovision.ExplicitDisconnect

  • Deprovision.Delete

The first two options also enable you to modify attributes and object location by changing the DN. The function can modify any attributes or the DN property.

Deprovision Parameters

csentry

All attributes can be used in read-write mode.

Example

The example below shows a simple implementation of a deprovisioning rule. In this example:

  • a temporary contractor is deleted;

  • a permanent contractor is moved to an inactive Contractors OU;

  • an employee is moved into an inactive employee organizational unit.

Public Function Deprovision(ByVal csentry As CSEntry) As DeprovisionAction _
Implements IMASynchronization.Deprovision
    ' set the default return value to leave object as a disconnector
    Deprovision = Deprovision.Disconnect
    Dim employeeType As String = csentry("employeeType").Value.ToUpper
    Dim objectSource As String = csentry("source").Value.ToUpper
    Dim container As String = ""

    If objectSource.Equals("CONTRACTOR") Then
        If employeeType.Equals("TEMP") Then
            Deprovision = Deprovision.Delete
            Exit Function
        Else
            container = "OU=InactiveCS,OU=People,DC=fabrikam,DC=com"
        End If
    Else
        container = "OU=Inactive,OU=People,DC=fabrikam,DC=com"
    End If

    csentry.DN = csentry.MA.EscapeDNComponent(csentry.RDN).Concat(container)
    csentry("employeeStatus").Value = "inactive"
End Function

Building a Metaverse Rules Extension

Generally, you prepare one rules extension .dll for the metaverse. Your rules extension .dll must include rule logic for rules defined as extension implemented. The provisioning rule can only be extension implemented.

The following procedure details how to create a metaverse rules extension project. To create a project, you must be a member of the MIISAdmins security group.

To create a metaverse rules extension project

  1. On the Tools menu of the UI, click Configure Extensions.

  2. Select the Enable Metaverse Rules Extension check box, and provide a name for the file to contain the extension code.

  3. Select the Run this extension in a separate process check box if the extension module is to run in a separate process from MIIS 2003.

  4. Select the Enable Provisioning Rules Extension check box if you want to enable provisioning.

  5. In the GlobalRules Extension Settings portion of the display, specify if you want to unload the rules extension when the duration of a single operation exceeds a certain value. The default value is 60 seconds. This also applies to management agent rules extensions.

  6. Click Create Rules Extension Project. The rules extension project defaults to Visual Basic .NET 2003 as a programming language. If desired, select Visual C# .NET 2003, if desired.

  7. MIIS 2003 supplies a default project name of MVExtension. You might change this if you wish. By default, Visual Studio .NET 2003 builds a .dll with the same name as your project and stores it in the MIIS 2003 Extensions directory. Therefore, it is essential to ensure that your project has a different name from all other rules extension projects within the solution. A valid rules extension name can contain uppercase and lowercase letters A through Z, dashes (-), underscores (_), and spaces. Other characters are not permitted and it cannot be a reserved system file name.

  8. If you want to change the default folder in which the project is created, click Browse….

  9. Select the Launch in VS .Net IDE box to launch a Visual Studio .NET 2003 project in the IDE.

  10. If necessary, create an initialization file to hold configuration information; save this file in the Extensions folder for MIIS 2003.

Using the Metaverse Rules Extension Initialize and Terminate Methods

Your rules extension .dll contains an Initialize method, which you can use to include code for any preprocessing work that the rules extensions in the .dll might require. For example, you might place code here to read an XML file that contains constants for the rule extensions or make a connection to a database. MIIS 2003 only loads the .dll when it determines that a call will be made to a rules extension in the .dll. After loading the .dll, MIIS 2003 calls Initialize prior to making the first call to the rules extension.

The rules extension .dll also contains a Terminate method, in which you can include code for cleanly releasing resources before the .dll is unloaded. For example, if you connected to a database in the Initialize method, yourTerminate code would close this connection. As with management agent rules extensions, although the current version of MIIS 2003 calls Terminate when no rules extension is called within a 5-minute interval, you should not build your rules assuming that this will be the case in the future.

Using the Metaverse Object Deletion Function

In MIIS 2003, a metaverse object is deleted when its last connector disconnects, without any further processing. Through the UI you can also choose to have a metaverse object deleted when a connector associated with a particular management agent disconnects, or you can choose to use a rules extension. If the metaverse object deletion rule has been defined as extension implemented, then the ShouldDeleteFromMV function is called.

ShouldDeleteFromMV returns True if the Metaverse object should be deleted.

ShouldDeleteFromMV Parameters

csentry

This parameter is the connector space object that is being disconnected from the metaverse.

mventry

This parameter is the Metaverse object that was linked to the connector space object and is the candidate for deletion.

Example

The following example shows an implementation of the metaverse object deletion function; the intention is that this function deletes the mventry if the csentry that projected it disconnects. In fact, the logic relies on a particular attribute (uid in this case) being provided only by the csentry that projected it, and you can usually find such an attribute by analyzing the rules used to populate the metaverse.

Public Function ShouldDeleteFromMV(ByVal csentry As CSEntry, ByVal mventry As
MVEntry) As Boolean Implements IMVSynchronization.Should DeleteFromMV

    ShouldDeleteFromMV = False

    If csentry.MA.Name = mventry.("uid").LastContributingMA.Name then
        ShouldDeleteFromMV = True
    End If

End Function

Using the Provisioning Method

A provisioning rule is used after inbound management agent synchronization rules are applied and before any management agent outbound synchronization rules are applied. The provisioning rule:

  • Creates a new connector space object

  • Renames an existing connector space object

  • Removes a link to an existing connector space object to trigger the deprovisioning rule and

  • Completes any other processing that might be useful.

The only way to define this rule is through a rules extension that implements the Provision method – there is no declarative route within the UI.

Provision Parameters

mventry

This parameter is the metaverse object involved. Attributes are read-only.

Example

The following example shows an implementation of the Provisioning method. The code provisions a new person object in the Telephone management agent if one does not already exist. It only provisions if the metaverse objects have an attribute called EmpType to the value “employee.”

Public Sub Provision(ByVal mventry As Microsoft.MetadirectoryServices.MVEntry)_
Implements IMVSynchronization.Provision
    ' First, the telephone system only takes person objects
    If mventry.ObjectType.Equals("person") Then
        ' Also, telephone MA should only receive employee objects 
        If mventry("EmpType").Value.ToLower = "employee" Then
            Dim csentry As CSEntry
            Dim PhoneMA As ConnectedMA = mventry.ConnectedMAs("Phone MA")
            ' If there is no connector present, add a new telephone connector
            If TelephoneMA.Connectors.Count = 0 Then
                csentry = TelephoneMA.Connectors.StartNewConnector("person")
                csentry("EMPID").Values.Add(mventry("employeeID").Value)
                csentry.CommitNewConnector()
            ElseIf PhoneMA.Connectors.Count = 1 Then
                ' Nothing to do, connector already exists for this MV object
            Else
                Throw New UnexpectedDataException("Multiple connectors:" + _
PhoneMA.Connectors.Count.ToString)
            End If
        End If 'employees only
    End If 'person objects only
End Sub

Preparing Rules Extensions for Execution

When you have completed a rules extension, build it and run it according to the instructions in MIIS 2003 Help. Ensure that you place the .dll and any other relevant files, such as XML control files, in the MIIS 2003 Extensions folder. When MIIS 2003 builds your project template, it modifies the build location by default, and places the .dll file in the Extensions folder. Your rules extensions are called during management agent runs or by using the MIIS 2003 preview mode.

Testing Rules Extensions

Test your rules extensions according to the testing guidelines for your deployment. You can test rules extensions by using Preview and a run that specifies just a few objects to be processed, before you test rules on all objects. If you detect problems with a rules extension, discuss the problems with the rules planner for the project team. For more information about testing rules extensions, see the Microsoft Identity Integration Server 2003 Developer Reference.

Building Robust Rules Extensions

By using assertions in your code, you can test and debug a rules extension for unexpected values. If you include code in a compile time debug block, you can test assumptions that you have made and raise an exception if a failure is detected. For example:

#If DEBUG Then
   If csentry.ObjectType <> "person" Then
     Throw New UnexpectedDataException("Person object expected: " & _
csentry.ObjectType & "passed.")
   End If
#End If

This code is only included in your module when you build a debug version. These lines of code are excluded by Visual Studio .NET 2003 for a release version of the project.

Next

See Also

Concepts

Introduction to Building Rules Extensions for MIIS 2003
Rules Extension Environment
Identifying Rules Extension Requirements
Hints and Tips for Building Rules Extensions
Best Practices for Coding