{"id":1065,"date":"2010-11-13T18:41:00","date_gmt":"2010-11-13T18:41:00","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?p=1065"},"modified":"2022-10-31T02:52:26","modified_gmt":"2022-10-31T02:52:26","slug":"importing-groups-from-ad-to-the-fim-portal-using-classic-flow-rules","status":"publish","type":"post","link":"https:\/\/www.wapshere.com\/missmiis\/importing-groups-from-ad-to-the-fim-portal-using-classic-flow-rules","title":{"rendered":"Importing groups from AD to the FIM Portal using classic flow rules"},"content":{"rendered":"<p>My general negativity about FIM codeless sync aka &#8220;declarative provisioning&#8221; aka &#8220;Synchronization Rule Provisioning&#8221; is, I think, reasonably well-known by now. While Markus wrote <a href=\"http:\/\/social.technet.microsoft.com\/wiki\/contents\/articles\/how-do-i-synchronize-groups-from-active-directory-domain-services-to-fim.aspx?wa=wsignin1.0\">an excellent document<\/a> about importing AD groups into the FIM Portal using the codeless rules, I think there are still plenty of reasons to go old skool, and here&#8217;s how you&#8217;d do it.<\/p>\n<p><!--more--><\/p>\n<h3>PreReqs<\/h3>\n<p>Custom sync rules do involve .NET coding, so you&#8217;re going to need Visual Studio installed on the Sync server. My example code in is VB.NET so you&#8217;ll need the Visual Basic libraries installed to use them.<\/p>\n<blockquote><p>And it&#8217;s only a minusculey tiny bit of code, okay?<\/p><\/blockquote>\n<p>I will assume you&#8217;ve already managed to create your AD and FIM management agents, <em>and<\/em> that you have already sucessfully imported or joined the group members &#8211; ie the users and contacts.<\/p>\n<p>The &#8220;member&#8221; attribute is relational, meaning it effectively points to other objects that it also knows about. To maintain the referential relationship from AD through to the FIM Portal you must satisfy the following requirements:<\/p>\n<ul>\n<li>The groups <em>and<\/em> their member objects must exist within the connector space of the same AD MA. You can&#8217;t import groups from one MA and users from another &#8211; you have to have the groups and users together.<\/li>\n<li>The groups <em>and<\/em> their members must be joined to their metaverse counterparts, either through Join or Projection rules.<\/li>\n<li>The groups <em>and<\/em> their members must be exported through the same FIM MA to the FIM Portal (though AFAIK you can only have one FIM MA anyway).<\/li>\n<\/ul>\n<h3>Step 1: Importing the AD Groups into the Metaverse<\/h3>\n<table border=\"1\">\n<tbody>\n<tr>\n<td>First make sure that the OU(s) containing the groups are within the scope of your MA.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/01%20ADMA%20containers.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Next check the &#8220;group&#8221; object type.<\/p>\n<p>Note I also have my potential group member object types selected, and within the scope of the MA &#8211; see the comment above about maintaining references in the prereqs section above.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/02%20ADMA%20object%20types.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>And make sure the following attributes are selected: displayName, domain, groupType, member, sAMAccountName, (and for Distribution Lists) mail, mailNickname.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/03%20ADMA%20attribs.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Create a Projection Rule. This will project AD groups as new group objects in the Metaverse. Note the following points:<\/p>\n<ol>\n<li>You should also create a Join Rule so that already-projected groups may be rejoined automatically if they happen to become disconnected,<\/li>\n<li>If you want some groups to be ignored then the simplest way is with a Connector Filter. Otherwise you can use a coded Projection Rule, but I won&#8217;t be going into that here.<\/li>\n<\/ol>\n<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/04%20ADMA%20project.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Next create Direct import flow rules for the following attributes:<\/p>\n<p>displayName &#8211;&gt; displayName<br \/>\nsAMAccountName &#8211;&gt; accountName<br \/>\nmember &#8211;&gt; member<br \/>\nmail &#8211;&gt; mail<br \/>\nmailNickname &#8211;&gt; mailNickname<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/05%20ADMA%20direct%20IAF.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>At this point you can save the MA and go ahead and run an Import-Sync.<\/p>\n<p>What you should see is some group objects projected into the Metaverse. If you&#8217;ve already mapped the group object type in the FIM MA you should see objects created there too, but don&#8217;t try to export them yet, we need to add a few more attributes.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/06%20ADMA%20test%20projection.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Now go back into your AD MA and add the following Advanced import flow rules:<\/p>\n<p>Constant: your NETBIOS domain name &#8211;&gt; domain<br \/>\nConstant: &#8220;Owner Approval&#8221; &#8211;&gt; membershipAddWorkflow<br \/>\nConstant: &#8220;false&#8221; &#8211;&gt; membershipLocked<br \/>\ngroupType &#8211;&gt; Rules Extension: &#8220;import_scope&#8221; &#8211;&gt; scope<br \/>\ngroupType &#8211;&gt; Rules Extension: &#8220;import_type&#8221; &#8211;&gt; type<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/07%20ADMA%20adv%20IAF.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>When you try and save the MA now you should get this error:<br \/>\n&#8220;Rules Extension validation error: Please specify a valid rules extension name.&#8221;<\/p>\n<p>When you click OK you will be taken to the place where you can specify the name of the dll where those two advanced rules (import_scope and import_type) are to be found. In fact we haven&#8217;t written the dll yet, but that&#8217;s ok, just accept the default name.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/08%20extension%20name.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Now it is time to create the extension project.<\/p>\n<p>Select your MA and click <strong>Create Extension Project<\/strong>. You want to create a project of type &#8220;Rules Extension&#8221;.<\/p>\n<p>Check the default name &#8211; it should be the same as already set in the MA in the previous step (if it somehow isn&#8217;t don&#8217;t worry, you can always change the dll referenced in the MA later).<\/p>\n<p>The only thing you might want to change is the folder where the project will be created.<\/p>\n<p>When you&#8217;re ready, click OK and the new project will be created and opened in Visual Studio for you (assuming you installed Visual Studio on the server).<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/09%20new%20extension.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Now fill in the MapAttributesForImport section of the project as shown here.<\/p>\n<p>Once you&#8217;ve done that you can compile the code. The dll shoud be put straight into the correct folder for you (normally C:\\Program Files\\Microsoft Forefront Identity Manager\\2010\\Synchronization Service\\Extensions).<\/td>\n<td>\n<pre>Public Sub MapAttributesForImport(ByVal FlowRuleName As String, ByVal csentry As CSEntry,\n ByVal mventry As MVEntry) Implements IMASynchronization.MapAttributesForImport\n\n    Select Case FlowRuleName\n        Case \"import_type\"\n            Select Case csentry(\"groupType\").IntegerValue\n                Case 2, 4, 8\n                    mventry(\"type\").Value = \"Distribution\"\n                Case Else\n                    mventry(\"type\").Value = \"Security\"\n            End Select\n\n        Case \"import_scope\"\n            Select Case csentry(\"groupType\").IntegerValue\n                Case 2, -2147483646\n                    mventry(\"scope\").Value = \"Global\"\n                Case 4, -2147483644\n                    mventry(\"scope\").Value = \"DomainLocal\"\n                Case Else\n                    mventry(\"scope\").Value = \"Universal\"\n            End Select\n\n        Case Else\n            Throw New EntryPointNotImplementedException()\n\n    End Select\nEnd Sub<\/pre>\n<\/td>\n<\/tr>\n<tr>\n<td>Now you should be able to Sync the AD MA and check how the group objects look in the Metaverse.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/10%20mventry.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Step 2: Exporting the Groups from the Metaverse to the FIM Portal<\/h3>\n<table border=\"1\">\n<tbody>\n<tr>\n<td>There are a couple of Portal MPRs that must be enabled to allow the Sync Service to create groups in the Portal.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/00%20FIM%20MA%20MPR.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>If you haven&#8217;t already done so, select the group object type in your FIM MA.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/01%20FIMMA%20object%20types.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>And add the mapping to the Metaverse group type.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/02%20FIMMA%20object%20mapping.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Now all you should need to do is add simple export flow rules for these attributes: accountName, displayName, domain, scope, type, membershipAddWorkflow, membershipLocked, member, (and for Distribution groups) mail, mailNickname .<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/03%20FIMMA%20eaf.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>Run another Sync on the AD MA and now you should be able to see the group objects in the FIM connector space, ready to export.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/04%20FIMMA%20csentry.JPG\" alt=\"\" \/><\/td>\n<\/tr>\n<tr>\n<td>After running an Export from the FIM MA the groups should be in the Portal, and you can start to manage them there.<\/p>\n<p>Note there is an error being reported about selecting a manger. If you do happen to have the group manager field populated in AD then by all means go ahead and import it from AD through to the Portal. Otherwise you will have to chose a manager directly in the Portal.<\/td>\n<td><img decoding=\"async\" src=\"https:\/\/www.wapshere.com\/images\/import_groups\/05%20FIMMA%20portal.JPG\" alt=\"\" width=\"600\" \/><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Troubleshooting FIM MA export errors<\/h3>\n<p>The FIM MA can give you some rather cryptic looking failed-creation-via-web-services messages, but usually if you read them properly you can work out the problem.<\/p>\n<h4>1. Missing Required Attribute<\/h4>\n<p>Here I have forgotten to populate the &#8220;Domain&#8221; attribute<\/p>\n<div><code>Fault Reason: The request message contains errors that prevent processing the request.<\/code><\/div>\n<div><code>Fault Details: &lt;RepresentationFailures xmlns=\"http:\/\/schemas.microsoft.com\/2006\/11\/ResourceManagement\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;&lt;AttributeRepresentationFailure&gt;&lt;AttributeType&gt;<span style=\"background-color: yellow;\">Domain<\/span>&lt;\/AttributeType&gt;<\/code><\/div>\n<div><code>&lt;AttributeValue&gt;&lt;\/AttributeValue&gt;&lt;FailureMessage&gt;<span style=\"background-color: yellow;\">An attribute is required to complete the operation.<\/span>&lt;\/FailureMessage&gt;<\/code><\/div>\n<div><code>&lt;AttributeFailureCode&gt;RequiredValueIsMissing&lt;\/AttributeFailureCode&gt;&lt;\/AttributeRepresentationFailure&gt;&lt;\/RepresentationFailures&gt;<\/code><\/div>\n<h4>2. Incorrect Attribute Value<\/h4>\n<p>Some attributes in the Portal Schema have validation strings listing which values are allowed. Here I&#8217;ve tried to export a type of &#8220;Distribution List&#8221; instead of &#8220;Distribution&#8221;, and that has been blocked.<\/p>\n<div><code><br \/>\nFault Reason: The request message contains errors that prevent processing the request.<\/code><\/div>\n<p><code>Fault Details: &lt;RepresentationFailures xmlns=\"http:\/\/schemas.microsoft.com\/2006\/11\/ResourceManagement\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" xmlns:xsd=\"http:\/\/www.w3.org\/2001\/XMLSchema\"&gt;&lt;AttributeRepresentationFailure&gt;&lt;AttributeType&gt;<span style=\"background-color: yellow;\">Type<\/span>&lt;\/AttributeType&gt;<br \/>\n&lt;AttributeValue&gt;<span style=\"background-color: yellow;\">Distribution List<\/span>&lt;\/AttributeValue&gt;&lt;FailureMessage&gt;<span style=\"background-color: yellow;\">The specified attribute value does not satisfy the regular expression.<\/span>&lt;\/FailureMessage&gt;&lt;AttributeFailureCode&gt;ValueViolatesRegularExpression&lt;\/AttributeFailureCode&gt;&lt;\/AttributeRepresentationFailure&gt;&lt;\/RepresentationFailures&gt;<br \/>\n<\/code><\/p>\n<h4>3. Permissions failure<\/h4>\n<p>Your MPRs need to allow the Built-In Synchronization account to create Group objects in the Portal. In this rather long-winded messages there are a few immediate giveaways.<\/p>\n<div><code><br \/>\nThere is an error executing a web service object creation request.<br \/>\nType: Microsoft.ResourceManagement.WebServices.Client.PermissionDeniedException <\/code><\/div>\n<div><code>Message: Fault Reason: <span style=\"background-color: yellow;\">Policy prohibits the request from completing.<\/span><\/code><\/div>\n<div><code>Fault Details:<\/code><\/div>\n<div><span style=\"background-color: yellow;\">No policy grants the Requestor permission to complete all changes.<\/span><\/div>\n<p>Exception: ManagementPolicyRule<br \/>\nStack Trace: Microsoft.ResourceManagement.WebServices.Exceptions.PermissionDeniedException: ManagementPolicyRule &#8212;&gt; System.Data.SqlClient.SqlException: Reraised Error 50000, Level 16, State 1, Procedure DoEvaluateRequestInner, Line 462, Message: Permission denied.<br \/>\nat System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)<br \/>\nat System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)<br \/>\nat System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)<br \/>\nat System.Data.SqlClient.SqlDataReader.ConsumeMetaData()<br \/>\nat System.Data.SqlClient.SqlDataReader.get_MetaData()<br \/>\nat System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)<br \/>\nat System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)<br \/>\nat System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)<br \/>\nat System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)<br \/>\nat System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)<br \/>\nat System.Data.SqlClient.SqlCommand.ExecuteReader()<br \/>\nat Microsoft.ResourceManagement.Data.DataAccess.DoRequestCreation(RequestType request, Guid cause, Guid requestMarker, Boolean doEvaluation, Int16 serviceId, Int16 servicePartitionId)<br \/>\n&#8212; End of inner exception stack trace &#8212;<br \/>\nat Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(CreateRequestDispatchParameter dispatchParameter)<br \/>\nat Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(UniqueIdentifier requestor, UniqueIdentifier targetIdentifier, OperationType operation, String businessJustification, List`1 requestParameters, CultureInfo locale, Boolean isChildRequest, Guid cause, Boolean doEvaluation, Nullable`1 serviceId, Nullable`1 servicePartitionId)<br \/>\nat Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(UniqueIdentifier requestor, UniqueIdentifier targetIdentifier, OperationType operation, String businessJustification, List`1 requestParameters, CultureInfo locale, Boolean isChildRequest, Guid cause, Boolean doEvaluation)<br \/>\nat Microsoft.ResourceManagement.WebServices.ResourceManagementService.Create(Message request)ManagementPolicyRule<\/p>\n<p>Stack Trace: at Microsoft.ResourceManagement.WebServices.ResourceFactoryClient.Create(Message request)<br \/>\nat Microsoft.ResourceManagement.WebServices.ResourceFactoryClient.Create(Create createBody)<br \/>\nat Microsoft.ResourceManagement.WebServices.Client.ResourceTemplate.CreateResource()<\/p>\n<p>Inner Exception: <span style=\"background-color: yellow;\">Policy prohibits the request from completing.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>My general negativity about FIM codeless sync aka &#8220;declarative provisioning&#8221; aka &#8220;Synchronization Rule Provisioning&#8221; is, I think, reasonably well-known by now. While Markus wrote an excellent document about importing AD groups into the FIM Portal using the codeless rules, I think there are still plenty of reasons to go old skool, and here&#8217;s how you&#8217;d&#8230;<\/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":[24,42,22],"tags":[],"class_list":["post-1065","post","type-post","status-publish","format-standard","hentry","category-ad","category-fim-2010","category-groups"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pkp1o-hb","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1065","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=1065"}],"version-history":[{"count":15,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1065\/revisions"}],"predecessor-version":[{"id":3306,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1065\/revisions\/3306"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=1065"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/categories?post=1065"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/tags?post=1065"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}