{"id":55923,"date":"2008-03-26T00:25:00","date_gmt":"2008-03-26T00:25:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/03\/26\/hey-scripting-guy-how-can-i-standardize-the-logon-name-for-all-my-users\/"},"modified":"2008-03-26T00:25:00","modified_gmt":"2008-03-26T00:25:00","slug":"hey-scripting-guy-how-can-i-standardize-the-logon-name-for-all-my-users","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-standardize-the-logon-name-for-all-my-users\/","title":{"rendered":"Hey, Scripting Guy! How Can I Standardize the Logon Name for All My Users?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! My company would like me to change our Active Directory logon names from this format \u2013 <B>kmyer<\/B> \u2013 to this format: <B>Ken.Myer<\/B>. Is there a way I can script all these changes?<BR><BR>&#8212; DO<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, DO. You know, sometimes the Scripting Guy who writes this column implies that he leads a dull and drab life, that nothing exciting ever happens to him. Well, to be honest, that\u2019s a bit of an exaggeration; as it turns out, exciting things happen to him all the time.<\/P>\n<P><I>All<\/I> the time.<\/P>\n<P>For example, a new <A href=\"http:\/\/www.jambajuice.com\/\" target=\"_blank\"><B>Jamba Juice<\/B><\/A> smoothie bar recently opened up inside his local grocery store. Admittedly, the Scripting Guy who writes this column didn\u2019t find that to be all <I>that<\/I> exciting; although he has nothing against smoothies he doesn\u2019t feel an overwhelming need to drink a smoothie while grocery shopping. (Nope, not even a Mango Mantra or a Strawberry Nirvana, hard as that is to believe.)<\/P>\n<P>What he <I>did<\/I> find exciting \u2013 or at least mildly-interesting, which is about all the excitement the Scripting Guy who writes this column can ever really hope for these days \u2013 is the reaction of his fellow shoppers: the line at the Jamba Juice now rivals \u2013 and oft-times even exceeds \u2013 the line at the Starbucks counter (which is also located inside the store). And that\u2019s not because the people have stopped in to buy a smoothie or a latte to take home with them; instead, they\u2019re drinking these beverages while they shop. In fact, all the shopping carts at the store were recently retrofitted with cupholders. <\/P>\n<P>No, wait: make that <I>dual<\/I> cupholders, which is fortunate: the Scripting Guy who writes this column has seen at least one solo shopper who had a latte in one cupholder and a Jamba Juice in the other. <\/P>\n<P>Now, there\u2019s nothing wrong with that \u2026 we think. It just seems funny that you would need a latte <I>and<\/I> a Jamba Juice just to get through your grocery shopping. The Scripting Guy who writes this column doesn\u2019t quite get it.<\/P>\n<TABLE class=\"dataTable\" id=\"E6D\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. Based on the current price of groceries, however, the Scripting Guy who writes this column <I>would<\/I> understand it if you needed, say, a fifth of vodka in order to get through your grocery shopping.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Admittedly, there are several aisles in the grocery store that the Scripting Guy who writes this column never goes down. (The seafood aisle, to name one.) As near as he can tell, however, the one thing that you <I>can\u2019t<\/I> get at the grocery store these days are scripts that enable you to change the sAMAccountName for all the users in a domain. <\/P>\n<P>But that\u2019s OK; after all, that\u2019s what the Scripting Guys are here for: <\/P><PRE class=\"codeSample\">On Error Resume Next<\/p>\n<p>Const ADS_SCOPE_SUBTREE = 2<\/p>\n<p>Set objConnection = CreateObject(&#8220;ADODB.Connection&#8221;)\nSet objCommand =   CreateObject(&#8220;ADODB.Command&#8221;)<\/p>\n<p>objConnection.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 objectClass=&#8217;user'&#8221;  <\/p>\n<p>Set objRecordSet = objCommand.Execute<\/p>\n<p>objRecordSet.MoveFirst<\/p>\n<p>Do Until objRecordSet.EOF\n    Set objUser = GetObject(objRecordSet.Fields(&#8220;ADsPath&#8221;).Value)\n    strOldName = objUser.sAMAccountName\n    strNewName = objUser.givenName &amp; &#8220;.&#8221; &amp; objUser.sn\n    objUser.sAMAccountName = strNewName\n    objUser.SetInfo\n    Wscript.Echo strOldName &amp; vbTab &amp; strNewName\n    objRecordSet.MoveNext\nLoop\n<\/PRE>\n<P>Before we explain how this script works we need to note that, in real life, this task might be a tad bit more complicated than our solution suggests. For one thing, we\u2019re assuming that you\u2019ve already assigned first names (the <B>givenName<\/B> attribute) and last name (the <B>sn<\/B> attribute) to all your users. If you haven\u2019t, you\u2019re going to immediately run into problems when you try to create a new logon name (<B>sAMAccountName<\/B>) that combines a non-existent first name and a non-existent last name. One way to work around that issue is to retrieve your user accounts using the following query:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT AdsPath FROM &#8216;LDAP:\/\/dc=wingroup,dc=windeploy,dc=ntdev,dc=microsoft,dc=com&#8217; &#8221; &amp; _\n        &#8220;WHERE objectClass=&#8217;user&#8217; AND givenName = &#8216;*&#8217; AND sn = &#8216;*'&#8221;\n<\/PRE>\n<P>This query returns only those user accounts (<B>objectClass = &#8216;user&#8217;<\/B>) where the user has both a first name (<B>givenName = &#8216;*&#8217;<\/B>) <I>and<\/I> a last name (<B>sn = &#8216;*&#8217;<\/B>). Alternatively, you could use this query to retrieve a collection of all those users who are missing either a first name or a last name:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT AdsPath FROM &#8216;LDAP:\/\/dc=wingroup,dc=windeploy,dc=ntdev,dc=microsoft,dc=com&#8217; WHERE &#8221; &amp; _\n        objectClass=&#8217;user&#8217; AND (givenName &lt;&gt; &#8216;*&#8217; OR sn &lt;&gt; &#8216;*&#8217;)&#8221;\n<\/PRE>\n<P>That\u2019s entirely up to you. For this script we\u2019re assuming your user accounts have already been assigned first and last names.<\/P>\n<P>Wait, wait; we\u2019re not done yet. We also didn\u2019t address the possibility of there being two users with identical first and last names; for example, two different people named Ken Myer. That\u2019s a problem, because the script will try to assign both of those users the same logon name: Ken.Myer. That\u2019s a no-no: logon names must be unique within the domain. So how can you work around <I>this<\/I> problem? Well, one thing you could do is construct a proposed sAMAccountName and then \u2013 before assigning that name to a user \u2013 do a quick check of Active Directory to see if that name is already in use. If it\u2019s not, then you\u2019re home free; if it is, then you\u2019ll have to do something to the name (e.g., tack a 1 on the end) to make it unique. That\u2019s a bit more than we have time to go over today, but if anyone out there would like to know how to do this then drop us a line and we\u2019ll take it up in a future column.<\/P>\n<P>Assuming, of course, that the grocery store doesn\u2019t beat us to it.<\/P>\n<P>For <I>today\u2019s<\/I> column we\u2019re going to assume that there are no problems. (Which is par for the course for those of us who work at Microsoft; we never have <I>any<\/I> problems here.) We\u2019re also going to do what we always do, which is this: skip over the explanation of how you do an Active Directory search. Why do we skip that explanation? That\u2019s easy: that information is covered in great detail in our two-part <I>Tales From the Script<\/I> series <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/tales\/sg0405.mspx\"><B>Dude, Where\u2019s My Printer?<\/B><\/A> About all we <I>will<\/I> do is take a quick peek at the query that returns a collection of all the user accounts in the fabrikam.com domain:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT ADsPath FROM &#8216;LDAP:\/\/dc=fabrikam,dc=com&#8217; WHERE objectClass=&#8217;user'&#8221;\n<\/PRE>\n<P>As you can see, there\u2019s nothing fancy here at all: we\u2019re just requesting a collection of all the Active Directory objects that have an objectClass equal to <I>user<\/I>. You might note as well that we\u2019re asking the script to return only a single attribute value: <B>ADsPath<\/B>, the property that enables us to locate a particular object in Active Directory. That might seem a little strange; after all, if we\u2019re working with the sAMAccountName, givenName, and sn attributes shouldn\u2019t we ask to get back <I>those<\/I> property values as well?<\/P>\n<P>Well, you\u2019d think so, wouldn\u2019t you? As it turns out, however, Active Directory searches are read-only; you can\u2019t make any changes or updates to an object by using a query. (Bad news for those of you accustomed to using SQL commands like UPDATE.) Instead, any time you want to modify an object in Active Directory you need to bind directly to that object. The search portion of our script makes it easy to retrieve the locations of all our user account objects, but that\u2019s all it can do for us; we still have to bind to the actual user account in order to change the sAMAccountName. We didn\u2019t bother retrieving the sAMAccountName, givenName, and sn attributes for one simple reason: at the moment, there\u2019s nothing we can do with those attributes anyway.<\/P>\n<P>But don\u2019t worry; that will change in just a second.<\/P>\n<P>After we define our query we use the following line of code (and the <B>Execute<\/B> method) to retrieve a recordset consisting of all the user accounts in the fabrikam.com domain:<\/P><PRE class=\"codeSample\">Set objRecordSet = objCommand.Execute\n<\/PRE>\n<P>From there we call the <B>MoveFirst<\/B> method to move to the first record in the recordset, then set up a Do Until loop designed to run until we\u2019ve looped through each and every one of those records; that is, until the recordset\u2019s <B>EOF<\/B> (end-of-file) property is True:<\/P><PRE class=\"codeSample\">Do Until objRecordSet.EOF\n<\/PRE>\n<P>What are we going to do inside that recordset? You know what? This explanation has already drug on for several minutes; why don\u2019t you all run out and get a latte or a Strawberry Surf Rider and then we\u2019ll continue on after that?<\/P>\n<P>And yes, we apologize that this column does not come with built-in cupholders; we\u2019re working on that right now.<\/P>\n<P>OK, so what <I>are<\/I> we going to do inside that recordset? The first thing we\u2019re going to do is take the <B>Value<\/B> of the ADsPath attribute for the first record and use that to bind to the actual user account in Active Directory:<\/P><PRE class=\"codeSample\">Set objUser = GetObject(objRecordSet.Fields(&#8220;ADsPath&#8221;).Value)\n<\/PRE>\n<P>As soon as we make the connection we grab the user\u2019s existing sAMAccountName and store it in a variable named strOldName:<\/P><PRE class=\"codeSample\">strOldName = objUser.sAMAccountName\n<\/PRE>\n<P>We then use this line of code to construct a new sAMAccountName for the user:<\/P><PRE class=\"codeSample\">strNewName = objUser.givenName &amp; &#8220;.&#8221; &amp; objUser.sn\n<\/PRE>\n<P>Again, there\u2019s nothing fancy going on here at all: we\u2019re simply grabbing the user\u2019s first name (givenName), appending a period, then appending the user\u2019s last name (sn). The net result? A user with a first name of Ken and a last name of Myer gets a new sAMAccountName that looks like this:<\/P><PRE class=\"codeSample\">Ken.Myer\n<\/PRE>\n<P>Which, by a nifty piece of luck, is exactly the sAMAccountName we <I>want<\/I> Ken Myer to have.<\/P>\n<P>All we have to do now is assign the new value to Ken\u2019s sAMAccountName, then call the <B>SetInfo<\/B> method to write those changes to Active Directory:<\/P><PRE class=\"codeSample\">objUser.sAMAccountName = strNewName\nobjUser.SetInfo\n<\/PRE>\n<P>But, of course, we couldn\u2019t just leave it at that. Instead, just for the heck of it, we echo back Ken\u2019s old sAMAccountName and his new sAMAccountName:<\/P><PRE class=\"codeSample\">Wscript.Echo strOldName &amp; vbTab &amp; strNewName\n<\/PRE>\n<P>That gives you a report similar to this, a report that helps you keep track of all the changes that were made:<\/P><PRE class=\"codeSample\">Kmyer    Ken.Myer\npackerman    Pilar.Ackerman\njhaas    Jonathan.Haas\n<\/PRE>\n<P>At that point we call the <B>MoveNext<\/B> method to move to the next record in the recordset, then zip back to the top of the loop and repeat the process for user No. 2. And that, believe it or not, is all we have to do.<\/P>\n<P>In case you\u2019re wondering, the Scripting Guy who writes this column can now do each of the following at his local grocery store:<\/P>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Buy a Jamba Juice.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Buy a latte.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Buy take-home Chinese food or Panini sandwiches.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Buy gas.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Rent a movie.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Take out a home loan or car loan.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P>Send a bouquet of roses.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>As you can see, about the only thing missing from that list is \u201cbuy groceries.\u201d But, then again, a grocery store can\u2019t be expected to do <I>everything<\/I>.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! My company would like me to change our Active Directory logon names from this format \u2013 kmyer \u2013 to this format: Ken.Myer. Is there a way I can script all these changes?&#8212; DO Hey, DO. You know, sometimes the Scripting Guy who writes this column implies that he leads a dull and [&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,198],"class_list":["post-55923","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-scripting-guy","tag-users"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! My company would like me to change our Active Directory logon names from this format \u2013 kmyer \u2013 to this format: Ken.Myer. Is there a way I can script all these changes?&#8212; DO Hey, DO. You know, sometimes the Scripting Guy who writes this column implies that he leads a dull and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55923","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=55923"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/55923\/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=55923"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=55923"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=55923"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}