HTA / VBScript That Pulls Group Membership in AD

Hi Experts!

     I'm curious if one of you guys has a HTA (preferrably) that allows you to enter in the name of a  group and then the HTA queries AD and pulls the group membership of that group and gives the option to save/export as either a .txt or .csv file?

     I have an some example HTA code attached which is really quite amazing.   It basically scans the entire AD tree's parent OU's and sub OU's and enumerates each OU and then determines what permissions that OU and it's sub OU's have.  It also allows me to filter out readings that I do not want to see.  Is there anyway we could add to the below code what I'm requested above?  Or if you have a completely separate HTA that does this that's fine too.  

     Your help is GREATLY APPRECIATED!!!

     
<html>
<hta:application
	  ID="objOUPermissions" 
	  APPLICATIONNAME="OUPermissions"
	  SCROLL="yes"
	  SINGLEINSTANCE="yes"
	  WINDOWSTATE="normal"
>

<head>

<script language="vbscript">

Dim html
Dim strTitle
Dim arrExcludeList
Dim strExcludeList
Dim intAceCount

strExcludeList="System Admin,Domain Admins,Scheme Admins,Account Operators,Print Operators,Enterprise Domain Controllers,Password Manager,System"
arrExcludeList=split(strExcludeList,",")

strTitle="AD OU Permissions"

Sub Window_OnLoad
	document.title=strTitle
	CommentArea.innerHTML="<b>Excluded from listing:</b><br>" & strExcludeList & "<hr>"
	Get_OU_List
End Sub


Sub Get_OU_List
	

	Const ADS_SCOPE_SUBTREE = 2
	
	Set objRootDSE = GetObject("LDAP://rootDSE")
	strADsPath = "LDAP://" & objRootDSE.Get("defaultNamingContext")
	
	Set objConnection = CreateObject("ADODB.Connection")
	Set objCommand = CreateObject("ADODB.Command")
	objConnection.Provider = "ADsDSOObject"
	objConnection.Open "Active Directory Provider"
	Set objCommand.ActiveConnection = objConnection
	
	objCommand.Properties("Page Size") = 4000
	objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
	
	
	objCommand.CommandText = _
		"SELECT Name,ADsPath FROM '" & strADsPath & "' WHERE objectCategory='OrganizationalUnit'"
	
	Set objRecordSet = objCommand.Execute
	
	objRecordSet.MoveFirst
	While NOT objRecordSet.EOF
		strADsPathOU = objRecordSet.Fields("ADsPath").Value
		
		Set objNewOption = document.createElement("OPTION")
		posStart=instr(strADsPathOU,"//")+2
		posEnd=instr(ucase(strADsPathOU),",DC=")
		strName=mid(strADsPathOU,posStart,posEnd-posStart)
		
		objNewOption.Text = strName
		objNewOption.Value= strADsPathOU
		select1.options.Add(objNewOption)
		
		objRecordSet.MoveNext
	Wend
	

End Sub




Sub AddHtml(myLine)
	html=html &  myLine 
End Sub



Sub GetPermissions
	html=""
	
	For Each objOption In select1.Options
		If objOption.Selected = True Then
			myOU=objOption.text
			myADsPath=objOption.Value
		End If
	Next
	
	If myAdsPath="" then Exit Sub
	
	
	GetSecurityDescriptor myADsPath

	If html <> "" then AddButtons
	
	DataArea.innerHTML=html
	
End Sub

Sub AddButtons
	html = "<button id=""b1"" onmouseover=Highlight('b1') onmouseout=Highlight('b1') onclick=Collapse('ShowMe')>Expand All</button>" & _
		"<button id=""b2"" onmouseover=Highlight('b2') onmouseout=Highlight('b2') onclick=Collapse('HideMe')>Collapse All</button><br><br>" & html
End Sub

Sub Collapse(myClass)
	
	for i = 1 to intAceCount
		Set myElement = document.getElementById("divEntryData" & i)
		myElement.className=myClass
	next
End Sub

Sub Highlight(elem)
	Set myElement = document.getElementById(elem)
	If myElement.className="darkborder" then
		myElement.className="lightborder"
	Else
		myElement.className="darkborder"
	End If
End Sub

Sub ClearOUs
	For Each objOption In select1.Options
		If objOption.text<> "" then select1.removeChild(objOption)
	Next
End Sub


Sub ShowHide(elem)
	Set myElement = document.getElementById(elem)
	if myElement.className="HideMe" then
		myElement.className="ShowMe"
	Else
		myElement.className="HideMe"
	End If
End Sub



Sub GetSecurityDescriptor(myOU)
	Const SE_DACL_PROTECTED = &H1000 
	 
	Set objContainer = GetObject(myOU)
	 
	Set objNtSecurityDescriptor = objContainer.Get("ntSecurityDescriptor")
	 
	intNtSecurityDescriptorControl = objNtSecurityDescriptor.Control
	 
	AddHtml "<b>Permissions Tab</b><br>"
	AddHtml "Allow inheritable permissions from the parent to" & _
		"propogate to this object and all child objects "
		
	If (intNtSecurityDescriptorControl And SE_DACL_PROTECTED) Then
		AddHtml "is disabled."
	Else
		AddHtml "is enabled."
	End If
	AddHtml "<br><br>"
	 
	Set objDiscretionaryAcl = objNtSecurityDescriptor.DiscretionaryAcl
	DisplayAceInformation objDiscretionaryAcl, "DACL"


End Sub


 
Sub DisplayAceInformation(SecurityStructure, strType)
    Const ADS_ACETYPE_ACCESS_ALLOWED = &H0 
    Const ADS_ACETYPE_ACCESS_DENIED = &H1 
    Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5 
    Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6 
    intAceCount = 0
    For Each objAce In SecurityStructure
        strTrustee = objAce.Trustee
		If instr(strTrustee,"\") then
			tmpTrustee=mid(strTrustee,Instr(strTrustee,"\")+1)
		Else
			tmpTrustee=strTrustee
		End If
		go=True
		For each blah in arrExcludeList
			If lcase(blah)=lcase(tmpTrustee) then go=False
		Next 
		
        If Instr(strTrustee,"NT AUTHORITY")=False and go=True Then
		
            intAceCount = intAceCount + 1
            'AddHtml strType & " permission entry: " & intAceCount
            AddHtml "<div id=""divTrusteeName" & intAceCount & """ onclick=ShowHide('divEntryData" & intAceCount & "') class=""TrusteeName"">Entry #" & intAceCount & "&nbsp;" & objAce.Trustee & "</div>"
			AddHtml "<div id=""divEntryData" & intAceCount & """ class=""HideMe"">"
			AddHtml "<hr>"
			divCount=divCount+1

            intAceType = objAce.AceType
			If (intAceType = ADS_ACETYPE_ACCESS_ALLOWED Or _
				intAceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT) Then
				AddHtml "Type: Allow Access"
			ElseIf (intAceType = ADS_ACETYPE_ACCESS_DENIED Or _
				intAceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT) Then
				AddHtml "Type: Deny Acess"
			Else
				AddHtml "Access Type Unknown."
			End If
			ReadBitsInAccessMask(objAce.AccessMask)
			AddHtml "<br>"
			AddHtml "</div>"
		End If

    Next
End Sub
 
Sub ReadBitsInAccessMask(AccessMask)
    Const ADS_RIGHT_DELETE = &H10000
    Const ADS_RIGHT_READ_CONTROL = &H20000
    Const ADS_RIGHT_WRITE_DAC = &H40000
    Const ADS_RIGHT_WRITE_OWNER = &H80000
    Const ADS_RIGHT_DS_CREATE_CHILD = &H1
    Const ADS_RIGHT_DS_DELETE_CHILD = &H2
    Const ADS_RIGHT_ACTRL_DS_LIST = &H4
    Const ADS_RIGHT_DS_SELF = &H8
    Const ADS_RIGHT_DS_READ_PROP = &H10
    Const ADS_RIGHT_DS_WRITE_PROP = &H20
    Const ADS_RIGHT_DS_DELETE_TREE = &H40
    Const ADS_RIGHT_DS_LIST_OBJECT = &H80
    Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100
 
    AddHtml "<br>Standard Access Rights"
    If (AccessMask And ADS_RIGHT_DELETE) Then _
        AddHtml "<li>Delete an object.</li>"
    If (AccessMask And ADS_RIGHT_READ_CONTROL) Then _
        AddHtml "<li>Read permissions.</li>"
    If (AccessMask And ADS_RIGHT_WRITE_DAC) Then _
        AddHtml "<li>Write permissions.</li>"
    If (AccessMask And ADS_RIGHT_WRITE_OWNER) Then _
        AddHtml "<li>Modify owner.</li>"
  
    AddHtml "<br>Directory Service Specific Access Rights"
    If (AccessMask And ADS_RIGHT_DS_CREATE_CHILD) Then _
      AddHtml "<li>Create child objects."
    If (AccessMask And ADS_RIGHT_DS_DELETE_CHILD) Then _
        AddHtml "<li>Delete child objects.</li>"
    If (AccessMask And ADS_RIGHT_ACTRL_DS_LIST) Then _
        AddHtml "<li>Enumerate an object.</li>"
    If (AccessMask And ADS_RIGHT_DS_READ_PROP) Then _
        AddHtml "<li>Read the properties of an object.</li>"
    If (AccessMask And ADS_RIGHT_DS_WRITE_PROP) Then _
        AddHtml "<li>Write the properties of an object.</li>"
    If (AccessMask And ADS_RIGHT_DS_DELETE_TREE) Then _
        AddHtml "<li>Delete a tree of objects</li>"
    If (AccessMask And ADS_RIGHT_DS_LIST_OBJECT) Then _
        AddHtml "<li>List a tree of objects.</li>"
 
    AddHtml "<br>Control Access Rights"
    If (AccessMask And ADS_RIGHT_DS_CONTROL_ACCESS) + _
        (AccessMask And ADS_RIGHT_DS_SELF) = 0 Then
          AddHtml "<li>None</li>"
      Else 
      If (AccessMask And ADS_RIGHT_DS_CONTROL_ACCESS) Then _
          AddHtml "<li>Extended access rights.</li>"
      If (AccessMask And ADS_RIGHT_DS_SELF) Then
          AddHtml "<li>Active Directory must validate a property "
          AddHtml " write operation beyond the schema definition "
          AddHtml " for the attribute.</li>"
      End If
    End If
End Sub

</script>

<style>

body {
	font: 10pt arial;
	background-color: buttonface;
}

button
{
	font-family: arial;
	font-size: 8pt;
	width: 70px;
	border: 2px solid gray;
	margin: 3px;
	cursor: hand;
}

.lightborder {
	border: 2px solid gray;
}
.darkborder {
	border: 2px solid black;
}


.ShowMe {
	display: block;
	color: gray;
}

.HideMe {
	display: none;
}

.TrusteeName {
	font-weight: bold;
	cursor: hand;
	color: gray;
}

</style>

</head>

<body>
Organizational Unit:<br>
<select size="0" name="select1" id="select1" onchange="GetPermissions"><option value=""></option></select><BR><BR>
<div id="CommentArea"></div><br>
<div id="DataArea"></div>
</body>
</html>

Open in new window

itsmevicAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mrfixit584Commented:
Somarsoft's DumpSec program can pull a ton of data and save it to a file. It is free. It is distributed by SystemTools, the makers of Hyena. It is quite an amazing tool.
0
itsmevicAuthor Commented:
Hi there MrFixit, that looks like promising software, however if we could do this without having to install 3rd party software that would be great (Can't install 3rd party software for obvious reasons).  That's why I provided the example above hoping to add to it.  
0
RobSampsonCommented:
Hi,

This one would be a start, but I can't modify it until Monday.
http://www.experts-exchange.com/Software/Server_Software/File_Servers/Active_Directory/Q_23863991.html

What that one does is, you select an OU, then a group, and when you click Get Members, the users that are in BOTH the OU and the group are listed.

When I modify it, I'll just take out the OU listing, and have it list the members of the group.

Exporting after that is pretty easy.

On the other hand, someone else may jump in with a solution before then.

Regards,

Rob.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

itsmevicAuthor Commented:
Hey there Rob, I'll take a look at this first thing on Monday.  Thanks for jumping in on this : )
0
RobSampsonCommented:
Hi. OK, I finally got there. Try this.

Regards,

Rob.
<Html>
<Head>
<Title>List Group Members</Title>
 
<HTA:Application
Caption = Yes
Border = Thick
ShowInTaskBar = Yes
SingleInstance = Yes
MaximizeButton = Yes
MinimizeButton = Yes>
 
<script Language = VBScript>
 
	Sub Window_OnLoad
		intWidth = 800
		intHeight = 600
		Me.ResizeTo intWidth, intHeight
		Me.MoveTo ((Screen.Width / 2) - (intWidth / 2)),((Screen.Height / 2) - (intHeight / 2))
		lst_members.Style.Width = 500
    	Set objRootDSE = GetObject("LDAP://RootDSE")
    	strBaseConnString = objRootDSE.Get("defaultNamingContext")
		Set objOULevel = GetObject("LDAP://" & strBaseConnString)
		EnumerateGroups strBaseConnString
		Show_Group_Selection
	End Sub
 
	Sub Clear_Members
		For intListProgress = 1 To lst_members.Length
	   		lst_members.Remove 0
	   	Next
	End Sub
 
	Sub EnumerateGroups(strDNSDomain)
		Const ADS_SCOPE_SUBTREE = 2
		Const adVarChar = 200
		Const MaxCharacters = 255
		
		Set objConnection = CreateObject("ADODB.Connection")
		Set objCommand =   CreateObject("ADODB.Command")
		objConnection.Provider = "ADsDSOObject"
		objConnection.Open "Active Directory Provider"
		Set objCommand.ActiveConnection = objConnection
		
		objCommand.Properties("Page Size") = 1000
		objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
		
		objCommand.CommandText = "SELECT Name, distinguishedName FROM 'LDAP://" & strDNSDomain & "' WHERE objectClass='group'"
		Set objRecordSet = objCommand.Execute
		
		Set objDataList = CreateObject("ADOR.Recordset")
		objDataList.Fields.Append "name", adVarChar, MaxCharacters
		objDataList.Fields.Append "distinguishedName", adVarChar, MaxCharacters
		objDataList.Open
		
		While Not objRecordSet.EOF
		    objDataList.AddNew
		    objDataList("name") = objRecordSet.Fields("name").Value
		    objDataList("distinguishedName") = objRecordSet.Fields("distinguishedName").Value
		    objDataList.Update
			objRecordSet.MoveNext
		Wend
		objRecordSet.Close
		objDataList.Sort = "name"
		objDataList.MoveFirst
		While Not objDataList.EOF
			Set objActiveOption = Document.CreateElement("OPTION")
    		objActiveOption.Text = objDataList.Fields("name").Value
	    	objActiveOption.Value = objDataList.Fields("distinguishedName").Value
	    	lst_GroupFilter.Add objActiveOption
	    	objDataList.MoveNext
		Wend
		objDataList.Close
	End Sub
 
	Sub Show_Group_Selection
		span_GroupFilter.InnerHTML = lst_GroupFilter.Value
	End Sub
 
	Sub Default_Buttons
		If Window.Event.KeyCode = 13 Then
			btn_run.Click
		End If
	End Sub
 
	Sub Exit_HTA
		Window.Close
	End Sub
 
	Sub Get_Members
		Const adVarChar = 200
		Const MaxCharacters = 255

		Clear_Members

		Set objGroup = GetObject("LDAP://" & lst_groupfilter.Value)
		Set objDataList = CreateObject("ADOR.Recordset")
		objDataList.Fields.Append "name", adVarChar, MaxCharacters
		objDataList.Fields.Append "distinguishedName", adVarChar, MaxCharacters
		objDataList.Open
		
		For Each objObject In objGroup.Members
		    objDataList.AddNew
		    objDataList("name") = objObject.cn
		    objDataList("distinguishedName") = objObject.distinguishedName
		    objDataList.Update
		Next
		objDataList.Sort = "name"
		If Not objDataList.BOF Then objDataList.MoveFirst
		While Not objDataList.EOF
			Set objMember = Document.CreateElement("OPTION")
    		objMember.Text = objDataList.Fields("name").Value
	    	objMember.Value = objDataList.Fields("distinguishedName").Value
	    	lst_members.Add objMember
	    	objDataList.MoveNext
		Wend
		objDataList.Close
	End Sub
	
	Sub ExporT_To_TXT
	    If Mid(document.location, 6, 3) = "///" Then
	    	strHTAPath = Mid(Replace(Replace(document.location, "%20", " "), "/", "\"), 9)
	    Else
	    	strHTAPath = Mid(Replace(Replace(document.location, "%20", " "), "/", "\"), 6)
	    End If
		strFileName = Left(strHTAPath, InStrRev(strHTAPath, "\")) & lst_GroupFilter.Item(lst_GroupFilter.SelectedIndex).Text & ".txt"
		strFileName = InputBox("Enter file name to save as:", "Save As", strFileName)
		If strFileName <> "" Then
			Set objFSO = CreateObject("Scripting.FileSystemObject")
			Set objFile = objFSO.CreateTextFile(strFileName, True)
			objFile.WriteLine "Group Distinguished Name: " & lst_groupfilter.Value
			For Each objOption In lst_members
				objFile.WriteLine objOption.Text
			Next
			objFile.Close
			MsgBox "File saved."
		End If
	End Sub
</script>
<body style="background-color:#B0C4DE;" onkeypress='vbs:Default_Buttons'>
	<table height="90%" width= "90%" border="0" align="center">
		<tr>
			<td align="center" colspan="2">
				<h2>List Group Members</h2>
			</td>
		</tr>
		<tr>
			<td>
				<b>Group Filter:</b>
			</td>
			<td>
			    <select size='1' name='lst_GroupFilter'  onChange='vbs:Show_Group_Selection'>
				</select>
			</td>
		</tr>
		<tr>
			<td colspan=2>
				<b>Group Selected:</b>&nbsp&nbsp&nbsp<span id='span_GroupFilter'></span>
			</td>
		</tr>		<tr>
			<td>
				<b>Members:</b>
			</td>
			<td>
			    <select size='8' name='lst_members'>
				</select>
			</td>
		</tr>
	</table>
	<table width= "90%" border="0" align="center">
		<tr align="center">
			<td>
				<button name="btn_run" id="btn_run" accessKey="G" onclick="vbs:Get_Members"><u>G</u>et Members</button>
			</td>
			<td>
				<button name="btn_export" id="btn_export" accessKey="E" onclick="vbs:Export_To_TXT"><u>E</u>xport to TXT</button>
			</td>
			<td>
				<button name="btn_exit" id="btn_exit" accessKey="x" onclick="vbs:Exit_HTA">E<u>x</u>it</button>
			</td>
		</tr>
	</table>
</body>
</head>
</html>

Open in new window

1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
itsmevicAuthor Commented:
Very cool Rob, thank you.  I'll test this first thing and let ya know.
0
itsmevicAuthor Commented:
Oh WOW, Rob this is great man!  I'm just looking it over now....
0
itsmevicAuthor Commented:
As always, simply superb.
0
RobSampsonCommented:
Sure. It's nothing terribly special....just a list of group names.....hopefully it's what you're after.

Rob.
0
603currierCommented:
This script is AWESOME!!! So glad I found it! Thanks A MILLION, Rob!!!
0
RobSampsonCommented:
@603currier, no problem.  I'm glad you find it useful.

Regards,

Rob.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
HTML

From novice to tech pro — start learning today.