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
In the MIIS 2003 UI, select Management Agents.
Select the management agent for which you wish to create an extension project.
In the Actions pane, click Create Rules Extension. The rules extension project defaults to Visual Basic .NET 2003 as a programming language.
Select Visual C# .NET 2003, if desired.
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.
If you want to change the default folder in which the project is created, click Browse….
Select the Launch in Visual Studio .NET IDE checkbox to launch a Visual Studio .NET 2003 project in the integrated development environment (IDE).
If necessary, create your controlling XML file.
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.
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
On the Tools menu of the UI, click Configure Extensions.
Select the Enable Metaverse Rules Extension check box, and provide a name for the file to contain the extension code.
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.
Select the Enable Provisioning Rules Extension check box if you want to enable provisioning.
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.
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.
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.
If you want to change the default folder in which the project is created, click Browse….
Select the Launch in VS .Net IDE box to launch a Visual Studio .NET 2003 project in the IDE.
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