{"id":85951,"date":"2004-09-30T06:13:14","date_gmt":"2004-09-30T14:13:14","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/scripting\/?p=85951"},"modified":"2019-06-05T06:19:29","modified_gmt":"2019-06-05T14:19:29","slug":"how-can-i-compare-the-memberships-of-two-groups","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-compare-the-memberships-of-two-groups\/","title":{"rendered":"How Can I Compare the Memberships of Two Groups?"},"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! I\u2019m looking for a script that can get the memberships of two different groups, compare them, and then write out the differences. Can you help?<BR><BR>&#8212; LS<\/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, LS. When we received your question a week or so ago we thought, \u201cThat\u2019s a good question. Let\u2019s put it on the list and answer it sometime.\u201d Since then we\u2019ve had 3 or 4 more people ask the same question. Well, there\u2019s one thing about us Microsoft Scripting Guys: you might have to ask us 5 or 6 times, but by the 7<SUP>th<\/SUP> time we finally get the hint. Here\u2019s how you can do this.<\/P>\n<P>Because a couple of people specifically mentioned being able to compare the local Administrators group on two different computers that\u2019s the example we\u2019re going to use. But, needless to say, you can compare <I>any<\/I> two groups using this same technique. Want to compare two groups on the same computer? No problem. Want to compare two Active Directory groups? No problem. How about a local group and an Active Directory group? That\u2019s right: no problem.<\/P>\n<P>To begin with, we need some code that can grab the list of members of our two local groups and then stash that information somewhere so that we can then compare the two lists. Getting the membership is easy; here\u2019s a script that retrieves the members of the Administrators group on the computer atl-ws-01:<\/P><PRE class=codeSample>strComputer = &#8220;atl-ws-01&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n     Wscript.Echo objUser.Name   \nNext\n<\/PRE>\n<P>Of course, the preceding script echoes the user names to the screen. We don\u2019t really want to that; instead, we want to hang on to those user names so that we can then compare them with the names we get from the second computer. Fortunately, there\u2019s an easy way to do this: we just stuff the names into a Dictionary object:<\/P><PRE class=codeSample>Set objGroup1 = CreateObject(&#8220;Scripting.Dictionary&#8221;)<\/p>\n<p>strComputer = &#8220;atl-ws-01&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n    objGroup1.Add objUser.Name, objUser.Name   \nNext\n<\/PRE>\n<P>If you aren\u2019t familiar with the Dictionary object, you might want to check out this section of the <A href=\"http:\/\/null\/technet\/scriptcenter\/guide\/sas_scr_ildk.mspx\" target=_blank><B>Microsoft Windows 2000 Scripting Guide<\/B><\/A>. For now, consider the Dictionary object a collection of key\/value pairs; typically you store things like states and their state capitals in a Dictionary object:<\/P><PRE class=codeSample>Washingon\/Olympia\nOregon\/Salem\nIdaho\/Boise\n<\/PRE>\n<P>In this example, Idaho is a key and Boise is its corresponding value. Oregon is a key, and Salem is its corresponding value.<\/P>\n<P>The whole idea here is that you can ask a question like, \u201cWhat is the capital of Washington?\u201d and the script can check the key\/value pair and respond, \u201cOlympia.\u201d It does this by searching for the key &#8211; Washington &#8211; and then reporting back the value: Olympia. Of course, in our case, we\u2019re really only interested in the keys; we want to be able to ask a question like, \u201cIs Bob a member of Group 1?\u201d However, since the Dictionary object requires both a key and a value, we end up putting the same information (the user name) in each. Thus we end up with a list like this:<\/P><PRE class=codeSample>Bob\/Bob\nJill\/Jill\nJoe\/Joe\nSusan\/Susan\n<\/PRE>\n<P>But don\u2019t worry about the values. The important thing is that the collection of keys looks like this:<\/P><PRE class=codeSample>Bob\nJill\nJoe\nSusan\n<\/PRE>\n<P>If we repeat this process for Computer 2 (using a second Dictionary object to hold the membership of that group), we\u2019ll have a script that looks similar to this:<\/P><PRE class=codeSample>Set objGroup1 = CreateObject(&#8220;Scripting.Dictionary&#8221;)\nSet objGroup2 = CreateObject(&#8220;Scripting.Dictionary&#8221;)<\/p>\n<p>strComputer = &#8220;atl-ws-01&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n    objGroup1.Add objUser.Name,objUser.Name   \nNext<\/p>\n<p>strComputer = &#8220;atl-ws-02&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n    objGroup2.Add objUser.Name,objUser.Name   \nNext\n<\/PRE>\n<P>No, sorry, we aren\u2019t done yet. But we\u2019re getting close. We now have the two membership lists, and all we have to do is compare them and write out any differences. How do we do that? As it turns out, you can use a For Each loop to cycle through all the keys in a Dictionary object. For example, if you want to echo all the key names you can use code like this:<\/P><PRE class=codeSample>colKeys = objGroup1.Keys\nFor Each strUser in colKeys\n    Wscript.Echo strUser\nNext\n<\/PRE>\n<P>Of course, we don\u2019t want to echo the membership list, we want to find out who is in Group 1 and then check to see if they are also in Group 2. To do that, we use the For Each loop to get the first user in Group 1 &#8211; Bob &#8211; and we then use the Dictionary object\u2019s Exists method to see if Bob is also in Group 2. If he is, that\u2019s fine; if he\u2019s not, we then echo a message that says \u201cBob is not in Group 2.\u201d We know, that sounds complicated, but it only takes a few lines of code:<\/P><PRE class=codeSample>colKeys = objGroup1.Keys\nFor Each strUser in colKeys\n    If Not objGroup2.Exists(strUser) Then\n        Wscript.Echo strUser &amp; &#8221; is not in Group 2.&#8221;\n    End If\nNext\n<\/PRE>\n<P>We then repeat the process with Group 2, checking to see if all the users in that group are members of Group 1. When that part of the script ends, we\u2019ll have a list of the differences between the two groups.<\/P>\n<P>Here\u2019s the completed script. Again, it might look a little weird, but that\u2019s simply because people don\u2019t use the Dictionary object very often. It\u2019s actually very simple, though, and even &#8211; heaven forbid! &#8211; has some logic to it:<\/P><PRE class=codeSample>Set objGroup1 = CreateObject(&#8220;Scripting.Dictionary&#8221;)\nSet objGroup2 = CreateObject(&#8220;Scripting.Dictionary&#8221;)<\/p>\n<p>strComputer = &#8220;atl-ws-01&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n    objGroup1.Add objUser.Name,objUser.Name   \nNext<\/p>\n<p>strComputer = &#8220;atl-ws-02&#8221;\nSet objGroup = GetObject(&#8220;WinNT:\/\/&#8221; &amp; strComputer &amp; &#8220;\/Administrators&#8221;)\nFor Each objUser in objGroup.Members\n    objGroup2.Add objUser.Name,objUser.Name   \nNext<\/p>\n<p>colKeys = objGroup1.Keys\nFor Each strUser in colKeys\n    If Not objGroup2.Exists(strUser) Then\n        Wscript.Echo strUser &amp; &#8221; is not in Group 2.&#8221;\n    End If\nNext<\/p>\n<p>colKeys = objGroup2.Keys\nFor Each strUser in colKeys\n    If Not objGroup1.Exists(strUser) Then\n        Wscript.Echo strUser &amp; &#8221; is not in Group 1.&#8221;\n    End If\nNext<\/PRE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I\u2019m looking for a script that can get the memberships of two different groups, compare them, and then write out the differences. Can you help?&#8212; LS Hey, LS. When we received your question a week or so ago we thought, \u201cThat\u2019s a good question. Let\u2019s put it on the list and answer [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-85951","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I\u2019m looking for a script that can get the memberships of two different groups, compare them, and then write out the differences. Can you help?&#8212; LS Hey, LS. When we received your question a week or so ago we thought, \u201cThat\u2019s a good question. Let\u2019s put it on the list and answer [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/85951","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\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=85951"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/85951\/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=85951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=85951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=85951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}