Some people are blissfully unaware that there is a very powerful command line tool that ships with NetIQ IDM. The command line tool is dxcmd, and it can be used to start and stop Drivers, change Driver startup mode, start Driver Jobs, and start Driver migrations (the purpose of this post).

ECMAScript

The function below creates an XDS document which is used to initiate a migrate using dxcmd.

function createMigrateDocument(paramDestDN, paramClassName, paramSearchAttr, paramSearchAttrValue, paramScope, paramFileLocation)
{
    var now = new Date();
    var varFile = new File(paramFileLocation);
    var out = null;
    try
        {
            out = new BufferedWriter(new FileWriter(varFile));
            out.write("<nds dtdversion="3.5" ndsversion="8.x">");
      out.newLine();
      out.write("<source>");
      out.newLine();
      out.write("<product version="3.6.11.5281">DirXML</product>");
      out.newLine();
      out.write("<contact>Novell, Inc.</contact>");
      out.newLine();
      out.write("</source>");
      out.newLine();
      out.write("<input>");
      out.newLine();
      out.write("<query dest-dn="" + paramDestDN + "" class-name="" + paramClassName + "" scope="" + paramScope + "">");
      out.newLine();
      out.write("<search-class class-name="" + paramClassName + ""/>");
      out.newLine();
      out.write("<search-attr attr-name="" + paramSearchAttr + "">");
      out.newLine();
      out.write("<value>" + paramSearchAttrValue + "</value>");
      out.newLine();
      out.write("</search-attr>");
      out.newLine();
      out.write("</query>");
      out.newLine();
      out.write("</input>");
      out.newLine();
      out.write("</nds>");
      out.newLine();
      return varFile.getCanonicalPath();
    }
  catch(ex)
  {
    return null;
  }
  finally
  {
    if(out)
    {
      out.close();
      return paramFileLocation;
    }
  }
}
}

DirXML

The two rules below show how the Connector code calls out to DXCMD. The generated XDS document (created by calling the above script) is passed into the IDM Connector specified in the Local Variable varConnectorDN-Temp.

The Policy to which these two Rules belong has the namespace dxcmd defined as xmlns:dxcmd=”http://www.novell.com/nxsl/java/com.novell.nds.dirxml.util.DxCommand”.

Rule One

<rule>
  <description>[nrfResource] Set variable for processing a sync</description>
  <conditions>
    <and>
      <if-class-name op="equal">Organizational Unit</if-class-name>
      <if-xpath op="true">./operation-data/class/@valid-location = 'true'</if-xpath>
      <if-op-attr name="$gcvAttribute-TriggerAction$" op="changing"/>
      <if-op-attr name="$gcvAttribute-TriggerAction$" op="changing-to">$gcvAttribute-TriggerAction-ValueToSync$</if-op-attr>
    </and>
  </conditions>
  <actions>
    <do-set-local-variable name="varOU-EntitlementDN">
      <arg-string>
        <token-src-attr name="idamRFEntitlementDN"/>
      </arg-string>
    </do-set-local-variable>
    <do-set-local-variable name="varOU-ProcessSync">
      <arg-string>
        <token-src-attr name="idamRFAppAutoSync"/>
      </arg-string>
    </do-set-local-variable>
    <do-trace-message color="yellow">
      <arg-string>
        <token-global-variable name="gcvConnectorName"/>
        <token-text xml:space="preserve"> : </token-text>
        <token-text xml:space="preserve">Processing '</token-text>
        <token-src-dn/>
        <token-text xml:space="preserve">' with entitlement [</token-text>
        <token-local-variable name="varOU-EntitlementDN"/>
        <token-text xml:space="preserve">]</token-text>
      </arg-string>
    </do-trace-message>
    <do-if>
      <arg-conditions>
        <and>
          <if-local-variable mode="regex" name="varOU-EntitlementDN" op="equal">^.+$</if-local-variable>
          <if-local-variable name="varOU-ProcessSync" op="equal">true</if-local-variable>
        </and>
      </arg-conditions>
      <arg-actions>
        <do-set-local-variable name="varSource-XMLData-FinalLocation">
          <arg-string>
            <token-src-dn/>
          </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varProcessSync">
          <arg-string>
            <token-text xml:space="preserve">true</token-text>
          </arg-string>
        </do-set-local-variable>
      </arg-actions>
    </do-if>
  </actions>
</rule>

Rule Two

<rule>
    <description>[nrfResource, Organizational Unit] - Valid change was detected, process 'sync'</description>
    <conditions>
        <and>
            <if-local-variable mode="regex" name="varProcessSync" op="equal">true</if-local-variable>
        </and>
    </conditions>
    <actions>
        <do-set-local-variable name="varConnectorDN-Temp" scope="policy">
            <arg-string>
                <token-src-attr name="idamRFConnectorDN">
                    <arg-dn>
                        <token-local-variable name="varSource-XMLData-FinalLocation"/>
                    </arg-dn>
                </token-src-attr>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varConnectorLocation" scope="policy">
            <arg-string>
                <token-src-attr name="L">
                    <arg-dn>
                        <token-xpath expression="./operation-data/source-parent-dn/text()"/>
                    </arg-dn>
                </token-src-attr>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varConnectorDN" scope="policy">
            <arg-string>
                <token-parse-dn dest-dn-format="dot" start="1">
                    <token-local-variable name="varConnectorDN-Temp"/>
                </token-parse-dn>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varUsername" scope="policy">
            <arg-string>
                <token-parse-dn dest-dn-format="dot" src-dn-format="ldap">
                    <token-global-variable name="gcvUser-UserApplicationAdmin"/>
                </token-parse-dn>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varQuery-SearchBase" scope="policy">
            <arg-string>
                <token-src-attr name="idamRFAppSourceBaseLocation">
                    <arg-dn>
                        <token-local-variable name="varSource-XMLData-FinalLocation"/>
                    </arg-dn>
                </token-src-attr>
            </arg-string>
        </do-set-local-variable>
        <do-if>
            <arg-conditions>
                <or>
                    <if-local-variable mode="regex" name="varConnectorDN" op="not-equal">^.+$</if-local-variable>
                    <if-local-variable mode="regex" name="varQuery-SearchBase" op="not-equal">^.+$</if-local-variable>
                </or>
            </arg-conditions>
            <arg-actions>
                <do-trace-message color="yellow">
                    <arg-string>
                        <token-global-variable name="gcvConnectorName"/>
                        <token-text xml:space="preserve">: </token-text>
                        <token-text xml:space="preserve">EMPTY SEARCH BASE - BREAKING!</token-text>
                    </arg-string>
                </do-trace-message>
                <do-break/>
            </arg-actions>
        </do-if>
        <do-set-local-variable name="varCurrentJavaDate">
            <arg-object>
                <token-xpath expression="jdate:new()"/>
            </arg-object>
        </do-set-local-variable>
        <do-set-local-variable name="varNDSDate">
            <arg-string>
                <token-xpath expression="jdate:getTime($varCurrentJavaDate)"/>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varQueryFileName" scope="policy">
            <arg-string>
                <token-global-variable name="gcvQueryFile-BaseLocation"/>
                <token-text xml:space="preserve">IDAM_Migrate_</token-text>
                <token-local-variable name="varNDSDate"/>
                <!-- <token-parse-dn src-dn-format="slash" start="-1">-->
                <!-- <token-global-variable name="dirxml.auto.driverdn"/>-->
                <!-- </token-parse-dn>-->
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varQueryDocFile" scope="policy">
            <arg-string>
                <token-xpath expression="es:createMigrateDocument($varQuery-SearchBase, 'Group', 'CN', '*', 'subtree', $varQueryFileName)"/>
            </arg-string>
        </do-set-local-variable>
        <do-set-local-variable name="varCommand" scope="policy">
            <arg-string>
                <token-text xml:space="preserve">-host </token-text>
                <token-local-variable name="varConnectorLocation"/>
                <token-text xml:space="preserve">-user </token-text>
                <token-local-variable name="varUsername"/>
                <token-text xml:space="preserve">-password </token-text>
                <token-named-password name="npUserApplication-ProvisioningAdmin-Password"/>
                <token-text xml:space="preserve">-migrateapp </token-text>
                <token-text xml:space="preserve">'</token-text>
                <token-local-variable name="varConnectorDN"/>
                <token-text xml:space="preserve">'</token-text>
                <token-text xml:space="preserve"/>
                <token-local-variable name="varQueryDocFile"/>
            </arg-string>
        </do-set-local-variable>
        <do-trace-message color="yellow">
            <arg-string>
                <token-global-variable name="gcvConnectorName"/>
                <token-text xml:space="preserve">: </token-text>
                <token-text xml:space="preserve">Calling dxcmd for Connector '</token-text>
                <token-local-variable name="varConnectorDN"/>
                <token-text xml:space="preserve">' with command line [</token-text>
                <token-local-variable name="varCommand"/>
                <token-text xml:space="preserve">]</token-text>
            </arg-string>
        </do-trace-message>
        <do-set-local-variable name="varResult" scope="policy">
            <arg-string>
                <token-xpath expression="dxcmd:commandLine(string($varCommand))"/>
            </arg-string>
        </do-set-local-variable>
        <do-if>
            <arg-conditions>
                <and>
                    <if-xpath op="true">$varResult = -1</if-xpath>
                </and>
            </arg-conditions>
            <arg-actions>
                <do-trace-message>
                    <arg-string>
                        <token-text xml:space="preserve">The DXCMD command completed with an ERROR.</token-text>
                    </arg-string>
                </do-trace-message>
            </arg-actions>
            <arg-actions>
                <do-trace-message>
                    <arg-string>
                        <token-text xml:space="preserve">The DXCMD command completed SUCCESSFULLY.</token-text>
                    </arg-string>
                </do-trace-message>
            </arg-actions>
        </do-if>
    </actions>
</rule>