{"id":63503,"date":"2007-11-29T00:53:00","date_gmt":"2007-11-29T00:53:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/11\/29\/hey-scripting-guy-how-can-i-determine-the-manager-for-all-the-groups-in-active-directory\/"},"modified":"2007-11-29T00:53:00","modified_gmt":"2007-11-29T00:53:00","slug":"hey-scripting-guy-how-can-i-determine-the-manager-for-all-the-groups-in-active-directory","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-determine-the-manager-for-all-the-groups-in-active-directory\/","title":{"rendered":"Hey, Scripting Guy! How Can I Determine the Manager for All the Groups in Active Directory?"},"content":{"rendered":"<p><H2><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\"> <\/H2>\n<P>Hey, Scripting Guy! How can I return a list of all my Active Directory groups, along with the name of the user responsible for each group?<BR><BR>&#8212; PL<\/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, PL. You know, we realize that most of you are thinking, \u201cWow, this has been a <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/teched07\/eu.mspx\"><B>busy month<\/B><\/A> for you Scripting Guys. You guys really deserve to take some time off.\u201d Well, as much as we\u2019d like to \u2013 what\u2019s that? <I>No one<\/I> was thinking that we deserve to take some time off? No one at all? Mom? Dad? Anyone?<\/P>\n<P>Hmmm \u2026.<\/P>\n<P>Well, that\u2019s just as well, because the Scripting Guys can\u2019t afford to take any time off right now anyway. After all, the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><B>2008 Winter Scripting Games<\/B><\/A> are just around the corner (February 15<SUP>th<\/SUP> through March 3<SUP>rd<\/SUP>), and we have a lot to do in order to get ready for Scripting Games III. (Like, say, come up with some events for people to participate in.) As you might expect, our plan is to make the 2008 Games even bigger \u2013 and even better \u2013 than the 2007 version. To that end, we\u2019ve added a whole new division to the Games; this year you can compete (as either a beginning scripter and\/or an advanced scripter) in Perl as well as VBScript and Windows PowerShell. (That\u2019s right: Perl.) On top of that, we\u2019ll also have some bonus events designed for those show-offs (you know who you are) who somehow manage to complete all the events in a single day. (Sad but true: even though we were the ones who designed the events in the first place even the Scripting Guys can\u2019t complete all the events in a single day.) And if you\u2019re a member of a user group, well, stay tuned; there\u2019s a good chance we\u2019ll have a special little \u201cGames within the Games\u201d for user groups. <\/P>\n<P>What\u2019s that? Prizes? Of <I>course<\/I> there will be prizes. (Assuming we\u2019re able to come up with something, that is.) There will be prizes, and there will be Certificates of Excellence awarded to anyone who receives a score of 60 or better in any one division (e.g., Advanced Perl). Needless to say, it should be a great time for everyone.<\/P>\n<P>Well, except maybe for the two Scripting Guys, who have to test and score all those many entries. But for everyone else, it should be a great time.<\/P>\n<P>Make that it <I>will<\/I> be a great time.<\/P>\n<P>Ah, good question: how <I>are<\/I> you supposed to remember that the Scripting Games begin February 15th? Well, it\u2019s possible that we\u2019ll mention the fact once or twice before then. Alternatively, Microsoft Outlook users can run this script and set a reminder for Thursday, February 14, 2008:<\/P><PRE class=\"codeSample\">Const olAppointmentItem = 1\nSet objOutlook = CreateObject(&#8220;Outlook.Application&#8221;)\nSet objAppointment = objOutlook.CreateItem(olAppointmentItem)\nobjAppointment.Start = #2\/15\/2008 8:00 AM#\nobjAppointment.AllDayEvent = True\nobjAppointment.Subject = &#8220;2008 Winter Scripting Games&#8221;\nobjAppointment.Body = &#8220;The 2008 Winter Scripting Games begin at 8:00 AM Pacific Standard Time. &#8221; &amp; _\n    &#8220;Go to http:\/\/www.microsoft.com\/scriptcenter\/funzone\/games.mspx to begin play. The Games end &#8221; &amp; _\n        &#8220;on Monday, March 3, 2008.&#8221;\nobjAppointment.Location = &#8220;TechNet Script Center&#8221;\nobjAppointment.ReminderMinutesBeforeStart = 1440\nobjAppointment.ReminderSet = True<\/p>\n<p>objAppointment.Save\n<\/PRE>\n<P>And that\u2019s how you return a list of all your Active Directory groups, along with the name of the user responsible for each of those groups. Thank you, and we\u2019ll see you all tomorrow.<\/P>\n<P>Oops; sorry. We got a little ahead of ourselves there, didn\u2019t we? <I>This<\/I> is how you return a list of all your Active Directory groups, along with the name of the user responsible for each of those groups:<\/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;)\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 Name, managedBy FROM &#8216;LDAP:\/\/DC=fabrikam,DC=com&#8217; WHERE objectCategory=&#8217;group'&#8221;<\/p>\n<p>Set objRecordSet = objCommand.Execute<\/p>\n<p>objRecordSet.MoveFirst<\/p>\n<p>Do Until objRecordSet.EOF\n    Wscript.Echo objRecordSet.Fields(&#8220;Name&#8221;).Value \n    Wscript.Echo objRecordSet.Fields(&#8220;managedBy&#8221;).Value\n    Wscript.Echo\n    objRecordSet.MoveNext\nLoop\n<\/PRE>\n<P>That\u2019s a little more like it.<\/P>\n<P>As you can see, this is an Active Directory search script. And because this <I>is<\/I> an Active Directory search script, that can only mean one thing: we aren\u2019t going to discuss the script in much detail today. Why not? Well, for one thing, the Scripting Guys are kind of lazy (and deserving of some time off, even if no one else thinks so). More important, however, is the fact that a detailed discussion of Active Directory search scripts goes way beyond what we can do in a single <I>Hey, Scripting Guy!<\/I> column. But don\u2019t despair; after all, we have a two-part <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/tales\/sg0405.mspx\"><B>Tales from the Script series<\/B><\/A> that tells you everything you need to know about searching Active Directory.<\/P>\n<P>And then some.<\/P>\n<TABLE id=\"E3E\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD>\n<P><B>Note<\/B>. Hey, why the sad face? Oh, you say you\u2019re a Windows PowerShell user, and you think that no one cares whether or not <I>you<\/I> can search Active Directory? Listen, cheer up: the <I>Scripting Guys<\/I> care whether or not you can search Active Directory using Windows PowerShell. In fact, we\u2019ve written <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/topics\/winpsh\/searchad.mspx\"><B>an entire article<\/B><\/A> that explains how to do so. <I>And<\/I> we\u2019ve posted over <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/scripts\/powershell\/search\/default.mspx\"><B>100 sample scripts<\/B><\/A> in the Script Center Script Repository.<\/P>\n<P>And you thought that no one cared. The Scripting Guys <I>always<\/I> care!<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Instead of discussing Active Directory searching in detail, we\u2019ll take just a moment to look at two parts of our script: the SQL query used to retrieve group information, and the Do Until loop used to display that information. Our SQL query looks like this:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT Name, managedBy FROM &#8216;LDAP:\/\/DC=fabrikam,DC=com&#8217; WHERE objectCategory=&#8217;group'&#8221;\n<\/PRE>\n<P>As you can see, we\u2019re searching the entire fabrikam.com domain, asking the script to return the values for two attributes: <B>Name<\/B> and <B>managedBy <\/B>(the attribute that keeps track of the group owner). This query also includes a Where clause that restricts data to all those objects that have an <B>objectCategory<\/B> equal to <I>group<\/I>. What does all that add up to? That adds up to a SQL query that returns the name and owner of all the groups in fabrikam.com.<\/P>\n<P>Which is just exactly what we wanted our SQL query to return.<\/P>\n<P>When we execute this query we get back a recordset containing all the requested information. Once we have that information, we set up a Do Until loop that runs until the recordset\u2019s <B>EOF<\/B> (end-of-file) property is True. Inside that loop, we use these two lines of code to echo back the group name and the group owner:<\/P><PRE class=\"codeSample\">Wscript.Echo objRecordSet.Fields(&#8220;Name&#8221;).Value \nWscript.Echo objRecordSet.Fields(&#8220;managedBy&#8221;).Value\n<\/PRE>\n<P>After that, we use the command <B>Wscript.Echo<\/B> to insert a blank line in our output, then use the <B>MoveNext<\/B> method to move to the next record in the recordset. (Don\u2019t forget to call the MoveNext method. If you <I>do<\/I> forget, then your script will simply echo back the value of the first record in the recordset forever and ever.) When we\u2019re all done, we should have output similar to this:<\/P><PRE class=\"codeSample\">Finance Department Employees\nCN=Ken Myer,OU=Finance,DC=fabrikam,DC=com<\/p>\n<p>Finance Department Managers\nCN=Jonathan Haas,OU=Finance,DC=fabrikam,DC=com<\/p>\n<p>Human Resources Employees\nCN=Pilar Ackerman,OU=HR,DC=fabrikam,DC=com\n<\/PRE>\n<P>And <I>that\u2019s<\/I> how you return a list of all your Active Directory groups, along with the name of the user responsible for each of those groups. Thank you, and we\u2019ll see you all tomorrow.<\/P>\n<P>Oh, right; good point. As you can see, our sample script worked just fine: it returned the name of each group as well as the owner of each group. The only problem is that the managedBy attribute stores group owners by their distinguished name; that means we get back names similar to this:<\/P><PRE class=\"codeSample\">CN=Ken Myer,OU=Finance,DC=fabrikam,DC=com\n<\/PRE>\n<P>That\u2019s OK, but in many cases we\u2019d rather have owner names displayed like this:<\/P><PRE class=\"codeSample\">Ken Myer\n<\/PRE>\n<P>And that\u2019s a problem. That\u2019s a display name, and the managedBy attribute doesn\u2019t store display names. <\/P>\n<P>So does that mean we\u2019re out of luck? Hey, the Scripting Guys have been out of luck for years. (After all, if we were even the least bit lucky we wouldn\u2019t even <I>be<\/I> Scripting Guys in the first place.) Fortunately, though, we don\u2019t need luck to care of this problem; all we need to do is modify our Do Until loop so that it looks like this:<\/P><PRE class=\"codeSample\">Do Until objRecordSet.EOF\n    Wscript.Echo objRecordSet.Fields(&#8220;Name&#8221;).Value \n    strUserDN = objRecordSet.Fields(&#8220;managedBy&#8221;).Value\n    Set objUser = GetObject(&#8220;LDAP:\/\/&#8221; &amp; strUserDN)\n    Wscript.Echo objUser.displayName\n    Wscript.Echo\n    objRecordSet.MoveNext\nLoop\n<\/PRE>\n<P>What\u2019s different with this loop? Well, to begin with, nothing: in the first line we echo back the value of the group\u2019s Name attribute, just like we did in our original script. In line 2, however, things begin to change. This time around we don\u2019t echo the value of the managedBy attribute; instead, we store that value in a variable named strUserDN:<\/P><PRE class=\"codeSample\">strUserDN = objRecordSet.Fields(&#8220;managedBy&#8221;).Value\n<\/PRE>\n<P>What\u2019s the point of that? No point, really; we\u2019re just killing a little time before lunch.<\/P>\n<P>No, hey, just kidding: there\u2019s <I>always<\/I> a point to anything that the Scripting Guys do. (Whether or not there\u2019s a <I>good<\/I> point to anything that the Scripting Guys do is another story.) We\u2019re grabbing the value of the owner\u2019s distinguished name because we can then pass that value to the <B>GetObject<\/B> function and, in turn, bind directly to the owner\u2019s user account in Active Directory:<\/P><PRE class=\"codeSample\">Set objUser = GetObject(&#8220;LDAP:\/\/&#8221; &amp; strUserDN)\n<\/PRE>\n<P>And what\u2019s the point of <I>that<\/I>? Well, once we\u2019re connected to the user account we can echo back any of the attribute values for that account. If we bind to the group account we can only echo back the distinguished name of the group owner; that\u2019s because (via the managedBy attribute) that\u2019s the only name available to us. By binding to the owner\u2019s individual user account we can echo back <I>any<\/I> attribute value for that account, including the <B>displayName<\/B>:<\/P><PRE class=\"codeSample\">Wscript.Echo objUser.displayName\n<\/PRE>\n<P>And why do we want to echo back the value of the displayName attribute? Because then we get output that looks like this:<\/P><PRE class=\"codeSample\">Finance Department Employees\nKen Myer<\/p>\n<p>Finance Department Managers\nJonathan Haas<\/p>\n<p>Human Resources Employees\nPilar Ackerman\n<\/PRE>\n<P>Pretty slick, huh?<\/P>\n<P>And sure, you can easily modify the original script so that it returns the names of all the groups that are managed by a specified user. All you have to do is include the distinguished name of that user in your Where clause, like so:<\/P><PRE class=\"codeSample\">objCommand.CommandText = _\n    &#8220;SELECT Name FROM &#8216;LDAP:\/\/dc=fabrikam,dc=com&#8217; WHERE objectCategory=group&#8217; &#8221; &amp; _\n        &#8220;AND managedBy=&#8217;CN=Ken Myer,OU=Finance,dc=fabrikam,dc=com'&#8221;\n<\/PRE>\n<P>That query returns a list of groups managed by Ken Myer.<\/P>\n<P>That should do it, PL. Remember, the Winter Scripting Games are just a couple months of way (February 15, 2008 through March 3, 2008). Keep checking the <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/default.mspx\"><B>Games home page<\/B><\/A> between now and then; among other things, we\u2019ll be posting weekly tips to help you prepare for the Games. And if you got a perfect score in last year\u2019s Games, be sure to send us information for our <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/bios2007\/index.mspx\"><B>Profiles in Perfection<\/B><\/A> feature; just email a brief bio and a picture (or two) to <A href=\"mailto:scripter@microsoft.com\"><B>scripter@microsoft.com (in English, if possible)<\/B><\/A>. <\/P>\n<P>Oh, and keep this in mind: Tiger Woods did <I>not<\/I> enter the 2007 Scripting Games, and look what happened to him. Let that be a lesson to you all.<\/P>\n<P>What\u2019s that? He earned <I>how<\/I> much money?!? Wow; that <I>is<\/I> a lot of money, isn\u2019t it? Well, enter the Scripting Games anyway; money isn\u2019t <I>everything<\/I> you know. <\/P>\n<P>Besides, we bet Tiger Woods doesn\u2019t have a <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/bobbles.mspx\"><B>Dr. Scripto Bobblehead doll<\/B><\/A>. And we wouldn\u2019t sell him one, either, not at any price. Great Scripting Games prizes like Dr. Scripto bobblehead dolls can\u2019t be bought; they have to be <I>earned<\/I>.<\/P>\n<TABLE id=\"EFCAC\" 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 to Tiger Woods<\/B>. Don\u2019t worry about those last few sentences; that was all legal mumbo-jumbo that the Scripting Editor makes us put in. Feel free to contact the Scripting Guy who writes this column at any time and make him an offer. He\u2019ll see what he can do for you.<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I return a list of all my Active Directory groups, along with the name of the user responsible for each group?&#8212; PL Hey, PL. You know, we realize that most of you are thinking, \u201cWow, this has been a busy month for you Scripting Guys. You guys really deserve 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,44,3,5],"class_list":["post-63503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-groups","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I return a list of all my Active Directory groups, along with the name of the user responsible for each group?&#8212; PL Hey, PL. You know, we realize that most of you are thinking, \u201cWow, this has been a busy month for you Scripting Guys. You guys really deserve to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63503","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=63503"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/63503\/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=63503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=63503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=63503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}