{"id":63373,"date":"2008-01-02T21:07:00","date_gmt":"2008-01-02T21:07:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2008\/01\/02\/hey-scripting-guy-how-can-i-remove-group-members-whose-user-accounts-reside-in-a-specific-ou\/"},"modified":"2008-01-02T21:07:00","modified_gmt":"2008-01-02T21:07:00","slug":"hey-scripting-guy-how-can-i-remove-group-members-whose-user-accounts-reside-in-a-specific-ou","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-remove-group-members-whose-user-accounts-reside-in-a-specific-ou\/","title":{"rendered":"Hey, Scripting Guy! How Can I Remove Group Members Whose User Accounts Reside in a Specific OU?"},"content":{"rendered":"<h2><img decoding=\"async\" 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\" \/> <\/h2>\n<p>Hey, Scripting Guy! I have a problem and I haven&rsquo;t quite figured out how to solve it. I have an Active Directory group, and I&rsquo;d like to remove some users from that group; in particular, I&rsquo;d like to remove all the users whose user accounts reside in a specified OU. How do I do that?<\/p>\n<p>&#8212; AD<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\" \/><img decoding=\"async\" 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 decoding=\"async\" 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><\/p>\n<p>Hey, AD, and hey to everyone else out there in scripting land. As you can see, the Scripting Guy who writes this column is back from his year-end break <i>(and, you&rsquo;ll be happy to hear, so is the Scripting <\/i><i>Ed<\/i><i>itor)<\/i>, and is ready to crank out the first <i>Hey, Scripting Guy!<\/i> column of 2008. For those of you who keep track of that sort of thing, this marks the fifth calendar year in which a <i>Hey, Scripting Guy!<\/i> column has appeared. <i>Hey, Scripting Guy!<\/i> debuted in August, 2004, which means we&rsquo;ve published columns in 2004, 2005, 2006, 2007, and, now, 2008. As far as we know, that makes this the longest-running daily scripting column in the history of, well, history.<\/p>\n<p>Although, admittedly, there&rsquo;s not a whole lot of competition in the Daily Scripting Colum category.<\/p>\n<p>But hey, that&rsquo;s nothing. For example, here are a few other interesting facts about <i>Hey, Scripting Guy!<\/i><\/p>\n<p>Well, OK; here are a few other <i>facts<\/i> about <i>Hey, Scripting Guy!:<\/i><\/p>\n<ul>\n<li>\n<p>Unofficially, this is the 837<sup>th<\/sup><i>Hey, Scripting Guy!<\/i> column. Will we be holding a special celebration to mark the 1000<sup>th<\/sup><i>Hey, Scripting Guy!<\/i> column? Maybe. Needless to say, though, we actually have to <i>get<\/i> to 1000 first. And the Scripting Editor isn&rsquo;t getting any younger, you know.<\/p>\n<\/li>\n<li>\n<p>Of these 837 columns, 836 were written by the Scripting Guy who writes this column; however, the 837<sup>th<\/sup> was actually written by Scripting Guy Jean Ross. (Interestingly enough, that ratio holds true for pretty much <i>everything<\/i> the Scripting Guys do: Greg does 836 things for every thing that Jean does.) Can you figure out which column Jean wrote? And no, sorry. Although it&rsquo;s technically true, it&rsquo;s not good enough to just say, &ldquo;The one column that&rsquo;s nowhere near as good as the other 836.&rdquo; Instead, you need to be a little more specific. We&rsquo;ll send a Scripting Guys T-Shirt to the first 5 people who can tell us the date of the column that Jean wrote.<\/p>\n<\/li>\n<li>\n<p>The good folks at TechNet were actually opposed to the Scripting Guys writing a daily column; they preferred that we do a monthly column &ldquo;because it&rsquo;s far less work.&rdquo; Some 837 columns later we&rsquo;ve come to a sudden realization: they were right. Turns out that writing a column once a month, as opposed to once a day, really <i>would<\/i> have been far less work. That&rsquo;s the last time we let Dean do the math for us.<\/p>\n<\/li>\n<li>\n<p>If you look at the first couple months of <i>Hey, Scripting Guy!<\/i> you&rsquo;ll notice that the columns aren&rsquo;t quite as &hellip; colorful &hellip; as they are now. (No baseball stories? Say it isn&rsquo;t so!) That&rsquo;s because the good folks at TechNet were convinced that no one wanted to read about Scripting Sons and Scripting Editors. To tell you the truth, they were probably right. But after awhile we started writing about Scripting Sons and Scripting Editors anyway.<\/p>\n<\/li>\n<li>\n<p>About two years ago the Scripting Guy who writes this column was able to hammer out the next column in no time at all: both the script and the column practically wrote themselves. &ldquo;Gee, I&rsquo;m really getting good at this stuff,&rdquo; he thought. The next morning, just before he published the column, he suddenly realized why the article had been so easy to write: he&rsquo;d answered that exact same question, using that exact same script, just a couple of months before. Needless to say, that day&rsquo;s <i>real<\/i> column was published a bit later than usual.<\/p>\n<\/li>\n<\/ul>\n<table id=\"EEF\" class=\"dataTable\" cellspacing=\"0\" cellpadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" valign=\"top\">\n<td>\n<p class=\"lastInCell\"><strong>Note<\/strong>. Have the Scripting Guys implemented some sort of quality control procedures to ensure that a mistake like that never happens again? No, we have not. But don&rsquo;t worry; the Scripting Guys make so many new mistakes each day that the chances of them ever repeating a mistake are quite slim.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Today&rsquo;s column was an easy one to write, too, and not because we&rsquo;d already written it. Why was it so easy? Well, shortly after we received AD&rsquo;s question, AD sent a second email stating that he had solved the problem himself. Because this was a good question, because AD really <i>had<\/i> solved the problem, and because the Scripting Guy who writes this column is having trouble getting back into the swing of things after being off work for nearly three weeks, well, because of all that we decided to go ahead and answer AD&rsquo;s question, using the very same approach AD came up with. Here&rsquo;s how you can delete all the members of a group whose user account resides in a specified OU:<\/p>\n<pre class=\"codeSample\"><pre class=\"codeSample\">Const ADS_PROPERTY_DELETE = 4\n\nSet objGroup = GetObject(\"LDAP:\/\/CN=Finance Users,OU=Finance,DC=fabrikam,DC=com\") \n\nFor Each strUser in objGroup.Member \n    If InStr(strUser,\"OU=Kentucky Office,DC=fabrikam,DC=com\") Then \n        objGroup.PutEx ADS_PROPERTY_DELETE, \"member\", Array(strUser) \n        objGroup.SetInfo \n    End If\nNext<\/pre>\n<table id=\"EVF\" class=\"dataTable\" cellspacing=\"0\" cellpadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" valign=\"top\">\n<td>\n<p class=\"lastInCell\"><span style=\"font-family: verdana,geneva\"><strong>Note to AD<\/strong>.<\/span><span style=\"font-family: verdana,geneva\"> We really appreciate the fact that you sent in a script that answered your own question; it would make our <br \/>lives so much easier if <i>everyone<\/i> did that. Speaking of which, any chance that, next time, you could send in an entire <br \/><i>Hey, Scripting Guy!<\/i> column as well? That would <i>really<\/i> make our lives easier.<\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p><span style=\"font-family: verdana,geneva\">Seeing as how AD wasn&rsquo;t able to send us an entire column (at least not this time), let&rsquo;s see if we can figure out for <br \/>ourselves how the script works. As you can see, we start out by defining a constant named ADS_PROPERTY_DELETE <br \/>and setting the value of this constant to 4; we&rsquo;ll explain why we need this constant in just a moment. After defining the <br \/>constant, we then use this line of code to connect to the group in question; for our purposes, that&rsquo;s a group named Finance <br \/>Users, a group that resides in the Finance OU in the fabrikam.com domain:<\/span><\/p>\n<pre class=\"codeSample\">Set objGroup = GetObject(\"LDAP:\/\/CN=Finance Users,OU=Finance,DC=fabrikam,DC=com\")<\/pre>\n<p><span style=\"font-family: verdana,geneva\">As you probably know, each group object in Active Directory includes an attribute named <strong>Member<\/strong>. To be honest, that&rsquo;s <br \/>not an especially good name; a much better name would have been <i>Members<\/i>, seeing as how this multi-valued <br \/>attribute contains a collection of all the members of the group. Regardless of the name, however, we can cycle through <br \/>the entire group membership simply by setting up a For Each loop that loops through all the values in the Member <br \/>attribute:<\/span><\/p>\n<pre class=\"codeSample\">For Each strUser in objGroup.Member<\/pre>\n<p><span style=\"font-family: verdana,geneva\">What are we going to <i>do<\/i> inside this loop? Well, as you might recall, what we want to do is delete any user whose user <br \/>account resides in a particular OU; in this case, that&rsquo;s the Kentucky Office OU in fabrikam.com. How are we supposed <br \/>to <i>know<\/i> if a user account resides in the Kentucky Office OU? Good question. As it turns out, what&rsquo;s actually stored in <br \/>the Member attribute are the distinguished names of each group member; that means an individual group member <br \/>is listed like this:<\/span><\/p>\n<pre class=\"codeSample\">CN=Ken Myer,OU=Kentucky Office,DC=fabrikam,DC=com<\/pre>\n<p><span style=\"font-family: verdana,geneva\">So how do we know if this user account resides in the Kentucky Office OU? You got it: all we have to do is check to see <br \/>if the string value <i>OU=<\/i><i>Kentucky<\/i><i> Office,DC=fabrikam,DC=com<\/i> can be found anywhere in the user&rsquo;s distinguished <br \/>name.<\/span><\/p>\n<p><span style=\"font-family: verdana,geneva\">And how do we do <i>that<\/i>? Why, by using VBScript&rsquo;s <strong>InStr<\/strong> function, of course:<\/span><\/p>\n<pre class=\"codeSample\">If InStr(strUser,\"OU=Kentucky Office,DC=fabrikam,DC=com\") Then<\/pre>\n<p><span style=\"font-family: verdana,geneva\">If InStr returns False (0), we simply zip back to the top of the loop and repeat the check with the next group member. <br \/>If InStr returns True, however, (or, to be more precise, if InStr returns any value other than 0) then we execute these <br \/>two lines of code:<\/span><\/p>\n<pre class=\"codeSample\"><pre class=\"codeSample\">objGroup.PutEx ADS_PROPERTY_DELETE, \"member\", Array(strUser) \nobjGroup.SetInfo<\/pre>\n<p><span style=\"font-family: verdana,geneva\">Yet another good question: what <i>is<\/i> going on in these two lines of code? Well, in line one we&rsquo;re using the <strong>PutEx<\/strong> method <br \/>to remove the designated user from the group. (That is, a user whose user account resides in the Kentucky <br \/>Office OU.) As you can see, we need to pass PutEx three parameters:<\/span><\/p>\n<ul>\n<li>\n<p><span style=\"font-family: verdana,geneva\"><strong>ADS_PROPERTY_DELETE<\/strong>. <\/span><span style=\"font-family: verdana,geneva\">This, of course, is the constant we defined at the very beginning of the script. It&rsquo;s also the <br \/>constant that tells the PutEx method that we want to delete a value from a specified attribute of the group <br \/>account.<\/span><\/p>\n<\/li>\n<li>\n<p><span style=\"font-family: verdana,geneva\"><strong>\"member\"<\/strong>. <\/span><span style=\"font-family: verdana,geneva\">What&rsquo;s that? <i>Which<\/i> attribute do we want to delete a value from? Needless to say, we want to delete a value <br \/>from the Member attribute. It&rsquo;s no coincidence, then, that the second parameter passed to the PutEx method <br \/>is the name of the attribute we want to work with: <i>&ldquo;member&rdquo;<\/i>.<\/span><\/p>\n<\/li>\n<li>\n<p><span style=\"font-family: verdana,geneva\"><strong>Array(strUser)<\/strong>. <\/span><span style=\"font-family: verdana,geneva\">Last, but surely not least, the third parameter specifies the value to be deleted. (Remember, as a <br \/>multi-valued attribute Member can &ndash; and typically does &ndash; contain many values.) In the case of a group, we remove a <br \/>user from group membership by passing the distinguished name of that user. That&rsquo;s easy to do in this case, <br \/>because group members are already listed by distinguished name. Note, too that we need to pass this value as an <br \/>array, even though we&rsquo;re only passing a single value here. Why? Because the rules state that values passed to PutEx <br \/>must <i>always<\/i> be passed as arrays. And far be it from the Scripting Guys to ever break the rules.<\/span><\/p>\n<\/li>\n<\/ul>\n<p><span style=\"font-family: verdana,geneva\">Finally, in line two, we call the <strong>SetInfo<\/strong> method, which officially removes the specified user from the group membership. <br \/>Don&rsquo;t leave out the SetInfo method. If you leave this out, it will <i>appear<\/i> as though the user&rsquo;s group membership was <br \/>deleted; that&rsquo;s because the change takes place in the local cache, the &ldquo;virtual&rdquo; version of the group account that resides in <br \/>your computer&rsquo;s memory. However, calling PutEx only affects the virtual group account; to affect the actual Active <br \/>Directory account you need to call SetInfo.<\/span><\/p>\n<p><span style=\"font-family: verdana,geneva\">That should do it, AD. (Although, seeing as how you wrote pretty much the exact same script yourself, well, you probably <br \/>already <i>knew<\/i> that that would do it.) As for the rest of you, you can look forward to another full year of <\/span><span style=\"font-family: verdana,geneva\"><i>Hey <br \/>Scripting Guy!<\/i> That means more stories about the Scripting Son, more true facts about the Scripting Editor, and even <br \/>more amazing anecdotes about the Scripting Guy who writes this column. (Coming this week: how he managed to hide <br \/>a Christmas present from <i>himself<\/i>.) <\/span><\/p>\n<p><span style=\"font-family: arial,helvetica,sans-serif\"><span style=\"font-family: verdana,geneva\">And who knows? If we have time this year, maybe we&rsquo;ll throw in a little information about scripting from time-to-time. <br \/>We&rsquo;ll see.<\/span> <\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have a problem and I haven&rsquo;t quite figured out how to solve it. I have an Active Directory group, and I&rsquo;d like to remove some users from that group; in particular, I&rsquo;d like to remove all the users whose user accounts reside in a specified OU. How do I do that? [&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,20,5],"class_list":["post-63373","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-ous","tag-scripting-guy","tag-user-accounts","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have a problem and I haven&rsquo;t quite figured out how to solve it. I have an Active Directory group, and I&rsquo;d like to remove some users from that group; in particular, I&rsquo;d like to remove all the users whose user accounts reside in a specified OU. How do I do that? [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63373","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=63373"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63373\/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=63373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}