Here’s a quick walkthrough of creating an XMA. It’s by no means complete or authoritative, and just shows a method I’ve found success with. The example is creating Netware home directories, something I recognize most people don’t need to do these days, but it’s a flexible method which I have used for other scenarios as well.
Step 1 – Create the MA
- Create an Extensible MA in Identity Manager.
- On the Properties page, after entering a name for the MA, untick the separate process option, as it will stop you being able to debug your code.
-
On the Configure Connection Information page, I always tick the Import and Export option. I really don’t know what circumstances might need an Import-only or Export-only MA – perhaps I’ll find out one day.
- For the Connected Data Source extension name just put the name of the dll you will write – it doesn’t matter if it doesn’t exist yet. The convention is MAName_CSExtension.dll.
- On the Configure Attributes page, you need to tell MIIS the attributes in the CDS, because MIIS doesn’t know how to go and find them out itself. On the Advanced tab you specify the object type – you can only have one object type in an XMA, but you can call it whatever you like.
Â
Most of the rest of the MA config pages are similar to all MAs, and should not need explanation.
Step 2 – Create the CSExtension
In Identity Manager, highlight your new MA and click Create Extension Projects. Select the Project Type and change the Project Name as shown here:
This will give you a skeleton project with the procedures GenerateImportFile, BeginExport, ExportEntry and EndExport to be filled in by you.
Step 3 – Export Steps
I’ll look at the Exports first. The BeginExport and EndExport subs are run once at the start and end of the whole export and are used to establish and end your connection to the CDS. The ExportEntry sub is run for each object exported.
I tend to maintain a SQL table alongside the CDS where I can record extra information about the objects. So, taking my Netware home directory example, I have a table in a SQL database on the MIIS server with these columns:
Path | DN | Server | Volume | Folder | Status |
The Path is the primary key of the table. The DN is the owner’s – and this field allows me to join back to the user object in the metaverse. Status may contain “adding”, “active”, “archived”, or “deleted”. I could also add fields for dates and comments if I wanted to improve my logging.
So, in my code, the ExportEntry step calls scripts that create the homedir itself, and then enter information into the SQL table to record the fact.
Public Sub ExportEntry(ByVal modificationType As ModificationType, ByVal changedAttributes As String(), ByVal csentry As CSEntry)
Implements IMAExtensibleCallExport.ExportEntry
‘A CS object has already been created by the provisioning code
Dim server As String = csentry(“Server”).Value
Dim volume As String = csentry(“Volume”).Value
Dim folder As String = csentry(“Folder”).Value
Dim path As String = “\” server & “” & volume & “” & folder
If modificationType = modificationType.Add Then
‘Check it is not already in the SQL table
If Not rowExists(path) AndAlso csentry(“DN”).IsPresent Then
Dim dn As String = csentry(“DN”).Value
If CreateHomeDir(csentry) = 0 Then
‘Only add the SQL table row if CreateHomeDir
‘was successful. This will force MIIS to try
‘again next export if CreateHomeDir failed.
addRow(path, dn, server, volume, folder, “adding”)
End If
End If
End If
End Sub
Step 4 – Import Steps
Extensible MAs can only import objects from a text file, so your job, in the GenerateImportFile sub, is to construct the text file that contains all the information MIIS will be expecting. My preferred format is AVP because it will support both single and multi-valued attributes.
Path: \server1homectest
DN: ctest.staff.nds
Server: server1
Volume: home
Folder: ctest
Status: active
I tend to combine harvesting information direct from the source, with matching against what I’ve written into the SQL table. If an object doesn’t actually exist – say a homedir was not created, or was accidentally deleted – I won’t list the object in the text file; MIIS will register that as an unexpected disappearance; and will reprovision the object. Which is exactly what you’d want to happen.
Public Sub GenerateImportFile(ByVal filename As String, ByVal connectTo As String, ByVal user As String, ByVal password As String, ByVal configParameters As ConfigParameterCollection, ByVal fullImport As Boolean, ByVal types As TypeDescriptionCollection, ByRef customData As String)
Implements IMAExtensibleFileImport.GenerateImportFile
Dim Servers As String() = {“server1”, “server2”, “server3”}
Dim i As Int16
Dim s() As String
Dim folders As System.Collections.IEnumerator
Dim sqlConn As New SqlConnection(MIISDB_CONNECTION_STRING) sqlConn.Open()
Dim fw As StreamWriter
Try
‘Open the output file specified in the run profile
fw = New StreamWriter(filename, False)
Catch ex As Exception
Throw New UnauthorizedAccessException(“Unable to open file: ” & filename)
End Try
For i = 0 To UBound(Servers)
‘List all folders under \serverhome
s = System.IO.Directory.GetDirectories(“\” & Servers(i) & “Home”)
folders = s.GetEnumerator
While folders.MoveNext
‘For each folder, write an entry into the import file
fw.WriteLine(“Path: ” & folders.Current)
fw.WriteLine(“Server: ” & Servers(i))
fw.WriteLine(“Volume: Home”)
fw.WriteLine(“Folder: ” & folders.Current.Replace(“\” & Servers(i) & “Home”, “”))
‘Get DN and Status from the SQL table
Dim sqlQuery As New SqlCommand(“SELECT * FROM ” & MIISDB_TABLE & ” where path='” & folders.Current & “‘”, sqlConn)
Dim cnReader As SqlDataReader = sqlQuery.ExecuteReader
If cnReader.Read Then
fw.WriteLine(“stringDN: ” & cnReader.Item(1)) fw.WriteLine(“Status: ” & cnReader.Item(5))
Else
fw.WriteLine(“stringDN: “)
fw.WriteLine(“Status: owner unknown”)
End If
fw.WriteLine()
cnReader.Close()
End While
Next
sqlConn.Close()
fw.Close()End Sub
And the rest:
The complete solution also includes deprovisioning, as well as steps to archive home directories to ZIP files before deletion… but I’ll cover all that in another post.
How configure anchor attribute for import process? what field in this example is anchor?
I think in this one I was using the path as the anchor.
“On the Advanced tab you specify the object type – you can only have one object type in an XMA, but you can call it whatever you like”.
I do not think this is correct. In step 1, bullet 5 you just pick the radio button “Object class attribute” and choose the attribute in your schema/template AVP file that specifies the object type.
Yes that’s right – it’s a pretty old post this one – first time I wrote an XMA and there was no documentation.