{"id":67313,"date":"2006-05-16T09:33:00","date_gmt":"2006-05-16T09:33:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2006\/05\/16\/how-can-i-use-a-script-to-create-a-sequential-series-of-user-accounts\/"},"modified":"2006-05-16T09:33:00","modified_gmt":"2006-05-16T09:33:00","slug":"how-can-i-use-a-script-to-create-a-sequential-series-of-user-accounts","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-use-a-script-to-create-a-sequential-series-of-user-accounts\/","title":{"rendered":"How Can I Use a Script to Create a Sequential Series of User Accounts?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"> \n<P>Hey, Scripting Guy! For purposes of testing, I often need to create multiple user accounts like this: pgeorge01, pgeorge02, etc. How can I write a script that automatically creates the next account in the sequence; that is, pgeorge03?<BR><BR>&#8212; RG<\/P><IMG border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\"><\/A> \n<P>Hey, RG. You know, after our last experiment went horribly, horribly wrong, we vowed never to get involved in anything that even <I>smacked<\/I> of human cloning ever again. (In case you\u2019re wondering, creating an army of uncontrollable zombies that rise up and terrorize the countryside does <I>not<\/I> look good on your performance review.) Still, we\u2019re not really cloning <I>people<\/I> here, we\u2019re just kind of cloning user accounts. That seems safe enough. <\/P>\n<P>Besides, you know what they say: you can\u2019t keep a good man (or woman) down.<\/P>\n<P>Turns out, you can\u2019t keep the Scripting Guys down, either.<\/P>\n<P>Although there are several different ways we could approach this task we decided to stick with an old favorite: an Active Directory search. What we\u2019re going to do is search Active Directory for all the user accounts that have a <B>samAccountName<\/B> beginning with the letters <I>kenmyer<\/I>. We\u2019re then going to count the number of users we get back from this search. Why? Well, suppose we get back 3 users. Assuming we\u2019ve stuck to the naming convention (something that our script hinges on) that can only mean that we already have these three user accounts in Active Directory:<\/P>\n<TABLE border=\"0\" cellSpacing=\"0\" cellPadding=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>kenmyer01<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>kenmyer02<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>kenmyer03<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>That also means that all we need to do is increment the record count by 1 and we\u2019ll know which user account to create next: kenmyer04. Again, assuming you stick with the naming convention, everything should work just fine.<\/P>\n<TABLE id=\"EUD\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. What do we mean when we say \u201cstick with the naming convention?\u201d Well, suppose you manually create two users accounts: kenmyer and kenmyer03. Is that a problem? As a matter of fact, it is. When we search Active Directory we\u2019ll discover that there are two accounts that have samAccountNames beginning with the letters <I>kenmyer<\/I>. The script will thus assume that the next account to be created should be kenmyer03. Unfortunately, though kenmyer03 already exists. Admittedly, there are ways that we can handle that problem, but we won\u2019t worry about it today. If there\u2019s enough interest in this, we\u2019ll return to it in a future column.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Let\u2019s take a look at the script:<\/P><PRE class=\"codeSample\">On Error Resume Next<\/p>\n<p>Const ADS_SCOPE_SUBTREE = 2<\/p>\n<p>strName = &#8220;kenmyer&#8221;\nstrSearchName = strName &amp; &#8220;*&#8221;<\/p>\n<p>Set objConnection = CreateObject(&#8220;ADODB.Connection&#8221;)\nSet objCommand =   CreateObject(&#8220;ADODB.Command&#8221;)\nobjConnection.Provider = &#8220;ADsDSOObject&#8221;\nobjConnection.Open &#8220;Active Directory Provider&#8221;\nSet objCommand.ActiveConnection = objConnection<\/p>\n<p>objCommand.Properties(&#8220;Page Size&#8221;) = 1000\nobjCommand.Properties(&#8220;Searchscope&#8221;) = ADS_SCOPE_SUBTREE <\/p>\n<p>objCommand.CommandText = _\n    &#8220;SELECT AdsPath FROM &#8216;LDAP:\/\/dc=fabrikam,dc=com&#8217; WHERE objectCategory=&#8217;user&#8217; &#8221; &amp; _\n        &#8220;AND samAccountName = &#8216;&#8221; &amp; strSearchName &amp; &#8220;&#8216;&#8221;\nSet objRecordSet = objCommand.Execute<\/p>\n<p>intRecordCount = objRecordset.RecordCount\nintRecordCount = intRecordCount + 1<\/p>\n<p>If intRecordCount &lt; 10 Then\n    strNewName = strName &amp; &#8220;0&#8221; &amp; intRecordCount\nElse\n    strNewName = strName &amp; intRecordCount\nEnd If<\/p>\n<p>Set objOU = GetObject(&#8220;LDAP:\/\/OU=Finance,dc=fabrikam,dc=com&#8221;)\nSet objUser = objOU.Create(&#8220;User&#8221;, &#8220;cn= &#8221; &amp; strNewName)\nobjUser.samAccountName = strNewName\nobjUser.SetInfo\nobjUser.SetPassword &#8220;password&#8221;\nobjUser.AccountDisabled = False\nobjUser.SetInfo\n<\/PRE>\n<P>As you can see, we start out by defining a constant named ADS_SCOPE_SUBTREE and setting the value to 2; we\u2019ll use this constant to tell the script to search all of Active Directory. Having said that, that\u2019s pretty much all we <I>will<\/I> say about the code we use to conduct an Active Directory search. If you\u2019re unfamiliar with Active Directory search scripts then you might want to take a look at our two-part <I>Tales from the Script<\/I> feature <A href=\"http:\/\/null\/technet\/scriptcenter\/resources\/tales\/sg0405.mspx\"><B>Dude, Where\u2019s My Printer?<\/B><\/A><\/P>\n<P>After defining the constant we then assign values to a pair of variables:<\/P><PRE class=\"codeSample\">strName = &#8220;kenmyer&#8221;\nstrSearchName = strName &amp; &#8220;*&#8221;\n<\/PRE>\n<P>You can probably figure out what we\u2019re going to do with the variable strName: that variable contains the string of letters (<I>kenmyer<\/I>) we\u2019re searching for. It might not be so obvious, however, why we\u2019re assigning the value <I>kenmyer*<\/I> to the variable strSearchName. Oh, right: considering the fact that we named the variable strSearchName it actually <I>is<\/I> kind of obvious, isn\u2019t it? Well, you\u2019re right: strSearchName is simply the search string we\u2019re going to use; as we noted earlier, we want to get back a collection of all the user accounts where the samAccountName begins with the letters <I>kenmyer<\/I>. To do that we simply specify the letters we want to search for and then tack on an asterisk to use as a wildcard character. <\/P>\n<TABLE id=\"EBF\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. When searching Active Directory the wildcard character simply represents \u201canything,\u201d meaning that, in this script, we\u2019re searching for all samAccountNames that begin with <I>kenmyer<\/I> followed by anything (or even by nothing).<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>After assigning values to our two variables we then encounter a big block of code that actually performs the Active Directory search. Like we said, we won\u2019t discuss that code in any detail today; all we\u2019ll do is point out the query we use for retrieving the user accounts:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT AdsPath FROM &#8216;LDAP:\/\/dc=fabrikam,dc=com&#8217; WHERE objectCategory=&#8217;user&#8217; &#8221; &amp; _\n        &#8220;AND samAccountName = &#8216;&#8221; &amp; strSearchName &amp; &#8220;&#8216;&#8221;\n<\/PRE>\n<P>We\u2019re just searching for all the user accounts (<B>objectCategory = \u2018user\u2019<\/B>) that have a samAccountName equal to the search variable strSearchName. Pretty simple, really.<\/P>\n<P>That brings us to this part of the script:<\/P><PRE class=\"codeSample\">intRecordCount = objRecordset.RecordCount\nintRecordCount = intRecordCount + 1\n<\/PRE>\n<P>In the first line of code we\u2019re setting a variable named intRecordCount to the value of the <B>RecordCount<\/B> property; it probably comes as no surprise that RecordCount simply tells us the number of records in the returned dataset (or, more specifically, the number of users with a samAccountName that begins with <I>kenmyer<\/I>). In the second line of code we then increment the value of intRecordCount by 1. Why? Well, suppose we get back two records. That means the next account we create should be kenmyer03. Because 2 + 1 = 3, we increment the current record count by 1.<\/P>\n<P>And, yes, all those years of high school and college math have resulted in this: we know that 2 + 1 = 3. Time and money well-spent!<\/P>\n<TABLE id=\"EBG\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. What if the record count equals 0? That\u2019s OK: that just means we don\u2019t have any <I>kenmyer*<\/I> accounts at the moment. That also means that when we increment the record count by 1 we\u2019ll get, well, 1; thus the next account we create will be kenmyer01. Which is just as it should be.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>In the next section of code we then create a name for the new account:<\/P><PRE class=\"codeSample\">If intRecordCount &lt; 10 Then\n    strNewName = strName &amp; &#8220;0&#8221; &amp; intRecordCount\nElse\n    strNewName = strName &amp; intRecordCount\nEnd If\n<\/PRE>\n<P>What we do here is first check to see if the record count is less than 10. If it is, we create a user account using these three elements:<\/P>\n<TABLE border=\"0\" cellSpacing=\"0\" cellPadding=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>The user name (<B>kenmyer<\/B>), as stored in the variable strName.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>A <B>0<\/B>.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>The record count.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>Why do we toss the 0 into the middle? That\u2019s easy: that gives us accounts like kenmyer02 and kenmyer03 rather than kenmyer2 and kenmyer3. That maintains consistency, and also makes it easier to view and sort the account names. If the record count is 10 or more we create the user name using only the variable strName and the record count. For example:<\/P>\n<P><B>kenmyer + 11 = kenmyer11<\/B><\/P>\n<P>And now we\u2019re ready to create the account:<\/P><PRE class=\"codeSample\">Set objOU = GetObject(&#8220;LDAP:\/\/OU=Finance,dc=fabrikam,dc=com&#8221;)\nSet objUser = objOU.Create(&#8220;User&#8221;, &#8220;cn= &#8221; &amp; strNewName)\nobjUser.samAccountName = strNewName\nobjUser.SetInfo\nobjUser.SetPassword &#8220;password&#8221;\nobjUser.AccountDisabled = False\nobjUser.SetInfo\n<\/PRE>\n<P>This really isn\u2019t the time or place to discuss the ins and outs of creating user accounts in Active Directory. If the preceding code looks a bit mysterious to you, don\u2019t fret; instead, check out the <A href=\"http:\/\/null\/technet\/scriptcenter\/guide\/sas_usr_doig.mspx\" target=\"_blank\"><B>Active Directory Users<\/B><\/A> chapter in the <I>Microsoft Windows 2000 Scripting Guide<\/I>.<\/P>\n<P>And that\u2019s it: each time we run the script we\u2019ll create a new, properly-incremented kenmyer* account. Turns out that this human cloning thing isn\u2019t that big of a deal after all.<\/P>\n<TABLE id=\"ETH\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P class=\"lastInCell\"><B>Note<\/B>. Nonetheless, we do need to set the record straight on one thing. The army of clones we created didn\u2019t actually go around terrorizing the countryside. Instead, being clones of the Scripting Guys they pretty much lounged around the office all day, surfing the Internet, taking coffee breaks, and then going home early in order to coach baseball. Or at least they <I>said<\/I> they were going to \u201ccoach baseball \u2026.\u201d<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! For purposes of testing, I often need to create multiple user accounts like this: pgeorge01, pgeorge02, etc. How can I write a script that automatically creates the next account in the sequence; that is, pgeorge03?&#8212; RG Hey, RG. You know, after our last experiment went horribly, horribly wrong, we vowed never to [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[7,3,8,20,5],"class_list":["post-67313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-scripting-guy","tag-searching-active-directory","tag-user-accounts","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! For purposes of testing, I often need to create multiple user accounts like this: pgeorge01, pgeorge02, etc. How can I write a script that automatically creates the next account in the sequence; that is, pgeorge03?&#8212; RG Hey, RG. You know, after our last experiment went horribly, horribly wrong, we vowed never to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/67313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=67313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/67313\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=67313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=67313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=67313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}