<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Alex Tcherniakhovski - Security : Active Directory Programming</title><link>http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx</link><description>Tags: Active Directory Programming</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Utility to load Active Directory with sample data and introduce incremental changes</title><link>http://blogs.msdn.com/alextch/archive/2007/07/10/ADModifier.aspx</link><pubDate>Wed, 11 Jul 2007 00:17:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:3803570</guid><dc:creator>alextch</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alextch/comments/3803570.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=3803570</wfw:commentRss><description>&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm" mce_href="http://www.microsoft.com/info/cpyright.htm"&gt;http://www.microsoft.com/info/cpyright.htm&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Quite often I find myself in a situation where I need to quickly build a test environment for Active Directory (AD), whether it is to perform some MIIS directory synchronization testing or performance benchmarking of an application that utilizes AD.&lt;BR&gt;I took an initial stab at this problem by creating a simple VB script (ADPopulator) that was using several Excel spreadsheets as an input for creating some randomized by still realistic user information. You can see more info on that script here:&amp;nbsp; &lt;A href="http://blogs.msdn.com/alextch/archive/2006/09/18/AdPopulate.aspx" mce_href="http://blogs.msdn.com/alextch/archive/2006/09/18/AdPopulate.aspx"&gt;http://blogs.msdn.com/alextch/archive/2006/09/18/AdPopulate.aspx&lt;/A&gt;. The script has a number of limitations though: &lt;BR&gt;•&amp;nbsp;It only deals with user accounts and does not provide support for group population&lt;BR&gt;•&amp;nbsp;You can only load accounts using this script. Quite often in directory synchronization tests we need to introduce some random changes into directory (modifications, deletions, additions)&lt;BR&gt;•&amp;nbsp;It has very limited support for randomly populating AD attributes beyond SN, givenName, samAccountName, and userPrincipal Name&lt;BR&gt;•&amp;nbsp;It requires Excel to be installed on the server&lt;BR&gt;So when working on a test harness for my Oracle extensible MA I decided to write something that addressed the above limitations.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Introducing ADModifer 1.0&lt;BR&gt;ADModifier is written in C# (get the source and executable in the attachment section of this blog), and unlike the ADPopulator does not require Excel to be installed on the server. As a matter of fact all that is required to run this utility is .NET 2.0 framework. &lt;BR&gt;Similarly to ADPopulator&amp;nbsp; ADModifier utilizes a dictionary of European names to generate random material for SN, givenName, samAccountName, userPrincipal Name. This time in order to avoid the need for Excel or other databases I simply included the dictionary right in the executable by creating two classed FirstNames and LastNames. This change helps with rapid test environment setup, where all you need to do is just drop the executable on the server. But if you need to add some additional names into your test environment you would have to modify the source code (take a look at FirstNames and LastNames classes, I am sure it will be evident how to add additional names into the mix).&lt;BR&gt;ADModifer utilizes .NET config file (ADModifer.exe.config) for its configuration settings. I will go over the config file parameters in detail later in this blog.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;STRONG&gt;Some conceptual stuff&lt;/STRONG&gt;&lt;BR&gt;Before getting you started with the utility let me explain some of the concepts that I used when developing this utility.&lt;BR&gt;Randomness&lt;BR&gt;There are several aspects of randomness that I utilize in this utility. &lt;BR&gt;&lt;STRONG&gt;First&lt;/STRONG&gt;, the user IDs are generated by randomly selecting first and last name from a dictionary of European names. Prior to creating a new account the utility checks if such ID based on a random combination already exists and will add an integer to the end of the ID if a conflict exists. There is logic in the utility to keep looping and incrementing the integer until a unique ID is found, that is why you will see IDs of such format jbrown1234.&lt;BR&gt;&lt;STRONG&gt;Second&lt;/STRONG&gt; aspect of randomness in the utility is about picking accounts for deletion and modifications.&amp;nbsp; At startup the utility will search the directory and create an array of all the user objects currently present in AD. If your directory is empty then run the utility in initialLoad mode to only create new accounts (more on this when we talk about the config file). Once such an array is created we can randomly pick objects from the array by using .NET random object. So if we want delete 5% percent of the existing accounts the utility will iterate through the array and using random number generator as an index into the array of all AD objects will delete the required number of accounts. Same idea for modifying accounts&lt;BR&gt;Before I bring in the &lt;STRONG&gt;third&lt;/STRONG&gt; aspect of randomness in the utility let me introduce the concept of a template first.&lt;BR&gt;Prior to running a utility you will create an OU into which you will place accounts that represent your typical user account settings. For example: you may simulate different departments and locations by creating template accounts that represent respective user populations. So let’s say in my test I want to simulate a company with four locations. I will create four accounts in the designated OU (more on this OU in the config section of this blog).&amp;nbsp; Each template account will have all of the attributes setup to represent that specific location (for example: l, department, manager, postalAddress etc). Also create some AD groups that are typical in that location and add the template accounts into those groups.&lt;BR&gt;The idea here is that when we are creating a new account or modifying and existing account a set of attributes will be copied by randomly selecting a template account and copying those attribute from it. This can simulate employees moving to a different location or a different department. Also this approach allows for introducing some changes into the group membership within AD. So this the third aspect of randomness in this utility – we randomly select a template account from which we copy specified attributes and group membership.&amp;nbsp; The more template accounts your create the better distribution of values you will get in your test environment.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Getting Started&lt;/STRONG&gt;&lt;BR&gt;So enough with theory let’s take ADModifier for a spin&lt;BR&gt;1.&amp;nbsp;Installation. Copy ADModifer and ADModifier.exe.config to a folder of your choosing on the server.&lt;BR&gt;2.&amp;nbsp;Preparing AD.&lt;BR&gt;a.&amp;nbsp;Create an OU structure into which you want ADModifier to create new accounts. I suggest creating an OU dedicated for testing. This OU can have children; there are no limitations on the depth of the tree.&amp;nbsp; New accounts will be evenly and randomly distributed between OUs in this structure.&lt;BR&gt;b.&amp;nbsp;Create a separate OU outside the OU you created in step A for groups.&amp;nbsp; Manually create as many groups as you think are necessary for your tests. &lt;BR&gt;c.&amp;nbsp;Create a separate OU outside the OU you created in step A for template accounts. Create as many template accounts as you need (the names of the template accounts are arbitrary). Set all of the AD attributes that personalize a template account (department, location, address, manager, etc). Also add the template accounts into the groups created in step B. The idea here is that each template account will be a member of specific set of groups. Those group memberships and attributes will be copied into new and modified accounts.&lt;BR&gt;3.&amp;nbsp;Modify ADModifier.exe.config to adjust it to your environment.&lt;BR&gt;Below is a sample config file that I used in my test environment.&lt;BR&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;BR&gt;&amp;lt;configuration&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;appSettings&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="initialLoad" value="FALSE"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="initialLoadAmount" value="10"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="usersRoot" value="OU=employees,DC=contoso,DC=msft"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="addAtTheRoot" value="FALSE"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="userTemplateRoot" value="OU=templates,DC=contoso,DC=msft"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="defaultPwd" value="&lt;A href="mailto:pass@word1%22/" mce_href="mailto:pass@word1%22/"&gt;pass@word1"/&lt;/A&gt;&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="attributesToCopyFromTemplate" value="l;deparment”/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="percentToAdd" value="5"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="percentToDelete" value="5"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;add key="percentToModify" value="5"/&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;lt;/appSettings&amp;gt;&lt;BR&gt;&amp;lt;/configuration&amp;gt;&lt;BR&gt;Let me go through each of those setting one at a time&lt;BR&gt;&lt;STRONG&gt;initialLoad &lt;/STRONG&gt;– if your AD is empty you will need to do initial loading of sample data. In other words you are not at the point to specify in terms of % how much change to introduce, you simply want to get some initial data loaded. Note: even for the initial load you will need template accounts setup, since new accounts will be personalized based on those tamplates.&lt;BR&gt;&lt;STRONG&gt;initialLoadAmount&lt;/STRONG&gt; – This attribute is used in conjunction with the initialLoad and specifies how many accounts to create&lt;BR&gt;&lt;STRONG&gt;userRoot &lt;/STRONG&gt;– Distinguished name of the OU where new accounts will be created. This OU is also used as a target for account deletions and modifications. OUs that reside below this OU will also be used by addition, deletion and modification processes&lt;BR&gt;&lt;STRONG&gt;addAtTheRoot &lt;/STRONG&gt;– Quite often you may want to setup your OU structure as such: employees-&amp;gt;East, employees-&amp;gt;West. In this setup East and West are children of the employee OU, and if you don’t want new accounts to be created at the root (in this case employees, but only in sub OUs: east and west) set this value to FALSE. If you have only one OU into which you want to load all of you new accounts make sure to set this to TRUE.&lt;BR&gt;&lt;STRONG&gt;defaultPwd &lt;/STRONG&gt;– The value of a password that will be assigned to the new accounts&lt;BR&gt;&lt;STRONG&gt;attributesToCopyFromTemplate&lt;/STRONG&gt; – This is a list of attributes separated by semi-column which you want to be copied from the template accounts&lt;BR&gt;&lt;STRONG&gt;percentToAdd&lt;/STRONG&gt; - % of new accounts to be created&lt;BR&gt;&lt;STRONG&gt;percentToDelete&lt;/STRONG&gt; - % of accounts to be deleted&lt;BR&gt;&lt;STRONG&gt;percentToModify&lt;/STRONG&gt; - % of accounts to be modified &lt;BR&gt;4.&amp;nbsp;On your first run set the initialLoad to TRUE and specify the number of accounts you need to create.&lt;BR&gt;5.&amp;nbsp;On subsequent runs set the intialLoad to FALSE and adjust percent values for additions, deletions and modifications.&lt;/P&gt;
&lt;P&gt;Certain things to be aware of&lt;BR&gt;1.&amp;nbsp;Performance. Since at startup the utility needs to create an array of all existing accounts in the AD, this may take quite a bit of time and memory if you are building really large AD database. In my environment with 12000 accounts it takes over a minute for the utility to start doing some work.&lt;BR&gt;2.&amp;nbsp;Make sure to put correct values in the config file. I am only doing limited error checking so some error messages may be quite generic if you put wrong values into the config file.&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;After publishing this blog, I got a couple of e-mails where people were getting "The Server is unwilling to process the request error". After investigating this further I found a bug in my code, which is not fixed.&lt;/P&gt;
&lt;P&gt;The issue was around setting the userAccessControl attribute. Initially I was setting this attribute in the following sequence:&lt;/P&gt;
&lt;P&gt;newUser.Properties["userAccountControl"].Value = 512; newUser.CommitChanges();&lt;BR&gt;newUser.CommitChanges();&lt;BR&gt;newUser.Invoke("SetPassword", new object[] { ConfigurationSettings.AppSettings.Get("defaultPwd") });&lt;/P&gt;
&lt;P&gt;which worked fine in my lab environment where password complexity policy was disabled, but would produce the above mentioned error if password complexity policy is enabled.&lt;/P&gt;
&lt;P&gt;Rearanging the sequence like so fixed the issue:&lt;/P&gt;
&lt;P&gt;newUser.Invoke("SetPassword", new object[] { ConfigurationSettings.AppSettings.Get("defaultPwd") });&lt;BR&gt;newUser.Properties["userAccountControl"].Value = 512; newUser.CommitChanges();&lt;BR&gt;newUser.CommitChanges();&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=3803570" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/alextch/attachment/3803570.ashx" length="60084" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item><item><title>Active Directory Schema Design Considerations and Auxiliary Classes</title><link>http://blogs.msdn.com/alextch/archive/2007/05/16/active-directory-schema-design-considerations-and-auxiliary-classes.aspx</link><pubDate>Wed, 16 May 2007 22:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2678425</guid><dc:creator>alextch</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alextch/comments/2678425.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=2678425</wfw:commentRss><description>&lt;P&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm" mce_href="http://www.microsoft.com/info/cpyright.htm"&gt;http://www.microsoft.com/info/cpyright.htm&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;This blog addresses one very specific but important issue around rules of creating auxiliary classes, and as most of my blogs, is based on something I stumbled upon while working on one of my projects.&lt;BR&gt;The scenario I am working on involves extending Active Directory schema for the purposes of storing Oracle related information in Active Directory. For more details on the approach of synchronizing AD and Oracle security information see my previous blog on this subject: &lt;A href="http://blogs.msdn.com/alextch/archive/2006/06/05/ADtoOra.aspx" mce_href="http://blogs.msdn.com/alextch/archive/2006/06/05/ADtoOra.aspx"&gt;http://blogs.msdn.com/alextch/archive/2006/06/05/ADtoOra.aspx&lt;/A&gt;&lt;BR&gt;For the purposes of this discussion what is important is that we need to store additional information in the AD user class that pertains to Oracle specific attributes.&amp;nbsp; The best practice around extending AD schema suggests creating an auxiliary class to store such information as opposed to modifying directly schema classes provided by Microsoft. The idea here is to create OracleSecurityPrincipal auxiliary class, which contains Oracle specific attributes and then later add this class as an auxiliary class to the User schema class. In this way we encapsulated all of the Oracle related information in a separate class but still have the ability to store these attributes in AD user object. &lt;BR&gt;So I followed this guidance and created an LDIF import file that would create the required structure. &lt;BR&gt;Below you can see an excerpt from that LDIF file.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;dn: CN=codePlex-OraDefaultTableSpace,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;changetype: add&lt;BR&gt;adminDisplayName: codePlex-OraDefaultTableSpace&lt;BR&gt;attributeID: 1.2.840.113556.1.4.7000.159.24.10.66&lt;BR&gt;attributeSyntax: 2.5.5.12&lt;BR&gt;cn: codePlex-OraDefaultTableSpace&lt;BR&gt;description: Specifies Oracle Default TableSpace&lt;BR&gt;isMemberOfPartialAttributeSet: FALSE&lt;BR&gt;isSingleValued: TRUE&lt;BR&gt;lDAPDisplayName: codePlex-OraDefaultTableSpace&lt;BR&gt;distinguishedName: CN=codePlex-OraDefaultTableSpace,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;objectClass: attributeSchema&lt;BR&gt;oMSyntax: 64&lt;BR&gt;name: codePlex-OraDefaultTableSpace&lt;BR&gt;searchFlags: 0&lt;/P&gt;
&lt;P&gt;dn: CN=codePlex-OraProfile,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;changetype: add&lt;BR&gt;adminDisplayName: codePlex-OraProfile&lt;BR&gt;attributeID: 1.2.840.113556.1.4.7000.159.24.10.68&lt;BR&gt;attributeSyntax: 2.5.5.12&lt;BR&gt;cn: codePlex-OraProfile&lt;BR&gt;description: Specifies Oracle Profile Name&lt;BR&gt;isMemberOfPartialAttributeSet: FALSE&lt;BR&gt;isSingleValued: TRUE&lt;BR&gt;lDAPDisplayName: codePlex-OraProfile&lt;BR&gt;distinguishedName: CN=codePlex-OraProfile,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;objectClass: attributeSchema&lt;BR&gt;oMSyntax: 64&lt;BR&gt;name: codePlex-OraProfile&lt;BR&gt;searchFlags: 0&lt;/P&gt;
&lt;P&gt;DN:&lt;BR&gt;changetype: modify&lt;BR&gt;add: schemaUpdateNow&lt;BR&gt;schemaUpdateNow: 1&lt;BR&gt;-&lt;/P&gt;
&lt;P&gt;dn: CN=codePlex-OraSecurityPrincipal,CN=Schema,CN=Configuration,DC=Fabrikam,DC=msft&lt;BR&gt;changetype: add&lt;BR&gt;adminDisplayName: codePlex-OraSecurityPrincipal&lt;BR&gt;description: adds Oracle related attributes to the user class&lt;BR&gt;objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=Fabrikam,DC=msft&lt;BR&gt;objectClass: classSchema&lt;BR&gt;lDAPDisplayName: codePlex-OraSecurityPrincipal&lt;BR&gt;governsID: 1.2.840.113556.1.4.7000.159.24.10.611.11&lt;BR&gt;instanceType: 4&lt;BR&gt;objectClassCategory: 3&lt;BR&gt;subClassOf: top&lt;BR&gt;mustContain: codePlex-OraDefaultTableSpace&lt;BR&gt;mayContain: codePlex-OraProfile&lt;/P&gt;
&lt;P&gt;DN:&lt;BR&gt;changetype: modify&lt;BR&gt;add: schemaUpdateNow&lt;BR&gt;schemaUpdateNow: 1&lt;BR&gt;-&lt;/P&gt;
&lt;P&gt;dn: CN=User,CN=Schema,CN=Configuration,DC=fabrikam,DC=msft&lt;BR&gt;changetype: ntdsSchemaModify&lt;BR&gt;add: auxiliaryClass&lt;BR&gt;auxiliaryClass: codePlex-OraSecurityPrincipal&lt;BR&gt;-&lt;/P&gt;
&lt;P&gt;DN:&lt;BR&gt;changetype: modify&lt;BR&gt;add: schemaUpdateNow&lt;BR&gt;schemaUpdateNow: 1&lt;BR&gt;-&lt;/P&gt;
&lt;P&gt;So let’s quickly walk through this LDIF file. &lt;BR&gt;Firstly, we created several Oracle related attributes (there are many more required attributes, but I removed them to conserve space).&lt;BR&gt;Secondly, an auxiliary schema class is created and the attributes created in step 1 are attached to it via mustContain and mayContain attributes of this class. We will come back to those two attributes shortly.&lt;BR&gt;Thirdly, we add the auxiliary class created in step to 2 to the user schema object.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;When I put together this LDIF file it seemed pretty logical to me, but when I ran this file against my test environment I got the following error message “Unwilling to perform. The server side error is 8505.” This error occurred while trying to add the OracleSecurityPrincipal auxiliary class into User structured class.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;After conducting some research I realized that the issue was around the mandatory attributes defined as part of the auxiliary class via mustContain attribute. During addition of an auxiliary class AD checks if there are any existing objects of the structured class that we are modifying (in our case we are dealing with the User class, and of course any AD deployment would have existing user objects), but since I defined codePlex-oraDefaultTableSpace as a mandatory attribute, this would create an integrity issue within AD where some object that were created previously would be missing some mandatory attributes, and therefore AD refused this change.&lt;BR&gt;So now that we understand the issue at hand, the only way to fix this issue is to make all of the auxiliary class attributes optional, by specifying them as mayContain.&lt;BR&gt;mustContain: codePlex-OraDefaultTableSpace&lt;BR&gt;mayContain: codePlex-OraProfile&lt;BR&gt;Even though from the logic of the OracleSecurityPrincipal class the OraProfile attribute may be considered optional and OraDefaultTableSpace mandatory. &lt;BR&gt;This was not intuitive to me at the beginning, but I suppose this is something that we need to keep in mind when working with auxiliary classes, especially if we plan to add them into the structured classes that already have objects in AD.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2678425" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alextch/archive/tags/AD+Interop/default.aspx">AD Interop</category><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item><item><title>Populating InfoPath 2007 Forms with data from Active Directory</title><link>http://blogs.msdn.com/alextch/archive/2006/11/24/populating-infopath-2007-forms-with-data-from-active-directory.aspx</link><pubDate>Sat, 25 Nov 2006 07:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1145104</guid><dc:creator>alextch</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alextch/comments/1145104.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=1145104</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm" mce_href="http://www.microsoft.com/info/cpyright.htm"&gt;&lt;SPAN style="COLOR: #0033cc"&gt;http://www.microsoft.com/info/cpyright.htm &lt;/SPAN&gt;&lt;/A&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"&gt;This walkthrough&amp;nbsp;shows you how to&amp;nbsp;automatically populate an InfoPath 2007&amp;nbsp;form with information about the current user by utilizing data stored in&amp;nbsp;Active Directory.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Arial','sans-serif'"&gt;Even though not intended as a tutorial on InfoPath 2007 programming, this walkthrough will also introduce you to some basic programming tasks in InfoPath 2007: enumerating through form elements, programmatically setting an element value, etc.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;
&lt;P mce_keep="true"&gt;Please, follow this &lt;A class="" title=screencast href="http://www.alextch.members.winisp.net/AD2InfoPath/AD2InfoPath.wmv" target=_blank mce_href="http://www.alextch.members.winisp.net/AD2InfoPath/AD2InfoPath.wmv"&gt;link&lt;/A&gt; for detailed screencast of the solution.&lt;/P&gt;
&lt;P&gt;Related links:&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://blogs.msdn.com/infopath/archive/2006/06/06/619143.aspx" mce_href="http://blogs.msdn.com/infopath/archive/2006/06/06/619143.aspx"&gt;"Design Once" and the new InfoPath 2007 Object Model&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN class=b&gt;&lt;A class="" href="http://safari.oreilly.com/0321350170" mce_href="http://safari.oreilly.com/0321350170"&gt;The .NET Developer's Guide to Directory Services Programming&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1145104" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/alextch/attachment/1145104.ashx" length="53290" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item><item><title>Script to populate Active Directory with test accounts</title><link>http://blogs.msdn.com/alextch/archive/2006/09/18/AdPopulate.aspx</link><pubDate>Mon, 18 Sep 2006 19:26:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:760983</guid><dc:creator>alextch</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/alextch/comments/760983.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=760983</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm"&gt;&lt;SPAN style="COLOR: #0033cc"&gt;http://www.microsoft.com/info/cpyright.htm &lt;/SPAN&gt;&lt;/A&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Probably like many of you, I quite often need to create test environment for dealing with a range of test scenarios. Invariably, when building a test environment, a question comes up on how to populate Active Directory with test accounts to simulate production environment. Sometimes you may be able to perform restore from production environment or get an export from HR or other systems. But in many cases (for example performance testing, product functionality testing, backup and recovery etc) you don’t really need to have an exact replica of your production environment, so it would be very useful to have a script that could generate a simple but realistic Active Directory environment based on some random names.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Luckily, there is script available on Microsoft scripting repository site that provides us with a starting point &lt;A href="http://www.microsoft.com/technet/scriptcenter/scripts/ad/users/manage/usmgvb03.mspx?mfr=true"&gt;http://www.microsoft.com/technet/scriptcenter/scripts/ad/users/manage/usmgvb03.mspx?mfr=true&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This script will generate an arbitrary number of accounts in a specified OU based on a very simple naming convention (User1, User2, … UserN).&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Despite the fact that this is a good starting point, the script has some limitations:&lt;/P&gt;
&lt;UL style="MARGIN-TOP: 0in" type=disc&gt;
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; tab-stops: list .5in; mso-list: l0 level1 lfo1"&gt;Does not distribute users across OUs 
&lt;LI class=MsoNormal style="MARGIN: 0in 0in 0pt; tab-stops: list .5in; mso-list: l0 level1 lfo1"&gt;The names are not realistic. By the way, why having realistic names is important? Well, if you doing tests on conducting automated user management, sometimes real world names will cause some issues if you don’t catch them in the test. For example, would you process properly handle names with spaces in them, or accented characters?&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Finally, I decided to invest some time and enhance the script to overcome those limitations. The script that I provide here takes as an input 3 Excel Spreadsheets: first names list, last names list, and OUs list. As you may have guessed, the first names list provides a list of sample first names and the last names list provides a list of sample last names. I provide 2 Excel spreadsheets with European names; feel free to modify those to fit your locale. The script creates a name based on selecting random values from the list of first and last names. The samAccountName is generated based on first letter of first name and full last name. Despite using random combination of names, the script quite often may produce identical names which would cause errors while creating AD accounts. In this script I simply ignore those errors and let the script try again.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The third Excel spreadsheet has a list of Active Directory OUs names (fully distinguished names) among which to distribute the users (sample provided below)&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Before running the script, modify this portion of it according to your environment:&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;REM Modify these values according to your environment&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;excelPathFirstNames = "c:\dbpopulate\FirstNamesEurope.xls"&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;excelPathLastNames = "c:\dbpopulate\LastNamesEurope.xls"&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;excelPathOUs = "c:\dbpopulate\ou.xls"&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;upnSuffix = "contoso.com"&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;count = 30000&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Set objRootDSE = GetObject("LDAP://rootDSE")&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;By the way, since the script uses Excel files as an input make sure to have Excel installed on the machine from which you are executing the script.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;That is it; I hope that you may find this script useful.&lt;/P&gt;&lt;o:p&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;The script and accompanying sample files can be found in this blog attachment below.&lt;o:p&gt;&lt;/o:p&gt;&lt;/P&gt;&lt;/o:p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=760983" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/alextch/attachment/760983.ashx" length="18750" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item><item><title>Walkthrough: Creating Active Directory custom data source component in SSIS</title><link>http://blogs.msdn.com/alextch/archive/2006/03/08/ssisad.aspx</link><pubDate>Thu, 09 Mar 2006 04:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:546734</guid><dc:creator>alextch</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alextch/comments/546734.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=546734</wfw:commentRss><description>&lt;P&gt;Walkthrough: Creating Active Directory custom data source component in SSIS&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm"&gt;&lt;FONT color=#0033cc&gt;http://www.microsoft.com/info/cpyright.htm&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This walkthrough serves several purposes:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Provide an end-to-end example of creating a custom data source component for SSIS. Concepts described in this document could be applied&amp;nbsp;to writing custom components for sources other then Active Directory.&lt;/DIV&gt;
&lt;LI&gt;
&lt;DIV class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Create a community driven component for extracting data from Active Directory into relational format. The extracted information could later be used for reporting and data mining.&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;View the walkthrough &lt;A href="http://alextch.members.winisp.net/ADtoSQL/ADSSISSource.html"&gt;here&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Source code provided as an attachment to this blog.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=546734" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/alextch/attachment/546734.ashx" length="96386" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item><item><title>How to convert objectSID value in Active Directory from binary form to string (SDDL representation)</title><link>http://blogs.msdn.com/alextch/archive/2006/03/04/convertObjectSIDtoString.aspx</link><pubDate>Sun, 05 Mar 2006 03:22:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:543786</guid><dc:creator>alextch</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alextch/comments/543786.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alextch/commentrss.aspx?PostID=543786</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;FONT size=4&gt;How to convert objectSID value in Active Directory from binary form to string (SDDL representation)&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at &lt;A href="http://www.microsoft.com/info/cpyright.htm%20"&gt;http://www.microsoft.com/info/cpyright.htm&lt;/A&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Recently I have been working on a project in where I was extracting some data from Active Directory into a SQL table. One of the attributes that I wanted to get from AD was objectSID (this attribute uniquely identifies an object in a domain). ObjectSID is stored in AD as a binary value, but in order for it to be useful in my application I wanted to convert it to string representation, so that I could later conduct searches against it. I searched the web, posted on MSDN ADSI forum but could not really find an elegant solution that would easily accomplish this task.&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;Basically before .NET 2.0 the only way to convert objectSID to a string was by using win32 API called &lt;SPAN style="mso-no-proof: yes"&gt;ConvertSidToStringSid. Here is a link to the pinvoke.net site, which provies examples on&amp;nbsp;how to call this API from your .NET code.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="mso-no-proof: yes"&gt;But of couse, my preference would be to use managed code, as oppoesed going through win32 API, plus I knew that there must have been a more elegant way to perform this task, since this should be probably a very common operaton for folks working with AD. Anyway, I am currenlty reading an excellent book by Stefan Schackow “&lt;A href="http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764596985.html"&gt;Professional ASP.NET 2.0 Security, Membership, and Role Management&lt;/A&gt;”, and in there I stumbled on a piece of code where author was using SecurityIdentifier class in one of his examples. I did some further searching on this class in .NET documentation and was very happy to find out that this class allows us to easly (2 lines of code) convert objectSID from binary to string.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="mso-no-proof: yes"&gt;Here is how to do this:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="mso-no-proof: yes"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;public&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt; &lt;SPAN style="COLOR: blue"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt; SIDtoString(&lt;SPAN style="COLOR: blue"&gt;byte&lt;/SPAN&gt;[] sidBinary)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: teal"&gt;SecurityIdentifier&lt;/SPAN&gt; sid = &lt;SPAN style="COLOR: blue"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: teal"&gt;SecurityIdentifier&lt;/SPAN&gt;(sidBinary, 0);&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return&lt;/SPAN&gt; sid.ToString();&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-no-proof: yes"&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=543786" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alextch/archive/tags/Active+Directory+Programming/default.aspx">Active Directory Programming</category></item></channel></rss>