+On Error Resume Next\r
+\r
+Set WshShell = WScript.CreateObject ("WScript.Shell")\r
+Set fso = CreateObject ("Scripting.FileSystemObject")\r
+\r
+groups_file = "\\rtnlprod02\viewstore\PMO\CM_TOOLS\etc\groups.dat"\r
+\r
+' Simple routine to shorten WScript.Echo!\r
+Sub echo (msg)\r
+ WScript.Echo msg\r
+End Sub ' echo\r
+\r
+Sub Email_Owner (sendTo, groupname, members)\r
+ sch = "http://schemas.microsoft.com/cdo/configuration/"\r
+\r
+ Set cdoConfig = CreateObject ("CDO.Configuration")\r
+\r
+ With cdoConfig.Fields\r
+ .Item (sch & "sendusing") = 2 ' cdoSendUsingPort\r
+ .Item (sch & "smtpserver") = "appsmtp.ameriquest.net"\r
+ .Update\r
+ End With\r
+\r
+ Set email_msg = CreateObject ("CDO.Message")\r
+\r
+ email_msg.Configuration = cdoConfig\r
+ email_msg.From = "PMO-CM@Ameriquest.net"\r
+ email_msg.To = sendTo\r
+ email_msg.Subject = "Members of the " & UCase (groupname) & " Group"\r
+ email_msg.HTMLBody = "<h3>Members of the " & UCase (groupname) & " Group</h3><p> </p><ol>"\r
+\r
+ previous_member = ""\r
+ For Each member in members\r
+ If member <> previous_member Then\r
+ email_msg.HTMLBody = email_msg.HTMLBody & "<li>" & member & "</li>"\r
+ previous_member = member\r
+ End If\r
+ Next\r
+\r
+ email_msg.HTMLBody = email_msg.HTMLBody & "</ol>"\r
+ email_msg.Send\r
+End Sub \r
+\r
+' Routine to push things onto an array\r
+Sub pushArray (a, e)\r
+ On Error Resume Next\r
+ size = UBound (a)\r
+\r
+ If Err.Number <> 0 Then\r
+ size = 0\r
+ Else\r
+ size = size + 1\r
+ End If\r
+ \r
+ ReDim preserve a (size)\r
+\r
+ a (UBound (a)) = e\r
+End Sub 'pushArray\r
+\r
+' The famous QuickSort!\r
+Sub QuickSort (vec, loBound, hiBound)\r
+ Dim pivot\r
+ Dim loSwap\r
+ Dim hiSwap\r
+ Dim temp\r
+\r
+ ' This procedure is adapted from the algorithm given in:\r
+ ' Data Abstractions & Structures using C++ by\r
+ ' Mark Headington and David Riley, pg. 586\r
+ ' Quicksort is the fastest array sorting routine for\r
+ ' unordered arrays. Its big O is n log n\r
+\r
+ ' Two items to sort\r
+ If hiBound - loBound = 1 Then\r
+ If vec(loBound) > vec(hiBound) Then\r
+ temp = vec (loBound)\r
+ vec (loBound) = vec (hiBound)\r
+ vec (hiBound) = temp\r
+ End If\r
+ End If\r
+\r
+ ' Three or more items to sort\r
+ pivot = vec (Int ((loBound + hiBound) / 2))\r
+ vec (Int ((loBound + hiBound) / 2)) = vec (loBound)\r
+ vec (loBound) = pivot\r
+ loSwap = loBound + 1\r
+ hiSwap = hiBound\r
+ \r
+ Do\r
+ ' Find the right loSwap\r
+ While loSwap < hiSwap and vec (loSwap) <= pivot\r
+ loSwap = loSwap + 1\r
+ Wend\r
+ \r
+ ' Find the right hiSwap\r
+ While vec (hiSwap) > pivot\r
+ hiSwap = hiSwap - 1\r
+ Wend\r
+ \r
+ ' Swap values if loSwap is less then hiSwap\r
+ If loSwap < hiSwap Then\r
+ temp = vec (loSwap)\r
+ vec (loSwap) = vec (hiSwap)\r
+ vec (hiSwap) = temp\r
+ End If\r
+ Loop While loSwap < hiSwap\r
+ \r
+ vec (loBound) = vec(hiSwap)\r
+ vec (hiSwap) = pivot\r
+ \r
+ ' Recursively call function .. the beauty of Quicksort\r
+ ' 2 or more items in first section\r
+ If loBound < (hiSwap - 1) Then\r
+ QuickSort vec, loBound, hiSwap - 1\r
+ End If\r
+ \r
+ ' 2 or more items in second section\r
+ If hiSwap + 1 < hibound Then\r
+ QuickSort vec, hiSwap+1, hiBound\r
+ End If\r
+End Sub ' QuickSort\r
+\r
+' Get the group members out of Active Directory and push them\r
+' onto the grp_mbrs array\r
+Sub DumpGroup (groupname)\r
+ ' Create an LDAP object and set up the search for groupname\r
+ On Error Resume Next\r
+ Err.Clear\r
+ Set LDAPGroups = GetObject ( _\r
+ "LDAP://cn=" & _\r
+ groupname & _ \r
+ ",ou=apps,ou=Groups,ou=Corp,dc=ameriquest,dc=net" _\r
+ )\r
+ \r
+ If Err.Number <> 0 Then\r
+ Err.Clear\r
+ echo "Warning: " & UCase (groupname) & " is empty!"\r
+ Exit Sub\r
+ End If\r
+\r
+ LDAPGroups.GetInfo\r
+\r
+ ' Get an array of members\r
+ members = LDAPGroups.GetEx ("member")\r
+\r
+ ' For each member get their displayName and push it onto the array\r
+ For Each member in members\r
+ Set user = GetObject ("LDAP://"& member)\r
+ LDAPGroups.filter = array ("user")\r
+ user.GetInfo\r
+\r
+ ' Kludgy way to check to see if this is a group: We attempt\r
+ ' to get groupType which should only be in a group type \r
+ ' record. If this fails then process the member as an\r
+ ' individual member, otherwise recurse to process the\r
+ ' group within the group...\r
+ Err.Clear\r
+ user.Get ("groupType")\r
+\r
+ if Err.Number = 0 Then\r
+ Err.Clear\r
+ groupname = LCase (user.Get ("cn"))\r
+ DumpGroup (groupname)\r
+ Else\r
+ name = user.Get ("displayName")\r
+ pushArray grp_mbrs, name\r
+ End If\r
+ Next\r
+End Sub \r
+\r
+' Open the groups definition file\r
+Set groups = fso.OpenTextFile (groups_file)\r
+\r
+Do While Not groups.AtEndOfStream\r
+ line = groups.ReadLine\r
+\r
+ ' *** Need to also skip blank lines\r
+ If Line <> "" Then\r
+ If InStr (line, "#") <> 1 Then\r
+ With New RegExp\r
+ .Pattern = "\s+"\r
+ .Global = True\r
+ line = Trim (.replace (line, " "))\r
+ End With\r
+\r
+ ' Split out fields\r
+ groupname = ""\r
+ owner = ""\r
+ fields = Split (line)\r
+ groupname = LCase (fields (0))\r
+ owner = LCase (fields (1))\r
+\r
+ echo "Processing group " & UCase (groupname) & " (" & owner & ")"\r
+\r
+ Dim grp_mbrs ()\r
+\r
+ ' Get members of this group\r
+ DumpGroup (groupname)\r
+\r
+ If UBound (grp_mbrs) > 0 Then\r
+ ' Sort them\r
+ QuickSort grp_mbrs, LBound (grp_mbrs), UBound (grp_mbrs)\r
+\r
+ ' Output them\r
+ If owner <> "" Then\r
+ Email_Owner owner, groupname, grp_mbrs\r
+ Else\r
+ echo "Group: " & UCase (groupname) & " has no owner email in " & groups_file\r
+ End If\r
+\r
+ Erase grp_mbrs\r
+ End If\r
+ End If\r
+ End If\r
+Loop\r