{"id":63333,"date":"2008-01-08T21:29:00","date_gmt":"2008-01-08T21:29:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/01\/08\/hey-scripting-guy-how-can-i-modify-the-email-addresses-of-all-the-users-in-an-ou-and-its-subous\/"},"modified":"2008-01-08T21:29:00","modified_gmt":"2008-01-08T21:29:00","slug":"hey-scripting-guy-how-can-i-modify-the-email-addresses-of-all-the-users-in-an-ou-and-its-subous","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-modify-the-email-addresses-of-all-the-users-in-an-ou-and-its-subous\/","title":{"rendered":"Hey, Scripting Guy! How Can I Modify the Email Addresses of All the Users in an OU and Its SubOUs?"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p><img decoding=\"async\" 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\" \/> <\/p>\n<p>Hey, Scripting Guy! I need to get a list of all the users in an OU and its subOUs, then change their email addresses so those addresses only user lowercase letters. How can I do that?<\/p>\n<p>&#8212; TB<\/p>\n<p><img decoding=\"async\" height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\" \/><img decoding=\"async\" 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 decoding=\"async\" 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> <\/p>\n<p>Hey, TB. You know, we had to think twice before going ahead and answering this question. That\u2019s not because this a particularly difficult question for us to answer; it\u2019s not. Nor is that because this is a question that wouldn\u2019t be of much interest to a lot of other people; it is. It\u2019s just that this question involves searching for something (user accounts in Active Directory), and the Scripting Guy who writes this column isn\u2019t particularly \u2026 adept \u2026 at searching for things. In fact, over the holiday season, in an attempt to hide a Christmas present from the Scripting Son, he succeeded only in hiding that present from \u2013 you guessed it \u2013 himself.<\/p>\n<p>The whole thing started shortly before Christmas, when the Scripting Grandpa called to ask what the Scripting Son would like for Christmas. \u201cWell,\u201d said the Scripting Guy who writes this column. \u201cHe\u2019d really like satellite radio for his car.\u201d<\/p>\n<p>\u201cOK,\u201d said the Scripting Grandpa. \u201cWe\u2019ll get him a radio for his car.\u201d<\/p>\n<p>\u201cUm, satellite radio.\u201d<\/p>\n<p>\u201cThat\u2019s what I said: radio. We\u2019ll get him a nice radio for his car.\u201d<\/p>\n<p>\u201cYou know what? Why don\u2019t I just pick that up for you?\u201d<\/p>\n<p>And so the Scripting Guy who writes this column did just that. When he returned home from the store, however, the Scripting Son was there, and unexpectedly so: the Scripting Son had intended to spend the day at a friend\u2019s house, but his friend was sick. The fact that the Scripting Son was home, coupled with the fact that the store used see-through plastic bags, posed a problem: how was the Scripting Guy who writes this column supposed to sneak the present into the house?<\/p>\n<p>Fortunately, the Scripting Guy who writes this column came up with a simple, yet clever, ruse, and managed to get the radio into the house and past the Scripting Son. A few days later, the Scripting Family started off on the long drive to Grandpa and Grandma\u2019s. Although his mother had warned him not to expect too much for Christmas (\u201cRemember, a few days ago you got a <i>really<\/i> nice present for your birthday\u201d) the Scripting Son was undeterred. \u201cI\u2019m not worried,\u201d he said. \u201cGrandpa and Grandma will get me something.\u201d<\/p>\n<p>Grandpa and Grandma will get me something?!?!?! Uh-oh. The Scripting Guy who writes this column suddenly realized that he didn\u2019t pack \u2013 or even wrap \u2013 the satellite radio. In fact, he hadn\u2019t even <i>seen<\/i> the satellite radio. He must have left it at the house.<\/p>\n<p>After a quick U-turn the Scripting Guy who writes this column raced home and ran upstairs to get the satellite radio. Gone! Somehow he had lost the Scripting Son\u2019s Christmas present!<\/p>\n<table class=\"dataTable\" id=\"EMD\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p class=\"lastInCell\"><b>Note to parents<\/b>. Not a good thing to do. Trust us.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Pretty exciting story so far, huh? Heck, we\u2019re on the edge of our seats and we <i>know<\/i> how it ends. Before we reveal that exciting, cliff hanger-type ending, however, let\u2019s take time out to do a little work. More specifically, let\u2019s take time out to show you how to write a script that can modify the email addresses for all the users in an OU and its subOUs:<\/p>\n<pre class=\"codeSample\">On Error Resume Next\n\nConst ADS_SCOPE_SUBTREE = 2\n\nSet objConnection = CreateObject(\"ADODB.Connection\")\nSet objCommand =   CreateObject(\"ADODB.Command\")\nobjConnection.Provider = \"ADsDSOObject\"\nobjConnection.Open \"Active Directory Provider\"\nSet objCommand.ActiveConnection = objConnection\n\nobjCommand.Properties(\"Page Size\") = 1000\nobjCommand.Properties(\"Searchscope\") = ADS_SCOPE_SUBTREE \n\nobjCommand.CommandText = _\n    \"SELECT AdsPath FROM 'LDAP:\/\/OU=Finance,DC=fabrikam,DC=com' WHERE objectCategory='user'\"  \nSet objRecordSet = objCommand.Execute\n\nobjRecordSet.MoveFirst\nDo Until objRecordSet.EOF\n    Set objUser = GetObject(objRecordSet.Fields(\"AdsPath\").Value)\n    strEmailAddress = objUser.Mail\n    strEmailAddress = LCase(strEmailAddress)\n    objUser.Mail = strEmailAddress\n    objUser.SetInfo\n    objRecordSet.MoveNext\nLoop\n<\/pre>\n<p>As usual, we aren\u2019t going to discuss Active Directory search scripts in any detail today; if you need that kind of background information we suggest you take a look at the 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><\/p>\n<table class=\"dataTable\" id=\"EHE\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td class=\"\">\n<p><b>Note<\/b>. <i>Why<\/i> don\u2019t we ever discuss Active Directory search scripts in any detail? Well, the fact that we did a two-part series on the subject should give you a hint: the topic is just too big to cover in a single daily column.<\/p>\n<p>Especially when the daily columnist is as lazy as this one is.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>What we <i>will<\/i> do, however, is take a quick peek at the SQL query we use to retrieve information from Active Directory:<\/p>\n<pre class=\"codeSample\">objCommand.CommandText = _\n    \"SELECT AdsPath FROM 'LDAP:\/\/OU=Finance,DC=fabrikam,DC=com' WHERE objectCategory='user'\"\n<\/pre>\n<p>Two things stand out here. (Three if you count the fact that we added a Where clause that limits the retrieved data to objects that have an <b>objectCategory<\/b> equal to <i>user<\/i>. As you probably figured out for yourself, this ensures that the only objects returned by our query are user account objects.)<\/p>\n<p>To begin with, notice that we start our search in the Finance OU:<\/p>\n<p>SELECT AdsPath FROM <b>&#8216;LDAP:\/\/OU=Finance,DC=fabrikam,DC=com&#8217;<\/b> WHERE objectCategory=&#8217;user<\/p>\n<p>Is that unusual? Yes, it is; typically we start a search in the domain root (DC=fabrikam,DC=com); that\u2019s because, typically, we want to search the entire domain. With this script, however, we only want to search the Finance OU and its subOUs. Consequently, we start the search in the Finance OU rather than the domain root.<\/p>\n<p>What\u2019s that? How does the script know to search the subOUs of the Finance OU as well as the Finance OU itself? Well, at the beginning of the script we defined a constant named AD_SCOPE_SUBTREE and set the value to 2; we then assigned this constant to the <b>Searchscope<\/b> property: <\/p>\n<pre class=\"codeSample\">objCommand.Properties(\"Searchscope\") = ADS_SCOPE_SUBTREE\n<\/pre>\n<p>That tells the script to search not only the Finance OU (that is, not only the target container) but also any subOUs or subcontainers.<\/p>\n<p>Pretty easy, huh?<\/p>\n<p>You might also have noticed that the only attribute we requested back from the search is the <b>ADsPath<\/b> attribute. Why didn\u2019t we ask for the <b>mail<\/b> attribute, especially when you considerthe fact that the whole idea of the script is to modify the value of the mail attribute?<\/p>\n<p>Good question and, for once, at least, we have an equally good answer. Although you can use database techniques to search Active Directory, you can\u2019t use database techniques to update or modify Active Directory; in other words, you can\u2019t write any sort of Update query that modifies the mail attribute. Instead, we have to individually connect to each and every user account and \u201cmanually\u201d modify the value of this attribute. (Don\u2019t worry; that sounds painfully slow, but it\u2019s actually quite fast.) In order to individually bind to each user account all we need is the ADsPath attribute; therefore, that\u2019s all we asked for. (The Scripting Guys aren\u2019t the least bit greedy. At least not when it comes to requesting information from Active Directory.)<\/p>\n<p>After we execute our query we set up a Do Loop to loop through all the records in the resulting recordset. The first thing we do inside this loop? Why, we use this line of code to bind to the user account for the first user in the recordset, of course:<\/p>\n<pre class=\"codeSample\">Set objUser = GetObject(objRecordSet.Fields(\"AdsPath\").Value)\n<\/pre>\n<p>Once we\u2019ve made the connection we then grab the user\u2019s current email address and assign it to a variable named strEmailAddress:<\/p>\n<pre class=\"codeSample\">strEmailAddress = objUser.Mail\n<\/pre>\n<p>And from there we use VBScript\u2019s <b>LCase<\/b> function to convert all the characters in strEmailAddress to their lowercase equivalents:<\/p>\n<pre class=\"codeSample\">strEmailAddress = LCase(strEmailAddress)\n<\/pre>\n<p>The net result? If the email address started out looking like this:<\/p>\n<pre class=\"codeSample\">KenMyer@Fabrkam.COM\n<\/pre>\n<p>It will now look like this, with all the uppercase letters converted to their lowercase equivalents:<\/p>\n<pre class=\"codeSample\">kenmyer@fabrkam.com\n<\/pre>\n<p>Now all we have to do is assign the value of strEmailAddress to the user\u2019s mail attribute. That\u2019s what we do here:<\/p>\n<pre class=\"codeSample\">objUser.Mail = strEmailAddress\nobjUser.SetInfo\n<\/pre>\n<p>As you can see, there\u2019s nothing fancy about these two lines of code: we simply assign strEmailAddress to the Mail attribute, then call the <b>SetInfo<\/b> method to write the change back to Active Directory. Having modified the email address for the first user in the recordset we call the <b>MoveNext<\/b> record and then repeat the process with the next record. By the time we reach the end of the recordset, and the end of the Do loop, we\u2019ll have modified the email addresses of all the users in the Finance OU and its subOUs.<\/p>\n<p>Which is just exactly what we wanted to do.<\/p>\n<p>That should do it, TB. Admittedly, it\u2019s a little different than what you asked for; you originally asked how you could save email information to a spreadsheet, change the letter case in the spreadsheet, then rewrite the modified email addresses back to Active Directory. As you can see, though, this approach is far easier. And, of course, if you still want the email addresses in a spreadsheet, well, it\u2019s easy enough to write a script that retrieves the newly-modified addresses. <\/p>\n<p>Now for the moment you\u2019ve all been waiting for: what <i>did<\/i> happen to the Scripting Son\u2019s satellite radio? As it turns out, the way the Scripting Guy who writes this column managed to sneak the radio into the house was by taking it out of the see-through plastic bag and wrapping it in an old towel that he had in the trunk of the car. He then proceeded to lay the towel in the middle of the room alongside all the other presents that had to be wrapped and taken to Grandpa and Grandma\u2019s. And there the towel sat, even as he dutifully wrapped all the other presents. In fact, the towel continued to sit there even when he returned home, frantically looking for the present; he actually had to step over the towel a couple of times as he looked behind the bookcase and in the closet. It was only after several minutes of desperate searching, and only after he pretty much gave up, that he remembered why there was an old towel lying in the middle of the floor.<\/p>\n<p>And <i>that\u2019s<\/i> why the Scripting Guy who writes this column was a little reluctant to help TB search for something. Fortunately, though, the Scripting Guy who writes this column usually handles himself reasonably well in scripting life. It\u2019s only in real life where he has trouble.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! I need to get a list of all the users in an OU and its subOUs, then change their email addresses so those addresses only user lowercase letters. How can I do that? &#8212; TB Hey, TB. You know, we had to think twice before going ahead and answering this question. [&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,43,3,8,198,5],"class_list":["post-63333","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-ous","tag-scripting-guy","tag-searching-active-directory","tag-users","tag-vbscript"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! I need to get a list of all the users in an OU and its subOUs, then change their email addresses so those addresses only user lowercase letters. How can I do that? &#8212; TB Hey, TB. You know, we had to think twice before going ahead and answering this question. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63333","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=63333"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63333\/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=63333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}