Creating an Extensible MA

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

  1. Create an Extensible MA in Identity Manager.
  2. 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.

  1. 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.

  2. 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.

 

  1. 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.

4 Replies to “Creating an Extensible MA”

  1. “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.

  2. Yes that’s right – it’s a pretty old post this one – first time I wrote an XMA and there was no documentation.

Comments are closed.