Re: Another Scripting Newbie - admin check




"STFW" <STFW@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:3CF5DB67-94DD-4898-97DF-1440ED390CDE@xxxxxxxxxxxxxxxx
The goal is to find out who is running with admin rights (and then later
worry about trying to get users to run as domain users only). In the past
we
typically added a user to the local Administrator group to workaround
programs that wouldn't run as a limited user. I'm looking for a way to
check
many XP workstations on a WS2003 domain for admins. So I guess I'm
looking
to get a report of what users are members of all local groups on all
computers in a domain.


This is not an easy task, but the question has come up before and I have a
limited solution. I say limited because you can grant admin rights to users
directly. Also, the local Administrators group can be renamed. The script
below discovers all users (and groups) that are members of the local
Administrators group on all computers in the domain. It finds direct
members, members due to group nesting of local groups, members of domain
groups that are members of the local Administrators group (like "Domain
Admins") and members due to nesting of domain groups. This program checks if
each computer is available. It uses a dictionary object so that domain group
membership is documented only once (like "Domain Admins"), not once for
every computer. This only documents the local Administrators groups, not all
groups. It should be run at a command prompt using the cscript host, so the
output can be redirected to a text file:
===============
Option Explicit

Dim objRootDSE, strDNSDomain, adoConnection, adoCommand
Dim strBase, strFilter, strAttributes, strQuery
Dim adoRecordset, strComputer
Dim objLocalAdmGroup
Dim objShell, objFSO, strTemp, strTempFile
Dim objTrans, strNetBIOSDomain, objGroupList

Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_1779 = 1

Set objShell = CreateObject("Wscript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTrans = CreateObject("NameTranslate")
objTrans.Init ADS_NAME_INITTYPE_GC, ""

' Specify temporary file to save ping results.
strTemp = objShell.ExpandEnvironmentStrings("%TEMP%")
strTempFile = strTemp & "\RunResult.tmp"

' Setup dictionary object so membership of each domain
' group is enumerated once.
Set objGroupList = CreateObject("Scripting.Dictionary")
objGroupList.CompareMode = vbTextCompare

' Determine DNS domain from RootDSE object.
Set objRootDSE = GetObject("LDAP://RootDSE";)
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Determine NetBIOS domain name (with trailing backslash).
objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)

' Use ADO to search Active Directory for computers.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

' Search entire domain.
strBase = "<LDAP://"; & strDNSDomain & ">"

' Filter on computer objects.
strFilter = "(objectCategory=computer)"

' Comma delimited list of attribute values to retrieve.
strAttributes = "sAMAccountName"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"

' Run the query.
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 60
adoCommand.Properties("Cache Results") = False

Set adoRecordset = adoCommand.Execute

' Enumerate the recordset.
Do Until adoRecordset.EOF
' NetBIOS name of computer is sAMAccountName
' with trailing "$" removed.
strComputer = adoRecordset.Fields("sAMAccountName").Value
strComputer = Left(strComputer, Len(strComputer) - 1)
If (IsConnectible(strComputer, 1, 759) = True) Then
' Bind to the local Administrators group on each computer
' with the WinNT provider. Trap error if group not found.
On Error Resume Next
Set objLocalAdmGroup = GetObject("WinNT://" & strComputer _
& "/Administrators,group")
If (Err.Number = 0) Then
On Error GoTo 0
Wscript.Echo strComputer
' Enumerate members of this group.
Call EnumLocalGroup(objLocalAdmGroup, "-- ")
Else
On Error GoTo 0
Wscript.Echo strComputer _
& " has no local Administrators group"
End If
Else
Wscript.Echo strComputer & " not available"
End If
adoRecordset.MoveNext
Loop
adoRecordset.Close

' Clean up.
adoConnection.Close

Function IsConnectible(strHost, intPings, intTO)
' Returns True if strHost can be pinged.
' Based on a program by Alex Angelopoulos and Torgeir Bakken.
' Variables strTempFile, objShell, and objFSO have global scope
' and must be declared in the main program.
Dim objFile, strResults

If (intPings = "") Then
intPings = 2
End If
If (intTO = "") Then
intTO = 750
End If

Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const ForReading = 1

objShell.Run "%comspec% /c ping -n " & intPings & " -w " & intTO _
& " " & strHost & ">" & strTempFile, 0, True

Set objFile = objFSO.OpenTextFile(strTempFile, ForReading, _
FailIfNotExist, OpenAsDefault)
strResults = objFile.ReadAll
objFile.Close

Select Case InStr(strResults, "TTL=")
Case 0
IsConnectible = False
Case Else
IsConnectible = True
End Select
End Function

Sub EnumLocalGroup(ByVal objLocalGroup, ByVal strOffset)
' Recursive subroutine to enumerate members of a local group.
Dim objMember, blnLocal

For Each objMember In objLocalGroup.Members
' Check if objMember is local.
If (InStr(LCase(objMember.AdsPath), "/" _
& LCase(strComputer) & "/") > 0) Then
' objMember is a local object.
blnLocal = True
Wscript.Echo strOffset & objMember.Name & " (local " _
& objMember.Class & ")"
Else
' objMember is a domain object.
blnLocal = False
Wscript.Echo strOffset & objMember.Name & " (domain " _
& objMember.Class & ")"
End if

' Check if objMember is a group.
If (LCase(objMember.Class) = "group") Then
If (blnLocal = True) Then
' objMember is a local group.
Call EnumLocalGroup(objMember, "--" & strOffset)
Else
' objMember is a domain group.
Call EnumDomainGroup(objMember, "--" & strOffset, True)
End If
End If
Next

End Sub

Sub EnumDomainGroup(ByVal objDomainGroup, ByVal strOffset, blnNT)
' Recursive subroutine to enumerate members of a domain group.
Dim strGroupDN, objGroup, objMember

' If group object bound with WinNT provider, bind with LDAP provider.
If (blnNT = True) Then
objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain _
& objDomainGroup.Name
strGroupDN = objTrans.Get(ADS_NAME_TYPE_1779)
Set objGroup = GetObject("LDAP://"; & strGroupDN)
Else
Set objGroup = objDomainGroup
End If

' Check if this group enumerated already.
If (objGroupList.Exists(objGroup.distinguishedName) = True) Then
' Group membership already enumerated.
Wscript.Echo strOffset & "duplicate domain group already enumerated"
Else
' Enumerate members of domain group.
objGroupList.Add objGroup.distinguishedName, True
For Each objMember In objGroup.Members
Wscript.Echo strOffset & objMember.sAMAccountName _
& " (domain " & objMember.Class & ")"
' Check if objMember is a group.
If (LCase(objMember.Class) = "group") Then
Call EnumDomainGroup(objMember, "--" & strOffset, False)
End If
Next
End If

End Sub

--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab web site - http://www.rlmueller.net
--


.



Relevant Pages

  • Re: Another Scripting Newbie - admin check
    ... members, members due to group nesting of local groups, members of domain ... Dim objRootDSE, strDNSDomain, adoConnection, adoCommand ... ' Bind to the local Administrators group on each computer ... For Each objMember In objLocalGroup.Members ...
    (microsoft.public.windows.server.scripting)
  • Re: Local computer - privileged access - active directory question
    ... Enumerate members of the local group. ... Sub EnumLocalGroup ... For Each objMember In objGroup.Members ...
    (microsoft.public.windows.server.scripting)
  • Re: Another Scripting Newbie - admin check
    ... the local Administrators group can be renamed. ... members, members due to group nesting of local groups, members of domain ... ' Enumerate members of this group. ... For Each objMember In objLocalGroup.Members ...
    (microsoft.public.windows.server.scripting)
  • Re: Enumerate members of all groups within a specific OU
    ... enumerate all the groups ahead of time and populate an array of arrays, ... row isn't an option as listing the members in each column would exceed ... ' Dictionary object to track groups. ... For Each objMember In objADGroup.Members ...
    (microsoft.public.windows.server.scripting)
  • Re: Local administrator access
    ... Dim objRootDSE, strDNSDomain, adoConnection, adoCommand ... ' Enumerate members of this group. ... For Each objMember In objLocalGroup.Members ...
    (microsoft.public.windows.server.scripting)

Loading