{"id":671,"date":"2010-01-26T12:57:53","date_gmt":"2010-01-26T12:57:53","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?p=671"},"modified":"2010-01-26T12:57:53","modified_gmt":"2010-01-26T12:57:53","slug":"account-deprovisioning-scenarios","status":"publish","type":"post","link":"https:\/\/www.wapshere.com\/missmiis\/account-deprovisioning-scenarios","title":{"rendered":"Account Deprovisioning Scenarios"},"content":{"rendered":"<p><!--Start Here --><\/p>\n<p>I just posted this article in the Greatest Hits series of the ILM Technet forum. It describes some of the methods and considerations around disabling and deleting users accounts with ILM.<\/p>\n<p><!--more--><\/p>\n<p>In Identity Management, deprovisioning is every bit as important as provisioning \u00e2\u20ac\u201c in fact the security guys would say it is more important.<\/p>\n<p>End-of-life management may have been one of the determining factors that got the IdM project started in the first place \u00e2\u20ac\u201c while most<br \/>\norganizations have a variety of scripts and processes they use to create accounts and assign permissions, the cleanup when a person leaves is often not handled so well.<\/p>\n<p>General rules for object deletion have been already well covered in Markus\u00e2\u20ac\u2122 article<br \/>\n<a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en-US\/identitylifecyclemanager\/thread\/603c4f8c-d782-4625-a045-009d15ed0f3b\" target=\"_blank\">Understanding Deletions in ILM<\/a>; however there is more that can be said on the subject of user accounts, for which an immediate delete is often not appropriate.<\/p>\n<p>This article shows how you can use ILM to configure a flexible deprovisioning solution that is customized to your technical, organizational and compliance needs.<\/p>\n<h2>Account Deprovisioning Scenarios in this document<\/h2>\n<p>We are going to look at the following types of account deprovisioning:<\/p>\n<ol>\n<li>Simple deletion<\/li>\n<li>Disabling the account<\/li>\n<li>Deleting the account on a time-delayed basis<\/li>\n<li>Stopping ILM from managing the account without actually deleting it (disconnection)<\/li>\n<\/ol>\n<h2>Parts to the Account Deprovisioning Puzzle<\/h2>\n<p>Depending on your needs, you will most likely have to piece together a number of different elements to achieve the desired result.<\/p>\n<p><strong>Account Disabling:<\/strong><\/p>\n<p>Deactivating an object normally involves changing one or more of its attributes (eg.: setting userAccountControl on an AD user), and the usual way to do this is with an export attribute flow (EAF).<\/p>\n<p>See code example \u00e2\u20ac\u0153<em><a href=\"#Disabling Flow Rules\">Disabling Flow Rules<\/a><\/em>\u00e2\u20ac\u009d below.<\/p>\n<p><strong>Moving deactivated accounts:<\/strong><\/p>\n<ul>\n<li>A common practice is to put disabled accounts in a particular place, such as a \u00e2\u20ac\u0153<em>Disabled<\/em>\u00e2\u20ac\u009d OU.For AD this is a &#8220;<em>Rename<\/em>&#8221; activity, and is typically done in the metaverse<br \/>\nextension code.<\/li>\n<li>For the \u00e2\u20ac\u0153<em>Stop management<\/em>\u00e2\u20ac\u009d scenario it is also possible to move the account just prior to disconnecting it in the MA Extension Deprovision method.<\/li>\n<\/ul>\n<p>See code example \u00e2\u20ac\u0153<em><a href=\"#Metaverse Deprovisioning\">Metaverse Deprovisioning<\/a><\/em>\u00e2\u20ac\u009d below.<br \/>\n\u00c2\u00a0<\/p>\n<p><strong>Deleting the connector space (CS) object:<\/strong><\/p>\n<ul>\n<li>The first step to deleting an account is to delete the object that represents it in the connector space.This can happen in one of the following two ways:\n<ul>\n<li>The joined Metaverse object is deleted<\/li>\n<li>The joined Metaverse object was disconnected, either manually or by using the<br \/>\n<em>CSEntry.Deprovision()<\/em> method in the<br \/>\nmetaverse extension code.<\/li>\n<\/ul>\n<\/li>\n<li>In both cases a deletion will only happen if the &#8220;<em>Configure Deprovisioning<\/em>&#8221; tab on the MA configuration has been set as follows:\n<ul>\n<li>\u00e2\u20ac\u0153<em>Stage a delete on the object for the next export run<\/em>\u00e2\u20ac\u009d, or<\/li>\n<li>\u00e2\u20ac\u0153<em>Determine with a rules extension<\/em>\u00e2\u20ac\u009d AND the rules extension code returns<br \/>\n<em>DeprovisionAction.Delete<\/em>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u00c2\u00a0<br \/>\nSee code example \u00e2\u20ac\u0153<em><a href=\"#MA Deprovision Sub\">MA Deprovision Sub<\/a><\/em>\u00e2\u20ac\u009d below<br \/>\n\u00c2\u00a0<br \/>\nSee \u00e2\u20ac\u0153<em><a href=\"#Metaverse Deprovisioning\">Metaverse Deprovisioning<\/a><\/em>\u00e2\u20ac\u009d for an example of the <em>CSEntry.Deprovision()<\/em> method.<br \/>\n\u00c2\u00a0<\/p>\n<p><strong>Deleting the account in the connected data source (CDS):<\/strong><\/p>\n<ul>\n<li>To delete the actual object in the CDS, we must first delete the connector space object using the methods above, after which we should find an export of type \u00e2\u20ac\u0153<em>delete<\/em>\u00e2\u20ac\u009d ready in the connector space.It is then just a matter of running an Export.\n<ul>\n<li>Note that the account used by the MA must have permission to delete objects of this type in the CDS.<\/li>\n<li>Note also that if the MA is of type \u00e2\u20ac\u0153Extensible Connectivity\u00e2\u20ac\u009d you must write a Delete method in the Connected Data Source extension (see example below).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u00c2\u00a0<br \/>\nSee code example \u00e2\u20ac\u0153<a href=\"#XMA Delete Method\">XMA Delete Method<\/a>\u00e2\u20ac\u009d below.<br \/>\n\u00c2\u00a0<\/p>\n<p><strong>Time dependant deletion:<\/strong><\/p>\n<ul>\n<li>Sometimes you want to delete an object on a certain date \u00e2\u20ac\u201c perhaps an expiration date, or 3 months after the account was disabled.To do this you need the date available on the Metaverse object, which means you have to flow it into the Metaverse from somewhere.\n<ul>\n<li>An example for AD accounts is to use a spare attribute on the account, such as info or one of the extensionAttributes, to write the date at the same time as you disable the account.Flow this value back into the Metaverse and the information will be available.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u00c2\u00a0<br \/>\nSee code example \u00e2\u20ac\u0153<a href=\"#Metaverse Deprovisioning\">Metaverse Deprovisioning<\/a>\u00e2\u20ac\u009d below.<br \/>\n\u00c2\u00a0<\/p>\n<h2>Deprovisioning Scenarios<\/h2>\n<h3>Simple Deprovision based on disappearance<\/h3>\n<p>The simplest deprovisioning scenario, and the one that can be executed without writing any code, is the \u00e2\u20ac\u0153disappearance\u00e2\u20ac\u009d scenario.<\/p>\n<p>Here an object (or database line, or text file line) disappears from a source MA and is imported as a delete.<\/p>\n<p>In the Metaverse we have configured our Object Deletion Rule as \u00e2\u20ac\u0153<em>Delete Metaverse object when connector from this management agent is disconnected<\/em>\u00e2\u20ac\u009d and selected our source MA.<\/p>\n<p>Finally we have configured our other MAs to delete the CS objects when the Metaverse object is deleted.<\/p>\n<p>In this way we could, for example, delete an AD account because the person\u00e2\u20ac\u2122s record disappeared from the HR data source.<\/p>\n<blockquote><p><strong>Caution: This method may lead to unexpected loss of accounts, temper and job!<\/strong><\/p><\/blockquote>\n<p>As a general rule, it is a bad idea to make destructive decisions based on an absence of information. All sorts of errors, both human and machine, could happen to cause data to be unavailable at the time an Import runs. If you do use this simple approach, only use it for low-priority objects that can be deleted and recreated without much impact.<\/p>\n<h3>Deprovision based on attribute change<\/h3>\n<p>It is a much better practice to make deprovisioning decisions based on positive data.<\/p>\n<p>So, with the HR data source, we continue to import resigned people, but with a status flag that indicates they are now inactive.<\/p>\n<p>We then write some code in the metaverse extension which reacts to the person\u00e2\u20ac\u2122s \u00e2\u20ac\u0153inactive\u00e2\u20ac\u009d status.<\/p>\n<p>The great advantage to this method is the flexibility it gives us.<\/p>\n<p>For example, we may deal with the person\u00e2\u20ac\u2122s connected objects in different ways, deleting contacts and application accounts immediately<br \/>\nbut, just disabling the AD user account until further notice.<\/p>\n<p>Deprovisioning a connector space object from metaverse extension code is trivial \u00e2\u20ac\u201c all you have to do is add the line<\/p>\n<p><em>CSEntry.Deprovision()<\/em><\/p>\n<p>The bulk of the code before this will be spent in testing attribute values, and connections to different MAs, to determine when conditions are right to issue this command.<\/p>\n<h3>Disable then delete<\/h3>\n<p>It is simple enough to disable an account using an EAF (see example \u00e2\u20ac\u0153<a href=\"#Disabling Flow Rules\">Disabling Flow Rules<\/a>\u00e2\u20ac\u009d below).<\/p>\n<p>You could also move the account to a special location (see example \u00e2\u20ac\u0153<a href=\"#Metaverse Deprovisioning\">Metaverse Deprovisioning<\/a>\u00e2\u20ac\u009d below).<\/p>\n<p>However what do you do if you want to remove the account at some point in the future?<\/p>\n<p>The first thing to be aware of is you must not delete the metaverse object.<\/p>\n<p>To be able to delete the disabled account in the future it has to be connected to something in the<br \/>\nmetaverse.<\/p>\n<p>ILM can only manage connectors.<\/p>\n<p>Next, you will need some kind of <em>datestamp<\/em> on the metaverse object so your<br \/>\nmetaverse extension code will know when it\u00e2\u20ac\u2122s OK to delete the account.<\/p>\n<p>The only way to write a value to a metaverse object is with an IAF \u00e2\u20ac\u201c so this implies writing the<br \/>\n<em>datestamp<\/em> outside ILM, on a CDS object, and then importing it back in.<\/p>\n<p>The method in the code examples below works like this:<\/p>\n<ol>\n<li>Based on the status attribute in the Metaverse, I export the <em>userAccountControl<\/em> to disable the AD user account,<\/li>\n<li>Based on the same rules, I also export today\u00e2\u20ac\u2122s date to the user\u00e2\u20ac\u2122s info attribute,<\/li>\n<li>II import info back to a metaverse attribute called <em>disableDate<\/em>,<\/li>\n<li>I can then use <em>disableDate<\/em> in my metaverse extension to decide when the time is right to issue a CSEntry.Deprovision().<\/li>\n<\/ol>\n<p>There are a couple of points to note about this method:<\/p>\n<ul>\n<li>While disables will happen on a delta sync, deletions will only happen on a<br \/>\nfull sync.<\/li>\n<li>The CDS attribute used to hold the date could be modified in the CDS (though you can use this to your advantage if you want to extend the disabled life of an account).<\/li>\n<\/ul>\n<h3>Stop Managing an Object<\/h3>\n<p>In some cases object deletion is handled in the CDS itself and all you need to do is to stop managing the object.<\/p>\n<p>In ILM terminology the object becomes a \u00e2\u20ac\u0153disconnector\u00e2\u20ac\u009d and, while it may still exist in the MA\u00e2\u20ac\u2122s connector space, it is no longer connected to a Metaverse object, and ILM can no longer impact it in any way.<\/p>\n<p>To disconnect rather than delete you actually use exactly the same CSEntry.Deprovision() method, but with the correct option selected on your MA\u00e2\u20ac\u2122s Configure Deprovisioning page.<\/p>\n<p>You could choose to:<\/p>\n<ul>\n<li>\u00e2\u20ac\u0153Make them disconnectors\u00e2\u20ac\u009d. The object is disconnected but remains in the CS and CDS.It will be reassessed for possible joins at each Full Sync,<\/li>\n<li>\u00e2\u20ac\u0153Make them explicit disconnectors\u00e2\u20ac\u009d.Like the above, but it will not be reassessed for possible joins, or<\/li>\n<li>Decide with a Rule Extension (see example \u00e2\u20ac\u0153<a href=\"#MA Deprovision Sub\">MA Deprovision Sub<\/a>\u00e2\u20ac\u009d below).<\/li>\n<\/ul>\n<p>The \u00e2\u20ac\u0153explicit\u00e2\u20ac\u009d option needs a bit more discussion.<\/p>\n<p>If ever you delete and re-import the CS all \u00e2\u20ac\u0153<em>explicit<\/em>\u00e2\u20ac\u009d tags will be lost and the objects become regular disconnectors again, and available for joins.<\/p>\n<p>This option should only be chosen in particular circumstances, such as when there is a regular and reliable deletion of redundant objects happening in the CDS.<\/p>\n<p>If you are sure that you will not need to rejoin to an object once it has been disconnected then another idea is to export a blocking attribute before disconnecting.<\/p>\n<p>For example you export the string \u00e2\u20ac\u0153<em>Unmanaged<\/em>\u00e2\u20ac\u009d to an attribute on the CDS object, and only disconnect it once the attribute value is confirmed.<\/p>\n<p>You can then use this attribute in a Connection Filter to prevent future re-connections.<\/p>\n<h2>Some Common Problems and Questions<\/h2>\n<h3>I staged some Deletes but I don\u00e2\u20ac\u2122t want to export them now<\/h3>\n<p>Perhaps there was an error in your code or your import data and you have a bunch of Deletes waiting to go out \u00e2\u20ac\u201c but you really don\u00e2\u20ac\u2122t want to do that!<\/p>\n<p>Even after correcting the code and re-syncing you may find they turn into Delete-Adds \u00e2\u20ac\u201c these should also not be exported as the actual CDS objects will be deleted and recreated \u00e2\u20ac\u201c not great for AD accounts!<\/p>\n<p>Unfortunately, the only full-proof fix in this case is a delete and re-import of the connector space.<\/p>\n<h3>I have some old accounts with no HR reference \u00e2\u20ac\u201c will ILM delete them?<\/h3>\n<p>ILM can only delete objects that it is connected to, so if it never connected to the object it can never delete it.<\/p>\n<p>If you plan to tidy up unmanaged objects in your CDS then have a look at the tool csexport.exe (from the MIIS\\bin folder) which can be used to export lists of disconnectors.<\/p>\n<h3>How can I block an Export if there are too many Disables?<\/h3>\n<p>The Export run profile contains an option to stop the job if there are more than a certain number of Deletes queued to go out.<\/p>\n<p>Unfortunately it is not possible to do something similar for disables with native functionality.<\/p>\n<p>If something like this is needed then it should be possible to increment a count in a file from the EAF which deactivates the account, and then modify the script which runs the Export profile to first check the count.<\/p>\n<h3>Sideways Joins<\/h3>\n<p>A scenario you need to watch out for is what I call a \u00e2\u20ac\u0153<em>sideways join<\/em>\u00e2\u20ac\u009d.<\/p>\n<p>Take a situation where the \u00e2\u20ac\u0153<em>person<\/em>\u00e2\u20ac\u009d object type has one source MA (eg.: HR) and multiple target MAs (AD, Notes, some other applications).<\/p>\n<p>The source object has been deleted, but one or more of the target objects have remained and are still joined to a<br \/>\nmetaverse object.<\/p>\n<p>The problem here is that these objects won\u00e2\u20ac\u2122t show up in lists of disconnectors and so can remain, unobserved, for some time.<\/p>\n<p>If deprovisioning logic is based on a value from the source MA then, in a default configuration, this value would have been recalled and is no longer present on the Metaverse object \u00e2\u20ac\u201c so your code is probably just skipping it.<\/p>\n<p>When writing your metaverse extension code, it is a good idea to test for unexpected situations \u00e2\u20ac\u201c like an object with no connector in the primary source MA \u00e2\u20ac\u201c and then throw an error or otherwise deal with the object.<\/p>\n<h3>I can see Deletes staged in the connector space, but the objects don\u00e2\u20ac\u2122t get deleted in the external system<\/h3>\n<p>First, look for error messages in Identity Manager and in the Event Log that may indicate the problem.<\/p>\n<p>Make sure the account used by the MA has the correct permissions in the CDS.<\/p>\n<p>If it\u00e2\u20ac\u2122s an \u00e2\u20ac\u0153<em>Extensible Connectivity<\/em>\u00e2\u20ac\u009d MA, check that a Delete method has been written in the Connected Data Source Extension.<\/p>\n<h3>I disabled an AD user \u00e2\u20ac\u201c now how do I remove it from groups?<\/h3>\n<p>This is one with no short answer.<\/p>\n<p>You cannot manage the <em>memberOf<\/em> attribute on AD users as it is a backlinked attribute.<\/p>\n<p>So group membership can only be managed through the member attribute of groups.<\/p>\n<p>This is fine if you are already managing AD groups with ILM \u00e2\u20ac\u201c but not ok if they are managed manually in AD.<\/p>\n<p>One of the reasons to keep an account in a disabled state for a while is to allow it to be restored quickly with all its previous rights intact \u00e2\u20ac\u201c so removing it from groups may not be the best idea anyway.<\/p>\n<p>If it is necessary then the choices are to fully take over group management with ILM, or to write a script that removes disabled users from groups, and is run outside of ILM.<\/p>\n<h2>Code Examples<\/h2>\n<h3>MA Deprovision Sub<\/h3>\n<p><a name=\"MA Deprovision Sub\">In<\/a> this example, when the Metaverse object is deleted or disconnected, accounts in the \u00e2\u20ac\u0153<em>Student<\/em>\u00e2\u20ac\u009d OU are deleted while accounts in the \u00e2\u20ac\u0153<em>Staff<\/em>\u00e2\u20ac\u009d OU become disconnectors.<\/p>\n<p>This sub is located in the Management Agent Extension code.<\/p>\n<pre lang=\"x-js\">Public Function Deprovision(ByVal csentry As CSEntry) As DeprovisionAction Implements IMASynchronization.Deprovision\r\n   If csentry.DN.ToString.Contains(\"OU=Students\") Then\r\n      Return DeprovisionAction.Delete\r\n   ElseIf csentry.DN.ToString.Contains(\"OU=Staff\") Then\r\n      ' Optionally, rename the cs object or change attributes\r\n      ' just prior to disconnecting\r\n      Return DeprovisionAction.Disconnect\r\n   Else\r\n      Throw New UnexpectedDataException(\"DN does not contain \" _\r\n      &amp; \"'OU=Staff' or 'OU=Students' so I don't know \" _\r\n      &amp; \"which deprovision action to perform.\")\r\n   End If\r\nEnd Function<\/pre>\n<h3>Metaverse Deprovisioning<\/h3>\n<p><a name=\"Metaverse Deprovisioning\">In<\/a> this example we use the user\u00e2\u20ac\u2122s status attribute in the Metaverse to decide if the account should be moved to a \u00e2\u20ac\u0153<em>Disabled<\/em>\u00e2\u20ac\u009d OU.<\/p>\n<p>(The actual account disabling is done by an EAF and the <em>disableDate<\/em> and<br \/>\n<em>userAccountControl<\/em> are flowed back by IAFs \u00e2\u20ac\u201c see below.)<\/p>\n<p>We then use the <em>disableDate<\/em> attribute on the metaverse object to decide when to perform the final deletion.<\/p>\n<p>This example subroutine has been called from <em>Sub Provision<\/em> which is located in the Metaverse Extension code.<\/p>\n<pre lang=\"x-js\">Private Sub User_Provisioning(ByVal mventry As MVEntry)\r\n   Dim ADMA As ConnectedMA = mventry.ConnectedMAs(\"MyDomain\")\r\n   Dim expectedDN As ReferenceValue\r\n   Dim ShouldExist As Boolean\r\n   Dim DoesExist As Boolean\r\n   Const OU_USERS As String = \"OU=Users,OU=MyOrg,DC=mydomain,DC=com\"\r\n   Const OU_DISABLED As String = \"OU=Disabled,OU=Users,OU=MyOrg,DC=mydomain,DC=com\"\r\n   Const KEEP_DISABLED_DAYS As Integer = 90\r\n\r\n   '' Should the account exist?\r\n   '' Inactive accounts should exist for KEEP_DISABLED_DAYS after being disabled.\r\n   If mventry(\"status\").IsPresent AndAlso mventry(\"status\").StringValue = \"Active\" Then\r\n      ShouldExist = True\r\n   Else\r\n      ShouldExist = False\r\n\r\n      If MVEntry(\"userAccountControl\").IsPresent AndAlso _\r\n         MVEntry(\"disableDate\").IsPresent Then\r\n\r\n         If (MVEntry(\"userAccountControl\").IntegerValue And ADS_UF_ACCOUNTDISABLE) = _\r\n             ADS_UF_ACCOUNTDISABLE Then\r\n\r\n            'Account disabled \u00e2\u20ac\u201c allow to exist until deletion date\r\n            ShouldExist = True\r\n\r\n            Dim disabledDate As DateTime\r\n            disabledDate = Convert.ToDateTime(MVEntry(\"disableDate\").StringValue)\r\n            If Now.Subtract(disabledDate).Days &gt; KEEP_DISABLED_DAYS Then\r\n               ShouldExist = False\r\n            End If\r\n         Else\r\n            'Account enabled\r\n            ShouldExist = True\r\n         End If\r\n      End If\r\n   End If\r\n   '' Check if the AD account already exists\r\n   Select Case ADMA.Connectors.Count\r\n      Case 0\r\n         DoesExist = False\r\n      Case 1\r\n         DoesExist = True\r\n      Case Else\r\n         Throw New UnexpectedDataException(\"Multiple connectors in MA \" &amp; ADMA.Name)\r\n   End Select\r\n\r\n   '' Generate the expected DN for the user - to use in renaming or moving\r\n   Dim RDN As String = \"CN=\" &amp; mventry(\"displayName\").StringValue\r\n\r\n   If mventry(\"status\").StringValue = \"Active\" Then\r\n      expectedDN = ADMA.EscapeDNComponent(RDN).Concat(OU_USERS)\r\n   Else\r\n      expectedDN = ADMA.EscapeDNComponent(RDN).Concat(OU_DISABLED)\r\n   End If\r\n\r\n   '' Take action based on values of ShouldExist and DoesExist\r\n\r\n   If ShouldExist And DoesExist Then\r\n      'Check if account should be renamed or moved\r\n      Dim CSEntry As CSEntry = ADMA.Connectors.ByIndex(0)\r\n      If CSEntry.DN.ToString.ToLower &lt;&gt; expectedDN.ToString.ToLower Then\r\n         CSEntry.DN = expectedDN\r\n      End If\r\n\r\n   ElseIf ShouldExist And Not DoesExist Then\r\n      'Provision Account\r\n      &lt;...&gt;\r\n\r\n   ElseIf Not ShouldExist And DoesExist Then\r\n      'Deprovision Account\r\n      CSEntry.Deprovision()\r\n\r\n   End If\r\n End Sub<\/pre>\n<h3>Disabling Flow Rules<\/h3>\n<p><a name=\"Disabling Flow Rules\">With<\/a> these flow rules I disable an AD account and also write a date onto the object (I\u00e2\u20ac\u2122m using info but you can use any free attribute) to indicate when it was disabled.<\/p>\n<p>I also flow <em>userAccountControl<\/em> and info back into the metaverse so I have access to the values in my<br \/>\nmetaverse extension code (above).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/public.bay.livefilestore.com\/y1p--wnV_K-shH6tRb6q_v9QW6CK8ju5SvYrGmyGW6MnVhzsHhYziWODyCHvP4kcrnF3HUmReTUud6NEi7hpFdUXw\/DP01.jpg\" alt=\"\" width=\"572\" height=\"234\" \/><\/p>\n<pre lang=\"x-js\">Public Sub MapAttributesForExport(ByVal FlowRuleName As String, ByVal mventry As MVEntry, ByVal csentry As CSEntry) Implements IMASynchronization.MapAttributesForExport\r\n\r\n   Const ADS_UF_NORMAL_ACCOUNT As Long = &amp;H200\r\n   Const ADS_UF_ACCOUNTDISABLE As Long = &amp;H2\r\n\r\n   Select Case FlowRuleName\r\n\r\n      Case \"export_userAccountControl\"\r\n         Dim currentValue As Long\r\n\r\n         If csentry(\"userAccountControl\").IsPresent Then\r\n            currentValue = csentry(\"userAccountControl\").IntegerValue\r\n         Else\r\n            currentValue = ADS_UF_NORMAL_ACCOUNT\r\n         End If\r\n\r\n         If mventry(\"status\").IsPresent AndAlso mventry(\"status\").Value = \"Active\" Then\r\n            ' Enable account\r\n            csentry(\"userAccountControl\").IntegerValue = _\r\n            (currentValue Or ADS_UF_NORMAL_ACCOUNT) And (Not ADS_UF_ACCOUNTDISABLE)\r\n\r\n         Else\r\n            ' Disable account\r\n            csentry(\"userAccountControl\").IntegerValue = _\r\n            currentValue Or ADS_UF_ACCOUNTDISABLE\r\n         End If\r\n\r\n      Case \"export_info\"\r\n         If mventry(\"status\").IsPresent AndAlso mventry(\"status\").Value = \"Active\" _\r\n            AndAlso csentry(\"info\").IsPresent Then\r\n            csentry(\"info\").Delete()\r\n         ElseIf mventry(\"status\").Value = \"Inactive\" AndAlso _\r\n            Not csentry(\"info\").IsPresent Then\r\n            csentry(\"info\").StringValue = Now.ToString\r\n         End If\r\n\r\n      End Select\r\nEnd Sub<\/pre>\n<h3>XMA Delete Method<\/h3>\n<p><a name=\"XMA Delete Method\">For<\/a> an MA of type \u00e2\u20ac\u0153<em>Extensible Connectivity<\/em>\u00e2\u20ac\u009d you need to write your own routines for the export types<br \/>\n<em>Add<\/em>, <em>Modify<\/em> and <em>Delete<\/em>.<\/p>\n<p>This example shows the <em>Delete<\/em> step for an XMA which manages home folders for user accounts.<\/p>\n<p>The sub is found in the <em>Connected Data Source Extension<\/em>.<\/p>\n<p>This example is a very simple deletion of the folder, but you could easily add extra code to, for example, move the folder to an archive location.<\/p>\n<p>(If you want to see an example of the Add method see my blog:<br \/>\n<a href=\"https:\/\/www.wapshere.com\/missmiis\/creating-user-home-directories-windows-version\" target=\"_blank\">Creating Home Directories<\/a>)<\/p>\n<pre lang=\"x-js\"> Public Sub ExportEntry(ByVal modificationType As ModificationType, ByVal changedAttributes As String(), ByVal csentry As CSEntry) Implements IMAExtensibleCallExport.ExportEntry\r\n\r\nIf modificationType = Microsoft.MetadirectoryServices.ModificationType.Add Then\r\n' Create the folder\r\n\r\nElseIf modificationType = _\r\nMicrosoft.MetadirectoryServices.ModificationType.Delete Then\r\nSystem.IO.Directory.Delete(csentry(\"path\").StringValue, True)\r\nEnd If\r\n\r\nEnd Sub<\/pre>\n<h2>About the Author<\/h2>\n<p>Carol Wapshere has been working in IT since 1990, and has since worked in many different organizations, across four different countries. She started out in Netware then moved into Microsoft server products, picking up an assortment of skills in other non-Microsoft systems along the way. She first started working with MIIS in 2005 and loved how it could be used to tie together disparate systems, bringing in much-needed order, and making lots of tedious jobs just disappear.<\/p>\n<p>Thanks to Markus Vilcinskas and Peter Geelen for their help with this document.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I just posted this article in the Greatest Hits series of the ILM Technet forum. It describes some of the methods and considerations around disabling and deleting users accounts with ILM.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[34,28,1],"tags":[],"class_list":["post-671","post","type-post","status-publish","format-standard","hentry","category-ilm2007","category-miis2003","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pkp1o-aP","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/671","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/comments?post=671"}],"version-history":[{"count":4,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/671\/revisions"}],"predecessor-version":[{"id":675,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/671\/revisions\/675"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=671"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/categories?post=671"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/tags?post=671"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}