What actually moves.

How the transformation works, what it produces, and what it will not pretend to do. Written for the person who has to sign off on it.

Book a scoping call
  • Deterministic translation, not a language model
  • Auditable before import
  • Proven in parallel before cutover

Migrating MIM to IdentityIQ is a discovery problem before it is an engineering problem. The configuration is spread across a synchronization service, a policy service, a portal, and compiled .NET assemblies that nobody has looked at in years. Most of the cost, and most of the risk, sits in finding out what the current system actually does before anyone can rebuild or replace it.

This starts from the MIM Configuration Documenter report, the same report your team can produce today, and converts it into an importable IdentityIQ build.

The principle that decides everything else

The transformation refuses to guess.

Every piece of MIM logic is either translated faithfully or left as a clearly marked scaffold, with the reason recorded in a caveats file. Nothing is approximated.

A subtly wrong attribute rule produces a wrong username or a wrong distinguished name that looks entirely correct in the output and surfaces weeks later in production. That principle is enforced in code, not in a style guide. The expression translator supports 70 of the 87 MIM Workflow Activity Library functions and refuses the other 17 on purpose, each with a message explaining why. The .NET translator parses C# with a real grammar specifically so it can reliably detect and decline constructs it cannot honor: LINQ, loops, exception handling, external service calls.

A scaffold is an honest deliverable. Confidently wrong identity logic is not.

1. Connectors and schema

Each management agent becomes an IdentityIQ Application. Connector type drives the features string, the schema is emitted in the shape IdentityIQ requires, and connection attributes are populated on a best-effort basis from the report.

Credentials never appear in a documenter report, so every secret is written as a placeholder token and listed in the caveats. The site bundle collects those tokens into a properties file and ships a substitution script, which is the SailPoint Services Standard Build convention: each environment gets its own property file rather than one artifact edited by hand per instance.

The FIM/MIM Service management agent is deliberately not built as a connector. That layer is the equivalent of the IdentityIQ portal and Identity Cube, not an external system. Its attributes land in the cube with no application source, its workflows become IdentityIQ workflows, and its groups go through the roles conversion. Building a connector for it would model IdentityIQ talking to itself.

2. Identity attributes, with the right system winning

When several management agents feed the same metaverse attribute, MIM ranks them, and rank 1 wins. That ranking is in the report and it is honored. IdentityIQ evaluates attribute sources in order and takes the first non-null, so an HR system at rank 1 stays authoritative and Active Directory remains the fallback, exactly as in MIM.

This is the single highest-risk item in a MIM migration. Get it wrong and the wrong system quietly becomes the source of truth for a value, with nothing in the configuration looking out of place. Contested attributes are listed in the caveats so a human confirms the ordering rather than trusting it.

3. Expressions become readable BeanShell

MIM sync rules and workflow activities carry real function expressions. They are translated deterministically, not by pattern matching and not by a language model.

A MIM expression like this:

Trim([//Target/LastName]) + ", " + Trim([//Target/FirstName])
  + IIF(IsPresent([//Target/MiddleInitial]), " " + UpperCase(Left([//Target/MiddleInitial],1)), "")

becomes finished, null-safe BeanShell, formatted one statement per line, with the helper methods living in a shared rule library rather than copied into every rule. Fix the helper once and every rule that uses it is fixed.

Several MIM functions do not behave the way their names suggest, and the translation accounts for it. Eq is case-insensitive. IIF evaluates both branches. Contains tests list membership rather than substring. WAL string indexes are zero-based where native MIM ones are one-based, which means the same function name compiles differently depending on whether the expression came from a sync rule or a workflow. These are the details that turn into defects when a migration is done by hand.

Logic that provably repeats gets promoted into a single method in a system-specific library, and every call site becomes a one-line call. Promotion requires an identical normalized expression. Similar-but-different logic stays separate, because guessing that two expressions are the same is how migrations corrupt data. Each promotion is listed in the caveats with its site count.

4. Compiled .NET rules extensions

This is normally the hardest part of a MIM migration, and the reason most projects end up rewriting logic from scratch.

Rules extensions are compiled into an assembly. The documenter report can say that a flow uses one, but not what it does. The report and the source join on an exact key: the report records a flow's mapping type as the rules-extension script context, and that context is the string MIM passes as the flow rule name into the import mapping call. Supply the source and the two halves fit together, producing a finished rule rather than a stub.

No source? We recover it. Most estates we see are missing the C# or VB rules-extension source. The developers left and the project files went with them. We decompile your assemblies, recover the logic, and translate it like any other input. Your own code, from your own binaries, recovered at your direction.

Constructs outside the supported dialect are refused by name. A case that loops over a multivalued attribute, catches exceptions, uses LINQ or calls an external service keeps its scaffold, and the caveats say precisely which construct stopped it. Refusal is per case, so one untranslatable flow never discards the others in the same file.

Provisioning declarations get their own treatment, because they are not attribute flows. Each connected system becomes a provisioning plan rule called from the lifecycle workflow. The request shape is generated, and the distinguished name and attribute values are carried as comments holding the original C#, because a mistranslated distinguished name puts accounts in the wrong organizational unit.

5. Lifecycle: policy rules and workflows

MIM implements one lifecycle event across several management policy rule and workflow pairs. IdentityIQ wants one workflow per event.

Each pair is classified as joiner, mover, leaver or unclassified, with the evidence that led to the classification, and every pair is put in front of a human to confirm or correct. Confirmed pairs for one event are merged into a single consolidated workflow, with the already-translated BeanShell spliced in rather than regenerated. Nothing is silently dropped. Pairs that end up unclassified or skipped are named in the package notes.

The leaver design is where most of the subtlety lives. The trigger matches a transition rather than a state, so a move from inactive to terminated does not re-run the workflow against an account that is already disabled and already moved. One workflow serves every leaver destination and the plan rule branches on the new status: disable and organizational unit move for both, group removal only for the terminal state, scoped to the groups a mapping table manages rather than stripping everything the account holds. Connected directories are processed independently, so an identity holding an LDAP account but no AD account still gets the LDAP lock.

Connector differences are respected too. The AD connector gets the IdentityIQ disable pseudo-attribute, the LDAP connector gets only the directory's real operational attribute, because passing the pseudo-attribute through rejects the whole change.

Trigger rules deliberately do not copy MIM's comparison behavior. MIM compares raw values, so a source system changing a value from NURSING to Nursing fires its policy rule. In IdentityIQ that same event would run a real provisioning plan, so values are trimmed, empty and missing are treated as the same thing, and case is ignored. The noise is filtered at the trigger instead of provisioned into your directory.

The decisions that your configuration cannot answer are put to your team through a guided wizard that scales with the environment. Microsoft's Contoso Pilot estate produces ten screens and 46 questions. Every question is prepopulated from your own reports, carries the evidence it was inferred from and a confidence score, and the ones that genuinely need a human decision are marked MUST CONFIRM.

The lifecycle wizard on the correlation and join page, listing the four join rules found in the Contoso AD management agent and asking which is authoritative
Correlation and join, prepopulated from the reports. It found four join rules on Contoso AD and asks which is authoritative, in what fallback order, and what to do when zero or several accounts match. Click to enlarge.

Read the second question in that screenshot. It enumerates the four join rules it actually found in the management agent, then asks which one wins. It is not offering a menu of generic options, it is reading your configuration back to you and asking the question a migration has to answer. The note underneath is the whole discipline in one line: ambiguous correlation must not silently merge identities.

The lifecycle wizard scope page showing proposed answers with confidence scores, the evidence each was inferred from, and the confidence penalties applied
Every proposal carries a confidence score and the evidence behind it, and the wizard states its own confidence penalties out loud. Click to enlarge.

Note what the panel at the top of that page is doing. It is listing the reasons its own confidence is reduced: a report-only rendering gap, an unconfirmed migration source, and a cap on every behavior that depends on compiled rules-extension logic it cannot see. Then it says that destructive and credential decisions require explicit confirmation regardless of how confident it is.

A tool that told you it was certain about all of it would be easier to sell and worse to rely on.

Shown with synthetic sample data. These are the questions a MIM configuration cannot answer on its own, which is exactly why they go to a human rather than being guessed.

6. Sets become populations

A MIM set is the who of every policy. Set XPath is translated into an IdentityIQ filter and emitted as a GroupDefinition population, usable as role criteria, policy scope, or an approval audience. Each one carries its original XPath in the description, so a reviewer can check the translation rather than trust it.

Sets whose XPath needs a subquery, or that compare MIM object identifiers, are refused with the reason given. A wrong population silently changes who a policy applies to.

7. Operations: run profiles become tasks

A migrated site with connectors but no tasks cannot run. Import steps become account aggregation tasks and synchronization steps become an identity refresh task, documented per profile.

Three things are deliberately absent, and are explained in the output rather than quietly omitted. Export steps produce no task, because IdentityIQ writes to targets through provisioning driven by workflows and policy, not a periodic export run. Schedules are not generated, because the report records a profile's steps and not whatever invokes it, so any cron expression would be invented. The FIM/MIM Service management agent is not aggregated, because no connector is built for it, so an aggregation task would reference an application that does not exist.

8. Active Directory groups become business roles and IT roles

Group membership is where MIM's behavior is most visible to end users, and where a migration is most obviously right or wrong. It is also the part of this transformation with the longest track record.

Feed it your existing group reporting and it produces a two-tier role model. IT roles carry the actual entitlement, one per AD group, holding the group membership on the target application. Business roles carry the meaning. They are what a manager or a certification campaign sees, and they confer the IT roles beneath them.

That split is the point. In MIM, group membership is usually the product of set criteria and policy, and there is no separate layer expressing why somebody has access. IdentityIQ gives you that layer, which is what makes access requests, certifications and role mining possible afterwards.

Alongside the role XML you get a conversion report: a row per group showing what it became, so the mapping is auditable on a spreadsheet before anything is imported rather than discovered afterwards in the target system.

9. The portal

RCDCs, navigation resources, search scopes and filter permissions are inventoried and mapped to Forms, QuickLinks, request authority, capabilities and scopes.

No XML is generated for the portal. MIM describes its portal with a grid layout model and per-attribute filter permissions. IdentityIQ uses Forms and capability-based scoping. They are different models, not different spellings, and producing Form XML from an RCDC would give you something that looks importable and is not. What you get instead is the complete inventory of what the portal does today and where each part goes, including the losses worth knowing about up front.

Watch the role conversion run

MIM security groups, distribution groups, and criteria based sets becoming SailPoint business roles and IT roles, end to end.

Automated group migration from MIM to SailPoint IdentityIQ, a 29 minute demonstration Watch the demonstration, 29 min

The demonstration is unedited, including a point where a case-sensitivity mistake in an attribute mapping is spotted and corrected on camera. SailPoint is case sensitive where MIM is not, and that class of difference is exactly what a migration has to get right. A full migration walkthrough is in production.

Run it on Microsoft's own sample, and check

Microsoft publishes a sample MIM configuration with the Configuration Documenter, the Contoso Pilot estate. It is not our data and not a client's, so anyone can take the same two reports and repeat what follows.

Feeding the sync and service reports through the transformation parses 8 management agents and produces 86 files: 7 Applications, 5 correlation configurations, the identity attribute mapping, 18 BeanShell rules, 23 lifecycle workflow and trigger files, 11 tasks, 4 provisioning policies, 3 email templates and the populations.

That is the whole point. Two HTML reports go in. An importable IdentityIQ configuration comes out.

The migration tool with both Contoso Pilot documenter reports staged, ready to convert, above the Assemble site bundle step
The Contoso Pilot sync and service reports staged for conversion. Below the button, the site bundle step that merges everything into import order and writes the scripts that push it into IdentityIQ. Click to enlarge.

Before and after, in the same file

Every translated rule carries the original MIM expression as a comment directly above the BeanShell it became, so a reviewer checks the translation rather than trusting it. This is the actual generated output, unedited:

<Rule language="beanshell" name="MIM Transform - Contoso Active Directory - dn"
      type="Transformation">
  <ReferencedRules>
    <Reference class="sailpoint.object.Rule" name="MIM WAL Helpers"/>
  </ReferencedRules>
  <Source><![CDATA[
  // MIM Expression: dn <- IIF(CustomExpression(Eq(employeeStatus,"Terminated")),
  //   CustomExpression("CN="+accountName+",OU=Terminated,OU=People,OU=FIM_Managed,DC=contoso,DC=com"),
  //   CustomExpression("CN="+accountName+",OU=People,OU=FIM_Managed,DC=contoso,DC=com"))

  Object v_employeeStatus = identity.getAttribute("employeeStatus");
  Object v_accountName = identity.getAttribute("accountName");

  return (eq(v_employeeStatus, "Terminated")
      ? ("CN=" + nvl(v_accountName) + ",OU=Terminated,OU=People,OU=FIM_Managed,DC=contoso,DC=com")
      : ("CN=" + nvl(v_accountName) + ",OU=People,OU=FIM_Managed,DC=contoso,DC=com"));
  ]]></Source>
</Rule>

Read what that rule does. A terminated employee's account is built in a different organizational unit from an active one. Get that wrong and accounts land in the wrong OU, inherit the wrong policy, and nothing in the configuration looks out of place. It is exactly the kind of logic that gets quietly mistranscribed when a migration is done by hand, and exactly why the original expression stays attached to the translation.

Note eq and nvl are not invented. They come from the shared MIM WAL Helpers rule library referenced at the top, which supplies null-safe equivalents of the MIM functions, so a fix in one place fixes every rule that uses it.

What does not come out clean, and why

Of the 18 rules that run produces, 6 are finished BeanShell and 12 are marked scaffolds. That is not a failure, it is the refusal to guess. The sample estate drives most of its flows through compiled rules extensions, and compiled .NET logic is not in a documenter report. Supply the source, or let us decompile the assemblies, and those 12 become finished rules too.

A migration that reported 18 of 18 finished from that input would be inventing twelve rules.

What you receive

We build the package, and we build the site. The archive below is the artifact, not the deliverable. The deliverable is a working IdentityIQ instance doing what your MIM does. Import, connector configuration, aggregation and the parallel comparison run are part of the engagement.

applications/     Application XML per connector
correlation/      CorrelationConfig per management agent
identity/         Identity attribute sources, precedence-ordered
provisioning/     Create templates from outbound sync rules
rules/            BeanShell rules plus the shared MIM WAL Helpers library
lifecycle/        Workflows, IdentityTriggers, trigger rules, JML analysis
policy/           Populations, the policy rule map, the portal worklist
tasks/            Aggregation and refresh TaskDefinitions
emailtemplates/   EmailTemplate XML with original HTML
roles/            Business and IT roles
build-out/        RHEL, Tomcat and database build runbook
jml-wizard/       Evidence manifest for the lifecycle design wizard
MIGRATION-SUMMARY.md
CAVEATS.md

A separate step merges the starter kit, the lifecycle package and the roles output into one directory tree, ordered the way IdentityIQ orders its own configuration, with an include manifest that imports the whole set in a single console command.

Every file is validated before it reaches that manifest. A file that does not parse, has no DOCTYPE, or is not an object IdentityIQ can import on its own is held back and named with the reason, so one malformed file can no longer abort an import partway through. Objects that must be merged rather than replaced are placed separately and deliberately kept off the manifest, because importing them over a live instance would replace IdentityIQ's standard configuration.

The bundle also documents itself. A generated system overview describes the delivered system with diagrams of the imported applications and lifecycle workflows, plus a use case catalog built from the delivered configuration, so what you received is stated from the artifacts themselves rather than from a template.

How correctness is established

Configuration that imports is not the same as configuration that behaves. Three layers, in increasing order of what they prove.

The translation is deterministic and tested. Expressions and .NET rules extensions are converted by parsers, not by pattern matching and not by a language model, so the same input always produces the same output. Generated BeanShell is executed through IdentityIQ's own interpreter during development, not merely inspected.

The role conversion is auditable before import. A conversion report gives a row per Active Directory group showing exactly what it became, so the mapping is reviewed on a spreadsheet rather than discovered in the target system.

MIM and IdentityIQ run in parallel and are compared. This is the layer that actually retires MIM. During the parallel run MIM is the only system provisioning to downstream systems. IdentityIQ aggregates, evaluates, and produces the provisioning it would send, but nothing it generates reaches a connected system until you cut over. We verify that Active Directory group membership produced through IdentityIQ roles matches what MIM produced, and we compare what each system sends to the connected systems. Both run live until the comparison holds.

Being straight about the current state: the generated XML is built against the documented IdentityIQ shapes and against real connector exports, and the first import into a development instance is still a real step in every engagement rather than a formality. The parallel comparison exists precisely because "it imported cleanly" is not proof that it behaves the same.

Fixed fee

We quote a fixed fee, because the scope is not a matter of opinion. It is whatever your MIM does today, moved. That boundary is what makes a fixed price honest.

This is a migration, not a redesign. If you want IdentityIQ to do something MIM never did, that is a different project. It is billed hourly, it extends the schedule, and we will tell you plainly which one you are asking for before you sign anything.

Get off MIM first. Improve second. Trying to do both at once is how these projects turn into years.

What this does not do

Stated plainly, because the honest list is what makes the rest credible.

Still running MIM?

Book a scoping call. We will tell you what your migration actually involves, before you commit to anything.

Book a scoping call