Show which users are in the local admin group for 50-100 servers
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.
February 4th, 2012 6:12pm

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 If For 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 If For 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 + _ PowerGroups Next ' 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.
Free Windows Admin Tool Kit Click here and download it now
February 4th, 2012 6:24pm

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
February 4th, 2012 6:47pm

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?
Free Windows Admin Tool Kit Click here and download it now
February 4th, 2012 8:02pm

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
February 4th, 2012 9:08pm

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
Free Windows Admin Tool Kit Click here and download it now
February 7th, 2012 12:02am

Awesome, thanks Richard. It was your script. I called the script localadmins.vbs. Saved it to my c:drive. Ran it throught command prompt with cscript //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.
February 7th, 2012 1:02am

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.
Free Windows Admin Tool Kit Click here and download it now
February 11th, 2012 12:18pm

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
February 11th, 2012 1:02pm

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
Free Windows Admin Tool Kit Click here and download it now
February 11th, 2012 4:06pm

Awesome, thanks Richard. It was your script. I called the script localadmins.vbs. Saved it to my c:drive. Ran it throught command prompt with cscript //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.
February 11th, 2012 5:06pm

I 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!
Free Windows Admin Tool Kit Click here and download it now
April 8th, 2012 8:30am

Thank 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.
April 8th, 2012 8:45am

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
Free Windows Admin Tool Kit Click here and download it now
April 8th, 2012 9:22am

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!
April 8th, 2012 9:38am

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
Free Windows Admin Tool Kit Click here and download it now
April 8th, 2012 10:47am

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
April 8th, 2012 11:32am

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
Free Windows Admin Tool Kit Click here and download it now
April 8th, 2012 1:03pm

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?
April 8th, 2012 4:45pm

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
Free Windows Admin Tool Kit Click here and download it now
April 8th, 2012 6:17pm

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
April 8th, 2012 11:48pm

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
Free Windows Admin Tool Kit Click here and download it now
April 9th, 2012 4:14am

This 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?
May 1st, 2012 4:42pm

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
Free Windows Admin Tool Kit Click here and download it now
May 1st, 2012 6:36pm

Thanks for the update! When I run this, I receive an error: <23,5> Microsoft VBScript runtime error: Variable is undefined: 'strLine'
May 2nd, 2012 2:17pm

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
Free Windows Admin Tool Kit Click here and download it now
May 2nd, 2012 8:11pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics