locked
How to get local admin detalis of all computer. RRS feed

  • Question

  • HI,

    In my environment i have having at least 100000+ desktops. I want to know how many users are added in all desktops local administrator group. Kindly help on this so that i can get this information centralized place not visiting individual desktop.

    I know the net local group “Administrators” > C:\group.txt.

    I have put this command in computer startup group policy. But i am not very much sure is this solution will work or not.

     Is there any vb script is available that takes input from a excel file (in which file I put the machine name) and provide me output of machines local admin membership information.

     

     


    Nirmal Singh IT Administrator
    Friday, July 22, 2011 11:08 AM

Answers

All replies

  • there are a number of different scenarios where you could accomplish this:

    1) SMS/SCCM
    2) Logon script that gathers the details using something similar to what you described:  net localgroup "administrators" > c:\%computername%.txt
       - Then copy this file out to a network share
    3) On-Demand script that you can run to try to connect to all machines and get this information locally on your machine
       - Typically, the caveat to this method is that you only get machines that are turned on at the time you run the script

    I'd recommend either 1) or 2). 


    Friday, July 22, 2011 11:44 AM
  • You should lock down teh Local Admin group with Group Policy then you wouldn't have to worry. It's BP now.

    You can do this with a VBScript but it will take  long time to run for 100,000 computers.  Of course it will take less time than walking around to each one but not much less.

    You can also do it easier with PowerShell.  Here is a function that will list members of teh local admingroup.  Feed it a list of computernames and it will report on all.

    function GetLocalAdministrators([string]$server=$env:computername){
         $group=[adsi]"WinNT://$Server/Administrators,group"
         $group.psbase.Invoke("Members") |
              ForEach-Object{
                  $name=$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
                  new-Object PSObject -property @{System=$server;AccountName=$name}
              }
    }

    GetLocalAdministrators | ft -auto

    By deffault the function will list teh admins for the current machine.

    GetLocalAdministrators MyPC1

    Will call MyPC1 and list its admins.

    Cat servers.txt | %{GetLocalAdministrators $_}

    will list all of the pcs listed in servers.txt

    ([adsisearcher]'objectCategory=computer').FindAll() | %{GetLocalAdministrators $_.Properties.name}

    will list all computers admni group for all computers in AD.

     


    jv
    • Proposed as answer by TNJMAN Tuesday, April 23, 2013 3:35 PM
    Friday, July 22, 2011 11:44 AM
  • i agree with jrv that you should lock down your administrators group at least with a script if not with group policy but, i would not recommend the method he's describing.  running a script once will only get the machines that are online at the time your run it.  a better option would be to already be grabbing this informatino that's in a DB somewhere (like SMS/SCCM) or if you have to come up with the solution yourself, make it a logon script to a share that Authenticated Users has Write rights to and then you can create a script to tabulate the results.  that way you don't have to continually run the script and only ever get 80% of the machines on your network.  And you don't have to wait forever for your script to run against 100K machines.
    Friday, July 22, 2011 12:08 PM
  • I would recommend using the Restricted Groups feature of Group Policy to enforce membership in the local Administrators group on all computers. See this link:

    http://support.microsoft.com/kb/279301

    However, the following VBScript program uses ADO to retrieve all computers in the domain, then pings each to see if it is available. If the computer is available, the script binds to the local Administrators group and enumerates the direct members.

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strComputer
    Dim objGroup, objMember, objShell, objSysInfo, strDomain, strLine

    ' Retrieve NetBIOS name of the domain.
    Set objSysInfo = CreateObject("ADSystemInfo")
    strDomain = objSysInfo.DomainShortName

    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 values.
        strComputer = adoRecordset.Fields("sAMAccountName").Value
        ' Strip off trailing "$" character.
        strComputer = Left(strComputer, Len(strComputer) - 1)
        strLine = strComputer
        ' Ping computer to see if online.
        If (PingMachine(strComputer, 1, 750) = True) Then
            ' Bind to Administrators group on the computer.
            On Error Resume Next
            Set objGroup = GetObject("WinNT://" & strComputer & "/Administrators,group")
            If (Err.Number = 0) Then
                On Error GoTo 0
                ' Enumerate direct members of group.
                For Each objMember In objGroup.Members
                    strLine = strLine & "," & objMember.Name
                Next
                Wscript.Echo strLine
            Else
                Wscript.Echo strLine & " <Failed to bind to Administrators group>"
            End If
        Else
            Wscript.Echo strLine & ", <Not available>"
        End If
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

    Function PingMachine(ByVal strHost, ByVal intPings, ByVal intTO)
        ' Returns True if strHost can be pinged.
        ' Variable objShell has global scope
        ' and must be declared in the main program.
        ' Modified 09/14/2010 to search for "Reply from" instead of "TTL=".

        Dim strResults, objExecObject

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

        ' Ping the machine.
        Set objExecObject = objShell.Exec("%comspec% /c ping -n " _
            & CStr(intPings) & " -w " & CStr(intTO) & " " & strHost)

        ' Read the output.
        Do Until objExecObject.StdOut.AtEndOfStream
            strResults = objExecObject.StdOut.ReadAll
        Loop

        Select Case InStr(strResults, "Reply from")
            Case 0
                ' No response.
                PingMachine = False
            Case Else
                ' Computer responded to ping.
                PingMachine = True
        End Select
    End Function

    -----

    This script will take a long time to run if you have many computers, and some will not be available. In this example, I document the member "Name". You could instead document the "ADsPath" (for example "WinNT://MyDomain/jsmith" or "WinNT://MyDomain/MyComputer/jsmith"), which indicates if the member is a local or domain object.

    Like most administrative scripts, this should be run at a command prompt using the cscript host program so the output can be redirected to a text file. In this case, the output is comma delimited so the file can be read directly into a spreadsheet program. If this code is saved in the file GetAdms.vbs, you could run it at a command prompt as follows:

    cscript //nologo GetAdms.vbs > LocalAdms.csv

    If you are not in the folder where the file GetAdms.vbs is saved, specify the full path to the file. The new file LocalAdms.csv is created in the current folder.


    Richard Mueller - MVP Directory Services
    • Proposed as answer by TNJMAN Tuesday, April 23, 2013 3:39 PM
    • Edited by Richard MuellerMVP Tuesday, April 23, 2013 4:58 PM Replaced IsConnectible with PingMachine function name
    Friday, July 22, 2011 1:20 PM
  • Take a look at the following PowerShell Script. Export all computer names to a CSV and this script will use that file as an input.   You can ignore the email part..

     

    http://portal.sivarajan.com/2011/04/list-local-administrator-group-members.html

    Cls
    $From = "santhosh@sanlab.com"
    $To = "santhosh@sanlab.com"
    $SMTPServer = "mail.sanlab.com"
    $SMTP = new-object Net.Mail.SmtpClient($SMTPServer)
    $GFile = New-Item -type file -force "C:\Scripts\SGroupMemberDetails.csv"
    Import-CSV "C:\Scripts\Servers.csv" | ForEach-Object {
    $N = 0
    $SName = $_.ServerName
    "Server Name - $SName" | Out-File $GFile -encoding ASCII -append
    $group = [ADSI]("WinNT://$SName/Administrators,group") 
    $GMembers = $group.psbase.invoke("Members")
    $GMembers | ForEach-Object {$_.GetType().InvokeMember("Name",'GetProperty', $null, $_, $null) | Out-File $GFile -encoding ASCII -append
    $N++
    }
      If ($N -gt 5)
        {
        $Sub = "Administrator Group Details on $SName Server"
        $Ebody = "Administrator Group on $SName Server has $N members."
        $SMTP.Send($From, $To, $Sub, $Ebody)
        #Add specific details/function here. 
        }
      Else 
        {
        $Sub = "Administrator Group Details on $SName Server"
        $Ebody = "Administrator Group on $SName Server has $N members."
        $SMTP.Send($From, $To, $Sub, $Ebody)
        #Add specific details/function here. 
        }
    
    }
    



    Santhosh Sivarajan | MCTS, MCSE (W2K3/W2K/NT4), MCSA (W2K3/W2K/MSG), CCNA, Network+ Houston, TX

    Blogs - http://blogs.sivarajan.com/
    Articles - http://www.sivarajan.com/publications.html
    Twitter: @santhosh_sivara - http://twitter.com/santhosh_sivara
    This posting is provided AS IS with no warranties,and confers no rights.
    Friday, July 22, 2011 4:52 PM
  • You could use this utility to remotely attach to each computer and list the members of the admins group to a text file, using a simple batch file.

    FOR /F %%a IN (computers.txt) DO  addmembers2group /tg=administrators /e=%%a.txt /c=%%a

    Or you could use the utilitiy in a logon script ran locally on the workstation, and redirect to a central share

    addmembers2group /tg=administrators /e /c=%computername% >> \\server\share\%computername%.txt

    http://networkadminkb.com/Utilities/Descriptions/AddMembers2Group.aspx

     


    • Marked as answer by Nirmal Singh Monday, July 25, 2011 10:14 AM
    Friday, July 22, 2011 7:32 PM
  • I would recommend using the Restricted Groups feature of Group Policy to enforce membership in the local Administrators group on all computers. See this link:

    http://support.microsoft.com/kb/279301

    However, the following VBScript program uses ADO to retrieve all computers in the domain, then pings each to see if it is available. If the computer is available, the script binds to the local Administrators group and enumerates the direct members.

     

    Option Explicit

    Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
    Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strComputer
    Dim objGroup, objMember, objShell, objSysInfo, strDomain, strLine

    ' Retrieve NetBIOS name of the domain.
    Set objSysInfo = CreateObject("ADSystemInfo")
    strDomain = objSysInfo.DomainShortName

    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 values.
        strComputer = adoRecordset.Fields("sAMAccountName").Value
        ' Strip off trailing "$" character.
        strComputer = Left(strComputer, Len(strComputer) - 1)
        strLine = strComputer
        ' Ping computer to see if online.
        If (IsConnectible(strComputer, 1, 750) = True) Then
            ' Bind to Administrators group on the computer.
            On Error Resume Next
            Set objGroup = GetObject("WinNT://" & strComputer & "/Administrators,group")
            If (Err.Number = 0) Then
                On Error GoTo 0
                ' Enumerate direct members of group.
                For Each objMember In objGroup.Members
                    strLine = strLine & "," & objMember.Name
                Next
                Wscript.Echo strLine
            Else
                Wscript.Echo strLine & " <Failed to bind to Administrators group>"
            End If
        Else
            Wscript.Echo strLine & ", <Not available>"
        End If
        ' Move to the next record in the recordset.
        adoRecordset.MoveNext
    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

    Function PingMachine(ByVal strHost, ByVal intPings, ByVal intTO)
        ' Returns True if strHost can be pinged.
        ' Variable objShell has global scope
        ' and must be declared in the main program.
        ' Modified 09/14/2010 to search for "Reply from" instead of "TTL=".

        Dim strResults, objExecObject

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

        ' Ping the machine.
        Set objExecObject = objShell.Exec("%comspec% /c ping -n " _
            & CStr(intPings) & " -w " & CStr(intTO) & " " & strHost)

        ' Read the output.
        Do Until objExecObject.StdOut.AtEndOfStream
            strResults = objExecObject.StdOut.ReadAll
        Loop

        Select Case InStr(strResults, "Reply from")
            Case 0
                ' No response.
                PingMachine = False
            Case Else
                ' Computer responded to ping.
                PingMachine = True
        End Select
    End Function

    -----

     

    This script will take a long time to run if you have many computers, and some will not be available. In this example, I document the member "Name". You could instead document the "ADsPath" (for example "WinNT://MyDomain/jsmith" or "WinNT://MyDomain/MyComputer/jsmith"), which indicates if the member is a local or domain object.

    Like most administrative scripts, this should be run at a command prompt using the cscript host program so the output can be redirected to a text file. In this case, the output is comma delimited so the file can be read directly into a spreadsheet program. If this code is saved in the file GetAdms.vbs, you could run it at a command prompt as follows:

    cscript //nologo GetAdms.vbs > LocalAdms.csv

    If you are not in the folder where the file GetAdms.vbs is saved, specify the full path to the file. The new file LocalAdms.csv is created in the current folder.

     


    Richard Mueller - MVP Directory Services

    I'm trying to use this one but IsConnectible is not being defined and I'm getting an error (sorry scripting newb or I'd try to fix it myself).

    Wednesday, February 15, 2012 5:16 PM
  • Hi,

    This question has already been marked as answered. If you need help, please start a new question (referencing this thread, if appropriate).

    Bill

    Wednesday, February 15, 2012 5:52 PM
  • Sorry, my mistake. When I pasted the code I used a new function called PingMachine in place of IsConnectible. Simply replace the string "IsConnectible" with the string "PingMachine" in the script.

    I tested the corrected script in my domain and it worked for me.


    Richard Mueller - MVP Directory Services

    Wednesday, February 15, 2012 8:06 PM
  • Is there any way to change the script to report on a specific OU within the domain rather than the entire domain?
    Wednesday, February 29, 2012 5:00 PM
  • Yes. Modify the base of the query. Replace the DNSName of the domain (the distinguished name of the domain) with the distinguished name of the OU. For example:

    strBase = "<LDAP://ou=Sales,ou=West,dc=MyDomain,dc=com>"

    -----

    This restricts the query to the specified OU, plus child OU's. If you don't want child OU's, replace "subtree" with "onelevel".


    Richard Mueller - MVP Directory Services

    Wednesday, February 29, 2012 5:11 PM
  • Is there a way to run this against a list of computers, cause i have a forrest and many domains within that forest. Could i specify only the computers in my domain?

    Friday, September 7, 2012 12:08 AM
  • Hi,

    This question is already marked answered. Please start a new question.

    Bill

    Friday, September 7, 2012 12:26 AM
  • Actually, no it doesn't work after simply changing that function name. Then it complains about that "true / false" variable "PingMachine" that you also use in the script... Anyway, would be nice to get this working

    And,

    YES, THIS HAS BEEN MARKED AS ANSWERED, but wouldn't it be nice to let us still have some discourse on the topic, so that we could refine this stuff, so that it works properly. To be sure, if Mr. Mueller's script worked properly, it should be considered a "co-answer."

    So, after changing the function name to "IsConnectible," AND doing "Dim PingMachine," the script does run but it puts "<Not available>" beside every single record in the CSV file.

    I guess we can start another thread called "Fix Mueller's Script"?


    tnjman

    Tuesday, April 23, 2013 4:14 PM
  • In the script I posted above, replace "IsConnectible" with "PingMachine". Sorry, I put the script together from two others and didn't spot that I used a different function name.


    Richard Mueller - MVP Directory Services

    Tuesday, April 23, 2013 4:53 PM