Synchronizing Country from FIM to Active Directory

Question: What do “c”, “co”, and “countryCode” all have in common?

Answer: They are all attributes found on user objects in Active Directory (AD) that represent a user’s country.

So, why is this the focus of a blog post? Well, it makes synchronizing a user’s country from FIM to AD a bit more complex than one would initially think. For starters, one might ask, “which attribute do I synchronize to?” Then the next question could be, “when I change the code on one attribute will the other two attributes automatically update?” Yet another is, “are only certain values allowed to be written to each of the different attributes?”

The answers to these questions and more will be found in this blog posting. In addition, we will provide a recommended approach for dealing with this issue.

First off, let’s look at the three different attributes in AD that represent a user’s country:

c: This is the ISO-3166 2-character string value for country. “US” is the 2-character string code for United States.
co: A user friendly representation of the country code. “United States” is the friendly name for US.
countryCode: ISO-3166 integer value for country. “840” is the integer value for United States.

Note: For more information about ISO standards for country codes including a list of codes, click here: ISO.org Web Site

These three attributes of a user account in AD can be viewed using the ADSI Edit tool.

Synchronizing Country to AD Screenshot: Country_ADSI

If you change a user’s Country/region using the drop down field in Active Directory Users and Computers (ADUC) tool, all three attributes are updated automatically. This is a function of ADUC and is not something that is occurring within the Active Directory database. So,if you change any of the three attributes programmatically, like synchronizing via FIM for example, the other two attributes are not updated. Therefore, if we want to ensure that we have a consistent representation of a user’s country within AD, we will need to write all three attributes to AD from FIM.

So, what is the best method for synchronizing these attributes from FIM? There is already an attribute in the FIM Portal called “Country”. When one assigns a country to a user via the FIM Portal, this attribute is updated with the  ISO-3166 2-character string value for country.

Synchronizing Country to AD Screenshot: FIM Portal Country

We know that in AD, the ISO-3166 2-character string value for country is represented by an attribute named “c”. So, we can easily synchronize the “Country” attribute in the FIM Portal to the “c” attribute in AD by adding a direct attribute flow to a Portal AD User outbound synchronization rule where source is “Country” and destination is “c”.

Writing “co” and “countryCode” to AD using an outbound Portal synchronization rule is a bit more complex than writing “c” because we don’t have simple one-to-one direct mappings for these other two attributes. One possible approach would be to add “co” and “countryCode” attributes to both the FIM Service database (in the Portal) and to the metaverse. With that approach, we could write workflows that would automatically update those attributes whenever the “Country” attribute in FIM was changed. However, there are a number of problems with this approach. First, it unnecessarily bloats the FIM databases by storing unnecessarily duplicated information. Second, workflows are inefficient and clutter the FIM Portal request history. And finally, workflows are difficult to monitor and re-run if you need to resolve any PostProcessingError conditions which crop up. With all that being said, a better alternative is to write these attributes to AD by calculating the correct values in the export flows of your outbound synchronization rule.

Once we’ve decided that the synchronization rule is the right place to implement this logic, we’re immediately challenged by the lack of an obvious way to convert the ISO-3166 2-character string value to the friendly name or integer value. As an example, when “c” changes to “US” we need to write “United States” to “co” and “840” to “countryCode”, but we do not have that data stored on the user accounts in FIM. Thankfully, FIM provides us with an option to use functions within our flows, which allow us to manipulate data during synchronization and prior to exporting it to our destination system (AD in this case). However, because the set of built-in functions is extremely limited and can’t be expanded through custom development, we’ll need to get a bit creative in order to figure out how we can accomplish this. For more information on all available FIM functions and how they are used check this link.

Populating the “co” Attribute

First let’s look at how we will populate “co” which is the user friendly representation of the country code in AD. The only allowed values for the “co” attribute in AD are the ISO-3166 friendly name values. If you attempt to write something else, you will receive a failure error. Since we don’t have the friendly names in FIM, we will add them to the custom expression and associate each with the appropriate 2-character country code.

This is an extremely long expression mostly because of the large number (233) of ISO-3166 country codes. This is the code that you would copy and paste into your AD Outbound Sync rule so that “co” will populate into AD.

Word(Word(ReplaceString("|AX|Aland Islands|AL|Albania|DZ|Algeria|AS|American Samoa|AD|Andorra|AO|Angola|AI|Anguilla|AQ|Antarctica|AG|Antigua and Barbuda|AR|Argentina|AM|Armenia|AW|Aruba|AU|Australia|AT|Austria|AZ|Azerbaijan|BH|Bahrain|XX|Baker Island|BD|Bangladesh|BB|Barbados|BY|Belarus|BE|Belgium|BZ|Belize|BJ|Benin|BM|Bermuda|BT|Bhutan|BO|Bolivia|BA|Bosnia and Herzegovina|BW|Botswana|BV|Bouvet Island|BR|Brazil|IO|British Indian Ocean Territory|BN|Brunei|BG|Bulgaria|BF|Burkina Faso|BI|Burundi|KH|Cambodia|CM|Cameroon|CA|Canada|CV|Cape Verde|KY|Cayman Islands|CF|Central African Republic|TD|Chad|CL|Chile|CN|China|CX|Christmas Island|CO|Colombia|KM|Comoros|CG|Congo|CK|Cook Islands|CR|Costa Rica|HR|Croatia|CU|Cuba|CY|Cyprus|CZ|Czech Republic|DK|Denmark|DJ|Djibouti|DM|Dominica|DO|Dominican Republic|EC|Ecuador|EG|Egypt|SV|El Salvador|GQ|Equatorial Guinea|ER|Eritrea|EE|Estonia|ET|Ethiopia|FO|Faroe Islands|FJ|Fiji Islands|FI|Finland|FR|France|GF|French Guiana|PF|French Polynesia|TF|French Southern and Antarctic Lands|GA|Gabon|GE|Georgia|DE|Germany|GH|Ghana|GI|Gibraltar|GR|Greece|GL|Greenland|GD|Grenada|GP|Guadeloupe|GU|Guam|GT|Guatemala|GG|Guernsey|GN|Guinea|GY|Guyana|HT|Haiti|HM|Heard Island and McDonald Islands|HN|Honduras|XX|Howland Island|HU|Hungary|IS|Iceland|IN|India|ID|Indonesia|IR|Iran|IQ|Iraq|IE|Ireland|IL|Israel|IT|Italy|JM|Jamaica|SJ|Jan Mayen|JP|Japan|XX|Jarvis Island|JE|Jersey|XX|Johnston Atoll|JO|Jordan|KZ|Kazakhstan|KE|Kenya|XX|Kingman Reef|KI|Kiribati|KR|Korea|KW|Kuwait|KG|Kyrgyzstan|LA|Laos|LV|Latvia|LB|Lebanon|LS|Lesotho|LR|Liberia|LY|Libya|LI|Liechtenstein|LT|Lithuania|LU|Luxembourg|MG|Madagascar|MW|Malawi|MY|Malaysia|MV|Maldives|ML|Mali|MT|Malta|MH|Marshall Islands|MQ|Martinique|MR|Mauritania|MU|Mauritius|YT|Mayotte|MX|Mexico|FM|Micronesia|XX|Midway Islands|MD|Moldova|MC|Monaco|MN|Mongolia|ME|Montenegro|MS|Montserrat|MA|Morocco|MZ|Mozambique|MM|Myanmar|NA|Namibia|NR|Nauru|NP|Nepal|NL|Netherlands|AN|Netherlands Antilles|NC|New Caledonia|NZ|New Zealand|NI|Nicaragua|NE|Niger|NG|Nigeria|NU|Niue|NF|Norfolk Island|KP|North Korea|MP|Northern Mariana Islands|NO|Norway|OM|Oman|PK|Pakistan|PW|Palau|PS|Palestinian Authority|XX|Palmyra Atoll|PA|Panama|PG|Papua New Guinea|PY|Paraguay|PE|Peru|PH|Philippines|PN|Pitcairn Islands|PL|Poland|PT|Portugal|PR|Puerto Rico|QA|Qatar|RE|Reunion|RO|Romania|RU|Russia|RW|Rwanda|WS|Samoa|SM|San Marino|SA|Saudi Arabia|SN|Senegal|CS|Serbia|SC|Seychelles|SL|Sierra Leone|SG|Singapore|SK|Slovakia|SI|Slovenia|SB|Solomon Islands|SO|Somalia|ZA|South Africa|GS|South Georgia and the South Sandwich Islands|ES|Spain|LK|Sri Lanka|SD|Sudan|SR|Suriname|SJ|Svalbard|SZ|Swaziland|SE|Sweden|CH|Switzerland|SY|Syria|ST|São Tomé and Príncipe|TW|Taiwan|TJ|Tajikistan|TZ|Tanzania|TH|Thailand|TG|Togo|TK|Tokelau|TO|Tonga|TT|Trinidad and Tobago|TN|Tunisia|TR|Turkey|TM|Turkmenistan|TC|Turks and Caicos Islands|TV|Tuvalu|UG|Uganda|UA|Ukraine|AE|United Arab Emirates|GB|United Kingdom|US|United States|UY|Uruguay|UZ|Uzbekistan|VU|Vanuatu|VA|Vatican City|VE|Venezuela|VN|Vietnam|VI|Virgin Islands|XX|Wake Island|WF|Wallis and Futuna|EH|Western Sahara|YE|Yemen|ZM|Zambia|ZW|Zimbabwe|","|"+country+"|","*"),2,"*"),1,"|")

How It Works

So that we can better understand the expression, I have simplified it to include only US and Germany below:

Word(Word(ReplaceString("|US|United States|DE|Germany|","|"+country+"|","*"),2,"*|"),1,"|")

So, we have an expression which is actually comprised of an expression nested within another expression which is nested in a third expression; the innermost using the function ReplaceString nested in two additional expressions using the Word function. Lets look at the innermost expression:

ReplaceString("|US|United States|DE|Germany|","|"+country+"|","*")

The ReplaceString function replaces all occurrences of a string to another string. The format is:

 ReplaceString(string, OldValue, NewValue)

So, in this case, the string is  “|US|United States|DE|Germany|”. The OldValue is “|”+country+”|”. The NewValue is “*”. So, when +country+ is passed by FIM as “US” for example, the output from the expression would be:

"*United States|DE|Germany|"

Basically, the expression replaced “|US|” with “*”. So now we need to wrap this expression in another expression with a Word function. The Word function returns a word contained within a string, based on parameters describing the delimiters to use and the word number to return. The format is as follows:

Word(string, number, delimiters)

The string in this case would be the output of the previous expression; “*United States|DE|Germany|”. So, again using “US” as the example, the expression would look like this after the innermost expression runs.

Word("*United States|DE|Germany|",2,"*")

The above function establishes “*” as the delimiter. Because the number specified is “2”, the function pulls the second “word” from the string. The word function defines a word as anything in a string that is separated by the delimiters. The function counts the non existent character to the left of the * as the first word. The second word is anything after the “*” leaving us with “United States|DE|Germany|”. All we did here was strip everything to the left of and including the “*”. So, now we have the final expression which again will use the Word function:

Word("United States|DE|Germany|",1,"|")

In this case the delimiter is “|” and the output will be everything to the left of it because the number is “1” which will provide us with the desired output for “co” of “United States”.

Populating the “countryCode” Attribute

So, now that we know how to populate “c” and “co”, let’s look at how we will populate the final attribute that represents country in AD; “countryCode”. This attribute represents the ISO-3166 integer value for country. So, for US, the value for “countryCode” should be “804”.

This is the code that you would copy and paste into your AD Outbound Sync rule so that “countryCode” will populate into AD.

IIF(Eq(Country,"AX"),248,IIF(Eq(Country,"AL"),8,IIF(Eq(Country,"DZ"),12,IIF(Eq(Country,"AS"),16,IIF(Eq(Country,"AD"),20,IIF(Eq(Country,"AO"),24,IIF(Eq(Country,"AI"),660,IIF(Eq(Country,"AQ"),10,IIF(Eq(Country,"AG"),28,IIF(Eq(Country,"AR"),32,IIF(Eq(Country,"AM"),51,IIF(Eq(Country,"AW"),533,IIF(Eq(Country,"AU"),36,IIF(Eq(Country,"AT"),40,IIF(Eq(Country,"AZ"),31,IIF(Eq(Country,"BH"),48,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"BD"),50,IIF(Eq(Country,"BB"),52,IIF(Eq(Country,"BY"),112,IIF(Eq(Country,"BE"),56,IIF(Eq(Country,"BZ"),84,IIF(Eq(Country,"BJ"),204,IIF(Eq(Country,"BM"),60,IIF(Eq(Country,"BT"),64,IIF(Eq(Country,"BO"),68,IIF(Eq(Country,"BA"),70,IIF(Eq(Country,"BW"),72,IIF(Eq(Country,"BV"),74,IIF(Eq(Country,"BR"),76,IIF(Eq(Country,"IO"),86,IIF(Eq(Country,"BN"),96,IIF(Eq(Country,"BG"),100,IIF(Eq(Country,"BF"),854,IIF(Eq(Country,"BI"),108,IIF(Eq(Country,"KH"),116,IIF(Eq(Country,"CM"),120,IIF(Eq(Country,"CA"),124,IIF(Eq(Country,"CV"),132,IIF(Eq(Country,"KY"),136,IIF(Eq(Country,"CF"),140,IIF(Eq(Country,"TD"),148,IIF(Eq(Country,"CL"),152,IIF(Eq(Country,"CN"),156,IIF(Eq(Country,"CX"),162,IIF(Eq(Country,"CO"),170,IIF(Eq(Country,"KM"),174,IIF(Eq(Country,"CG"),178,IIF(Eq(Country,"CK"),184,IIF(Eq(Country,"CR"),188,IIF(Eq(Country,"HR"),191,IIF(Eq(Country,"CU"),192,IIF(Eq(Country,"CY"),196,IIF(Eq(Country,"CZ"),203,IIF(Eq(Country,"DK"),208,IIF(Eq(Country,"DJ"),262,IIF(Eq(Country,"DM"),212,IIF(Eq(Country,"DO"),214,IIF(Eq(Country,"EC"),218,IIF(Eq(Country,"EG"),818,IIF(Eq(Country,"SV"),222,IIF(Eq(Country,"GQ"),226,IIF(Eq(Country,"ER"),232,IIF(Eq(Country,"EE"),233,IIF(Eq(Country,"ET"),231,IIF(Eq(Country,"FO"),234,IIF(Eq(Country,"FJ"),242,IIF(Eq(Country,"FI"),246,IIF(Eq(Country,"FR"),250,IIF(Eq(Country,"GF"),254,IIF(Eq(Country,"PF"),258,IIF(Eq(Country,"TF"),260,IIF(Eq(Country,"GA"),266,IIF(Eq(Country,"GE"),268,IIF(Eq(Country,"DE"),276,IIF(Eq(Country,"GH"),288,IIF(Eq(Country,"GI"),292,IIF(Eq(Country,"GR"),300,IIF(Eq(Country,"GL"),304,IIF(Eq(Country,"GD"),308,IIF(Eq(Country,"GP"),312,IIF(Eq(Country,"GU"),316,IIF(Eq(Country,"GT"),320,IIF(Eq(Country,"GG"),826,IIF(Eq(Country,"GN"),324,IIF(Eq(Country,"GY"),328,IIF(Eq(Country,"HT"),332,IIF(Eq(Country,"HM"),334,IIF(Eq(Country,"HN"),340,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"HU"),348,IIF(Eq(Country,"IS"),352,IIF(Eq(Country,"IN"),356,IIF(Eq(Country,"ID"),360,IIF(Eq(Country,"IR"),364,IIF(Eq(Country,"IQ"),368,IIF(Eq(Country,"IE"),372,IIF(Eq(Country,"IL"),376,IIF(Eq(Country,"IT"),380,IIF(Eq(Country,"JM"),388,IIF(Eq(Country,"SJ"),744,IIF(Eq(Country,"JP"),392,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"JE"),826,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"JO"),400,IIF(Eq(Country,"KZ"),398,IIF(Eq(Country,"KE"),404,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"KI"),296,IIF(Eq(Country,"KR"),410,IIF(Eq(Country,"KW"),414,IIF(Eq(Country,"KG"),417,IIF(Eq(Country,"LA"),418,IIF(Eq(Country,"LV"),428,IIF(Eq(Country,"LB"),422,IIF(Eq(Country,"LS"),426,IIF(Eq(Country,"LR"),430,IIF(Eq(Country,"LY"),434,IIF(Eq(Country,"LI"),438,IIF(Eq(Country,"LT"),440,IIF(Eq(Country,"LU"),442,IIF(Eq(Country,"MG"),450,IIF(Eq(Country,"MW"),454,IIF(Eq(Country,"MY"),458,IIF(Eq(Country,"MV"),462,IIF(Eq(Country,"ML"),466,IIF(Eq(Country,"MT"),470,IIF(Eq(Country,"MH"),584,IIF(Eq(Country,"MQ"),474,IIF(Eq(Country,"MR"),478,IIF(Eq(Country,"MU"),480,IIF(Eq(Country,"YT"),175,IIF(Eq(Country,"MX"),484,IIF(Eq(Country,"FM"),583,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"MD"),498,IIF(Eq(Country,"MC"),492,IIF(Eq(Country,"MN"),496,IIF(Eq(Country,"ME"),499,IIF(Eq(Country,"MS"),500,IIF(Eq(Country,"MA"),504,IIF(Eq(Country,"MZ"),508,IIF(Eq(Country,"MM"),104,IIF(Eq(Country,"NA"),516,IIF(Eq(Country,"NR"),520,IIF(Eq(Country,"NP"),524,IIF(Eq(Country,"NL"),528,IIF(Eq(Country,"AN"),530,IIF(Eq(Country,"NC"),540,IIF(Eq(Country,"NZ"),554,IIF(Eq(Country,"NI"),558,IIF(Eq(Country,"NE"),562,IIF(Eq(Country,"NG"),566,IIF(Eq(Country,"NU"),570,IIF(Eq(Country,"NF"),574,IIF(Eq(Country,"KP"),408,IIF(Eq(Country,"MP"),580,IIF(Eq(Country,"NO"),578,IIF(Eq(Country,"OM"),512,IIF(Eq(Country,"PK"),586,IIF(Eq(Country,"PW"),585,IIF(Eq(Country,"PS"),275,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"PA"),591,IIF(Eq(Country,"PG"),598,IIF(Eq(Country,"PY"),600,IIF(Eq(Country,"PE"),604,IIF(Eq(Country,"PH"),608,IIF(Eq(Country,"PN"),612,IIF(Eq(Country,"PL"),616,IIF(Eq(Country,"PT"),620,IIF(Eq(Country,"PR"),630,IIF(Eq(Country,"QA"),634,IIF(Eq(Country,"RE"),638,IIF(Eq(Country,"RO"),642,IIF(Eq(Country,"RU"),643,IIF(Eq(Country,"RW"),646,IIF(Eq(Country,"WS"),882,IIF(Eq(Country,"SM"),674,IIF(Eq(Country,"SA"),682,IIF(Eq(Country,"SN"),686,IIF(Eq(Country,"CS"),891,IIF(Eq(Country,"SC"),690,IIF(Eq(Country,"SL"),694,IIF(Eq(Country,"SG"),702,IIF(Eq(Country,"SK"),703,IIF(Eq(Country,"SI"),705,IIF(Eq(Country,"SB"),90,IIF(Eq(Country,"SO"),706,IIF(Eq(Country,"ZA"),710,IIF(Eq(Country,"GS"),239,IIF(Eq(Country,"ES"),724,IIF(Eq(Country,"LK"),144,IIF(Eq(Country,"SD"),736,IIF(Eq(Country,"SR"),740,IIF(Eq(Country,"SJ"),744,IIF(Eq(Country,"SZ"),748,IIF(Eq(Country,"SE"),752,IIF(Eq(Country,"CH"),756,IIF(Eq(Country,"SY"),760,IIF(Eq(Country,"ST"),678,IIF(Eq(Country,"TW"),158,IIF(Eq(Country,"TJ"),762,IIF(Eq(Country,"TZ"),834,IIF(Eq(Country,"TH"),764,IIF(Eq(Country,"TG"),768,IIF(Eq(Country,"TK"),772,IIF(Eq(Country,"TO"),776,IIF(Eq(Country,"TT"),780,IIF(Eq(Country,"TN"),788,IIF(Eq(Country,"TR"),792,IIF(Eq(Country,"TM"),795,IIF(Eq(Country,"TC"),796,IIF(Eq(Country,"TV"),798,IIF(Eq(Country,"UG"),800,IIF(Eq(Country,"UA"),804,IIF(Eq(Country,"AE"),784,IIF(Eq(Country,"GB"),826,IIF(Eq(Country,"US"),840,IIF(Eq(Country,"UY"),858,IIF(Eq(Country,"UZ"),860,IIF(Eq(Country,"VU"),548,IIF(Eq(Country,"VA"),336,IIF(Eq(Country,"VE"),862,IIF(Eq(Country,"VN"),704,IIF(Eq(Country,"VI"),850,IIF(Eq(Country,"XX"),581,IIF(Eq(Country,"WF"),876,IIF(Eq(Country,"EH"),732,IIF(Eq(Country,"YE"),887,IIF(Eq(Country,"ZM"),894,IIF(Eq(Country,"ZW"),716,"")))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

How It Works

Again, in the interest of making this easier to read, we’ll look at how it would look supporting only the US and Germany:

IIF(Eq(Country,"US"),804,IIF(Eq(Country,"DE"),206,""))

So again we are nesting expressions but in this case we are nesting an expression using the IIF function within another expression using the IIF function. The IIF function returns one of a set of possible values based on a specified condition. The format is as follows:

Object IIF(condition, valueIfTrue, valueIfFalse)

So, our expression reads, If the country is “US” the output is 804, if the country is “DE”, then the output is 206, otherwise the output is “”. The double quotes represent $null.

Summary

So there you have it. As long as you have the ISO-3166 2-character string value for country in the metaverse for your users, you can be certain that “c”, “co”, and “countryCode” in Active Directory are correct by adding these three separate Attribute Flows to your Outbound AD Sync rule. To wrap things up, I’ve included a screenshot of how the three flows look when added to your AD outbound sync rule in FIM:

Synchronizing Country to AD Screenshot: Outbound Sync Rule

 

About Matthew Brooks

Over 15 years experience in the IdAM field.

Leave a Reply

Your email address will not be published.