Show which users are in the local admin group for 50-100 servers
-
jueves, 02 de febrero de 2012 23:10
Hello all,
I have to do a security audit and find out which users are in local admin groups. I have 50-100 servers windows 2003 and 2008. I also want to add a user called pmbuild to the local admin group on all the servers. Can this be done through GPO?
Any help would be great.
Todas las respuestas
-
jueves, 02 de febrero de 2012 23:21
Hello,
some time ago i found this script in another thread:
'You can use the script below to generate a report on local Administrators and Power Users. Copy it into a text file and rename it with the .vbs extension. Run it from the domain controller. For the computers you are auditing, you must have Administrator privileges and be able to access the computer's RPC ports. The output is tab delimited and can be opened in Excel.
'--------------------------------------------------------------------------------Set oADInfo = CreateObject("ADSystemInfo")
Set oFso = WScript.CreateObject("Scripting.Filesystemobject")
Set oShell = WScript.CreateObject("Wscript.Shell")LogPath = oShell.SpecialFolders("MyDocuments") + "\Privileged LocalUser Audit.txt"
AdsiPath = "WinNT://" + oADInfo.DomainShortName
tab = Chr(9)' Connect to Active Directory
Set ADComputers = GetObject(AdsiPath)
ADComputers.Filter = Array("Computer")' Open the log file
Set oLog = oFso.CreateTextfile(LogPath, true)
oLog.WriteLine "Privileged Local Users on Computers in the " + _
oADInfo.DomainDNSName + _
" domain."
oLog.WriteLine Now
oLog.WriteLine ""
oLog.WriteLine "Computer" + tab + _
"Administrators" + tab + _
"Administrators Groups" + tab + _
"Power Users" + tab + _
"Power Users Groups"' Check each computer
For Each oComputer in ADComputers
' Trap any errors in case the user is unauthorized, the computer is inaccessible, etc.
On Error Resume Next' Get the Administrators users and groups
AdminUsers = ""
AdminGroups = ""
Set objGroup = GetObject("WinNT://" & oComputer.Name & "/Administrators")
If Not(Err.Number = 0) Then
AdminUsers = Err.Number
AdminGroups = Err.Number
End IfFor Each objUser In objGroup.Members
If objUser.Class = "User" Then
AdminUsers = AdminUsers + objUser.Name + "; "
else
AdminGroups = AdminGroups + objUser.Name + "; "
end if
Next' Get the Power Users users and groups
PowerUsers = ""
PowerGroups = ""
Set objGroup = GetObject("WinNT://" & oComputer.Name & "/PowerUsers")
If Not(Err.Number = 0) Then
PowerUsers = Err.Number
PowerGroups = Err.Number
End IfFor Each objUser In objGroup.Members
If objUser.Class = "User" Then
PowerUsers = PowerUsers + objUser.Name + "; "
else
PowerGroups = PowerGroups + objUser.Name + "; "
end if
Next' Output to the log
oLog.WriteLine oComputer.Name + tab + _
AdminUsers + tab + _
AdminGroups + tab + _
PowerUsers + tab + _
PowerGroupsNext
' Close log file handle, open the log in Notepad
oLog.Close
oShell.Run "notepad.exe """ + LogPath + """"' Clean up
Set ADComputers = Nothing
Set oADInfo = Nothing
Set oFso = Nothing
Set oLog = Nothing
Set oLog = Nothing
Set oShell = Nothing'--------------------------------------------------------------------------------
Do not forget to RUN IT IN A LAB BEFORE USING on production domains.
Best regards Meinolf Weber Disclaimer: This posting is provided "AS IS" with no warranties or guarantees , and confers no rights.- Editado Meinolf WeberMVP jueves, 02 de febrero de 2012 23:22
-
jueves, 02 de febrero de 2012 23:44
I also want to add a user called pmbuild to the local admin group on all the servers. Can this be done through GPO
yes, Computer Config, Policies, Windows Settings, Security Settings, Restricted Groups -
sábado, 04 de febrero de 2012 0:58
Thanks for the help, when I run the scrpit it say error on line 18 permission denied. I'm running the script on a dc with a domain admin credentials. I have a domain called test.local. Do I need to modify the script to include my domain name?
-
sábado, 04 de febrero de 2012 2:04
The script does not need to run on a DC. It can be run on any domain joined computer. The error message indicates line 18 in your copy of the script. If this is the line with the "oLog.WriteLine" statment, then you must lack permissions to write in LogPath. Check if the text file was created. Maybe you need to specify a different path.
Richard Mueller - MVP Directory Services -
lunes, 06 de febrero de 2012 17:14
Thanks for the help, I'm using a domain admin account on a windows 2008 server to run the script. I get the error on line 18 permission denied but the text file still opens but without any information. It shows computer administrator, administrators group, power users but no information below.
How would I specify a diffirent path? I noticed the file got saved to the my documents folder.
-
lunes, 06 de febrero de 2012 17:58
On a side note. I found the script below on an older post. This scripts works, it displays the results I'm looking for but doesn't create a txt file. I checked my documents but it wasn't listed. Where would the txt file be located so I can check if it's there?
Also, the script worked in my testing environment but I will to run the script against a OU with 50 computers. How do I do that?
Option Explicit
Dim objLocalGroup, strComputer, objShell
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim objRootDSE, strDNSDomain, strQuery, adoRecordset
' The wshShell object is required by the IsConnectible function.
Set objShell = CreateObject("Wscript.Shell")
' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
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"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 200
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
' Run the query.
Set adoRecordset = adoCommand.Execute
' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
' Retrieve computer name.
strComputer = adoRecordset.Fields("sAMAccountName").Value
' Strip off trailing "$" character.
strComputer = Left(strComputer, Len(strComputer) - 1)
' Ping computer to see if online.
If (IsConnectible(strComputer, 1, 750) = True) Then
' Bind to local Administrators group.
' Trap error if something is wrong.
On Error Resume Next
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Administrators,group")
If (Err.Number = 0) Then
On Error GoTo 0
Wscript.Echo "Computer: " & strComputer
' Enumerate members of the local group.
Call EnumLocalGroup(objLocalGroup, strComputer)
Else
Wscript.Echo "Computer " & strComputer _
& " unable to bind to local Administrators group"
Wscript.Echo " Error Number: " & CStr(Err.Number)
Wscript.Echo " Description: " & Err.Description
On Error GoTo 0
End If
Else
Wscript.Echo "Computer " & strComputer & " is not available"
End If
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop
' Clean up.
adoRecordset.Close
adoConnection.Close
Sub EnumLocalGroup(ByVal objGroup, ByVal strComputer)
' Subroutine to enumerate members of local group.
Dim objMember, strClass, strPath
' Enumerate direct members of group.
For Each objMember In objGroup.Members
strClass = objMember.Class
strPath = objMember.ADsPath
Wscript.Echo " Member: " & strPath & " (" & strClass & ")"
' Test if member is a group.
If (LCase(strClass) = "group") Then
' Nested group. Test if objMember is a local group.
If (InStr(LCase(strPath), "/" _
& LCase(strComputer) & "/") > 0) Then
' objMember is a local group.
' Call sub recursively to enumerate nested local group.
Call EnumLocalGroup(objMember, strComputer)
ElseIf (InStr(LCase(strPath), _
"/nt authority/") > 0) Then
' objMember is local implicit group (special identity).
' Membership cannot be enumerated.
Else
' objMember is a domain group.
' Do not enumerate membership.
End If
End If
Next
End Sub
Function IsConnectible(ByVal strHost, ByVal intPings, ByVal intTO)
' Returns True if strHost can be pinged.
' strHost is the NetBIOS name or IP address of host computer.
' intPings is number of echo requests to send.
' intTO is timeout in milliseconds to wait for each reply.
' Based on a program by Alex Angelopoulos and Torgeir Bakken,
' as modified by Tom Lavedas.
' Variable objShell has global scope and must be declared
' and set in the main program.
' Requires Windows NT or above.
' Modified 09/14/2010 to search for "Reply from" instead of "TTL=".
Dim lngResult
If (intPings = "") Then
intPings = 2
End If
If (intTO = "") Then
intTO = 750
End If
lngResult = objShell.Run("%comspec% /c ping -n " & intPings _
& " -w " & intTO & " " & strHost _
& " | find ""Reply from"" > nul 2>&1", 0, True)
Select Case lngResult
Case 0
IsConnectible = True
Case Else
IsConnectible = False
End Select
End Function -
lunes, 06 de febrero de 2012 21:02
That script looks like mine. Like most administrative scripts, it should be run at a command prompt using the cscript host program, so the output can be redirected to a text file. For example, if this program is saved in the file LocalAdmins.vbs, use the following at the command prompt of any computer joined to the domain:
cscript //nologo LocalAdmins.vbs > report.txt
This assumes you are in the folder where the file LocalAdmins.vbs is saved. Otherwise you must specify the full path to the file. The file report.txt is created in the current folder. The optional "//nologo" suppresses logo information, so it is not included in the new file.
To restrict the program to the computers in one OU, modify the base of the query. As written, the base is the entire domain. The value of the variable strDNSDomain will be the distinguished name of the domain. Just replace with the distinguished name of an OU. For example, change this:
strBase = "<LDAP://" & strDNSDomain & ">"
to this, where the DN of your ou is "ou=Sales,ou=West,dc=MyDomain,dc=com":strBase = "<LDAP://ou=Sales,ou=West,dc=MyDomain,dc=com>"
Does this help?
Richard Mueller - MVP Directory Services- Marcado como respuesta Shaon ShanMicrosoft Contingent Staff, Moderator jueves, 09 de febrero de 2012 0:40
-
lunes, 06 de febrero de 2012 22:02
Awesome, thanks Richard. It was your script. I called the script localadmins.vbs. Saved it to my c:drive. Ran it throught command prompt withcscript //nologo LocalAdmins.vbs > report.txt
And I got the result I was looking for. I now have to create an OU and modify the script.- Marcado como respuesta Shaon ShanMicrosoft Contingent Staff, Moderator jueves, 09 de febrero de 2012 0:40
-
lunes, 12 de marzo de 2012 3:42
Hello,
Thanks again, do you know how I would change the script above to disaply the users in the power user and users group?
Regards,
K
-
lunes, 12 de marzo de 2012 8:08
Instead of binding to the Administrators group with this statement:
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Administrators,group")
-----
You can bind to the Power Users group:
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Power Users,group")
-----
or, to the Users group:
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Users,group")
-----
Richard Mueller - MVP Directory Services
-
jueves, 22 de marzo de 2012 15:27
I am getting an error:
C:\Scripts\adminvbs.vbs(36, 1) Active Directory: There is no such object on the server.
Here is line 36: Set adoRecordset = adoCommand.Execute
Any advice for me?
Thank you
-
jueves, 22 de marzo de 2012 16:58
That line raises an error if the script cannot contact a Domain Controller in the specified domain. Either the base of the query is incorrect (the value assigned to the variable strBase), or a Domain Controller cannot be contacted, or the computer where the script is running is not joined to a domain, or you are logged into the computer locally (instead of into the domain).
Richard Mueller - MVP Directory Services
-
lunes, 26 de marzo de 2012 12:40Thank you for the help. I got it to work.. Now is there a way to output this into a CSV file for the auditors instead of having the message box pop up for every one? Thanks again for all the help.
-
lunes, 26 de marzo de 2012 13:17
Run the script at a command prompt using the cscript host program, so you can redirect the output to a text file. For example, if the VBScript is saved in a file named GetMembers.vbs use a command similar to:
cscript //nologo GetMembers.vbs > Members.csv
The optional //nologo parameter suppresses logo information, so it doesn't show up in the file. The above assumes you are in the folder where the file GetMembers.vbs is saved. Otherwise, you must specify the full path to the file. The new file Members.csv is created in the current folder.
You mention a csv file, but the program doesn't output in comma delimited format. It could be modified for this, but then there would be only one line of output. Is that really what you want? Or is the text file created with the above statement sufficient?
Richard Mueller - MVP Directory Services
-
lunes, 26 de marzo de 2012 13:33
That is beautiful! I should have re-read the whole post before asking, sorry about that. Ugh, Monday!
I will try with the CSV, I might be able to work it in Excel. If not, I will go with txt.
Thanks again sir, you saved me!
-
lunes, 26 de marzo de 2012 14:42
I decided that a csv format perhaps does make sense here. I modified the script to output one line per computer. The first field in each line is the name of the computer. Each subsequent field (comma delimited) is the ADsPath of each direct member of the group (Administrators in this case). I use the ADsPath so you can see if the member is local or domain. I don't show the class of the member in this case. I haven't tested, but I think this should work:
Option Explicit
Dim objLocalGroup, strComputer, objShell
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim objRootDSE, strDNSDomain, strQuery, adoRecordset
Dim strOutput
' The wshShell object is required by the IsConnectible function.
Set objShell = CreateObject("Wscript.Shell")
' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
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"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 200
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
' Run the query.
Set adoRecordset = adoCommand.Execute
' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
' Retrieve computer name.
strComputer = adoRecordset.Fields("sAMAccountName").Value
' Strip off trailing "$" character.
strComputer = Left(strComputer, Len(strComputer) - 1)
' Ping computer to see if online.
If (IsConnectible(strComputer, 1, 750) = True) Then
' Bind to local Administrators group.
' Trap error if something is wrong.
On Error Resume Next
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Administrators,group")
If (Err.Number = 0) Then
On Error GoTo 0
strOutput = strComputer
' Enumerate members of the local group.
Call EnumLocalGroup(objLocalGroup, strComputer)
Wscript.Echo strOutput
Else
Wscript.Echo strComputer _
& " unable to bind to local Administrators group"
On Error GoTo 0
End If
Else
Wscript.Echo strComputer & " is not available"
End If
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop
' Clean up.
adoRecordset.Close
adoConnection.Close
Sub EnumLocalGroup(ByVal objGroup, ByVal strComputer)
' Subroutine to enumerate members of local group.
' Variable strOutput has global scope.
Dim objMember, strClass, strPath
' Enumerate direct members of group.
For Each objMember In objGroup.Members
strClass = objMember.Class
strPath = objMember.ADsPath
strOutput = strOutput & "," & strPath
' Test if member is a group.
If (LCase(strClass) = "group") Then
' Nested group. Test if objMember is a local group.
If (InStr(LCase(strPath), "/" _
& LCase(strComputer) & "/") > 0) Then
' objMember is a local group.
' Call sub recursively to enumerate nested local group.
Call EnumLocalGroup(objMember, strComputer)
ElseIf (InStr(LCase(strPath), _
"/nt authority/") > 0) Then
' objMember is local implicit group (special identity).
' Membership cannot be enumerated.
Else
' objMember is a domain group.
' Do not enumerate membership.
End If
End If
Next
End Sub
Function IsConnectible(ByVal strHost, ByVal intPings, ByVal intTO)
' Returns True if strHost can be pinged.
' strHost is the NetBIOS name or IP address of host computer.
' intPings is number of echo requests to send.
' intTO is timeout in milliseconds to wait for each reply.
' Based on a program by Alex Angelopoulos and Torgeir Bakken,
' as modified by Tom Lavedas.
' Variable objShell has global scope and must be declared
' and set in the main program.
' Requires Windows NT or above.
' Modified 09/14/2010 to search for "Reply from" instead of "TTL=".
Dim lngResult
If (intPings = "") Then
intPings = 2
End If
If (intTO = "") Then
intTO = 750
End If
lngResult = objShell.Run("%comspec% /c ping -n " & intPings _
& " -w " & intTO & " " & strHost _
& " | find ""Reply from"" > nul 2>&1", 0, True)
Select Case lngResult
Case 0
IsConnectible = True
Case Else
IsConnectible = False
End Select
End Function
-----
Richard Mueller - MVP Directory Services
-
lunes, 26 de marzo de 2012 20:40
Just tested it and it works great. Thank you!
Another quick question though.. I had to change the strBase because I didnt want to scan the entire structure, just some OUs. Here is line 21.
strBase = "<LDAP://ou=Laptops, ou=Client Computers - Windows 7, dc=mydomain, dc=com>"
This works just fine, but as soon as I add another sub OU to the code:
strBase = "<LDAP://ou=XX, ou=Laptops, ou=Client Computers - Windows 7, dc=mydomain, dc=com>"
the script returns an error stating:
C:\Scripts\Admin1.vbs(37, 1) Active Directory: There is no such object on the server.
Am I doing something wrong or is there a limitation?
- Editado DrewMilizia lunes, 26 de marzo de 2012 21:00
-
lunes, 26 de marzo de 2012 22:12
There is no limitation, either in the length of the distinguished name, or in the depth of the OU structure. The error indicates there is no "ou=XX" within "OU=Laptops".
Richard Mueller - MVP Directory Services
-
martes, 27 de marzo de 2012 12:24I figured it out.. I looked in the attribute editor and although the OU name looked correct in AD, it was named differently. Thanks for all your help, I really appreciate it!
-
martes, 01 de mayo de 2012 20:42This is great. I was just wondering though, how can I change this to instead of searching all of AD, just pull from a text file with a list of servers?
-
martes, 01 de mayo de 2012 22:36
This maybe should be split into a separate question. In any case, here is the main program modified (but not tested) to read computer names from a text file, one name per line. The EnumLocalGroup and IsConnectible methods would be unchanged and are not included here:
Option Explicit
Dim objLocalGroup, strComputer, objShell
Dim strOutput
Dim strFile, objFSO, objFile
Const ForReading = 1
' Specify file of computer names.
strFile = "c:\Scripts\Computers.txt"
' Open file for reading.
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(strFile, ForReading)
' The wshShell object is required by the IsConnectible function.
Set objShell = CreateObject("Wscript.Shell")
' Read the file.
Do Until objFile.AtEndOfStream
strComputer = Trim(objFile.ReadLine)
' Skip blank lines.
If (strComputer <> "") Then
' Ping computer to see if online.
If (IsConnectible(strComputer, 1, 750) = True) Then
' Bind to local Administrators group.
' Trap error if something is wrong.
On Error Resume Next
Set objLocalGroup = GetObject("WinNT://" & strComputer _
& "/Administrators,group")
If (Err.Number = 0) Then
On Error GoTo 0
strOutput = strComputer
' Enumerate members of the local group.
Call EnumLocalGroup(objLocalGroup, strComputer)
Wscript.Echo strOutput
Else
Wscript.Echo strComputer _
& " unable to bind to local Administrators group"
On Error GoTo 0
End If
Else
Wscript.Echo strComputer & " is not available"
End If
End If
Loop
' Clean up.
objFile.Close
-----
Richard Mueller - MVP Directory Services
- Editado Richard MuellerMVP jueves, 03 de mayo de 2012 0:16 Fixed typo
-
miércoles, 02 de mayo de 2012 18:17
Thanks for the update!
When I run this, I receive an error:
<23,5> Microsoft VBScript runtime error: Variable is undefined: 'strLine'
-
jueves, 03 de mayo de 2012 0:11
Sorry, instead of strLine is should be strComputer. The line should be:
If (strComputer <> "") Then
I've corrected the code in my reply above.
Richard Mueller - MVP Directory Services
-
miércoles, 21 de noviembre de 2012 3:38
Hello,
I'm currently use your .csv output script on our single 2008 domain and I'm making ground. The script runs just fine as-is (your default) but I'm not able to do two modifications as mentioned in this discussion. First, I assume that this script will search all systems in the domain, computers and servers or just servers? I want to run this only against our 2003/2008 servers. Also, we have roughly 350 physical and virtual servers, will this script handle this volume?
So for starters I would like to run the script against our domain (dimensional.com also called dfa_primary) inside one OU called AustinSungard Servers, which is inside a root OU called DFA, so I did this:
'strBase = "<LDAP://" & strDNSDomain & ">" strBase = "<LDAP://OU=AustinSunGard Servers, OU=DFA, DC=dimensional.com, DC=com>"
and I receive this error:
C:\uc4>cscript //nologo LocalAdmins_csv.vbs > report.csv
C:\uc4\LocalAdmins_csv.vbs(38, 1) Active Directory: A referral was returned from
the server.Also, I would like to run this not only to return user objects w/in the local administrators group but also the power users group. When I add another line for power users like this:
Set objLocalGroup = GetObject("WinNT://" & strComputer _ & "/Administrators,group") Set objLocalGroup = GetObject("WinNT://" & strComputer _ & "/Power Users,group")The process runs, but it only populates the server name and no other information (i.e. the users in the local admin and power users groups are all blank). I'm guessing I need to somehow combine these lines?
Ultimately, I would like to also be able to exclude certain accounts such as WinNT://DFA_PRIMARY/DFAADMINS and WinNT://DFA_PRIMARY/Domain Admins and also local admins such as WinNT://DFA_PRIMARY/SERVER-NAME/Administrator
My goal is to create a csv file with a list of servers with all accounts other than the excluded ones inside the local administrators and power users groups.
Thanks,
Roy
- Editado Roy Niswanger miércoles, 21 de noviembre de 2012 4:07 typo

