Count Computer Objects in Active Directory

Posted on 2009-02-17
Last Modified: 2013-12-24
I need help creating a script (vb or powershell) to count the total number of computer objects throughout an AD domain. Getting a total count is easy, however I need a script to recursively discover and count enabled computer objects throughout a domain without specifying every path where these objects are located.

Input would be:

Output would be: distinguishedName where computer objects were discovered, total of enabled computer objects
Question by:ChWCIT
    LVL 18

    Accepted Solution

    If you find yourself doing alot of AD stuff I would get the free quest cmdlets

    Then this can be simply done like this

    (get-qadcomputer -sl 0 -enabled).count
    LVL 12

    Expert Comment

    Hi There

    Have you ever used Saved Queries in Active Directory Users and Computers Snap-In?
    Its very easy to use, i've provided steps on how to do what you want

    Right Click on Saved Queries in teh ADUC
    Click New -> Query
    Give it a name like All Computers
    Click Define Queries
    From Drop Down - Computers
    ComputerName = *
    Role can be what you choose
    Save this

    Right-Click on the New Query and click Refresh

    If you right-Click in the results window (blank area) and select View -> Add/Remove Columns
    You can select Distinguished names
    Then right-Click yor Query and select Export List
    Select "Save as Type" as Text CSV to makle it Outlook Friendly

    This is now there forever and can be refreshed regularly
    Saved Queries is quite powerful and can do most things you will need.

    Hope this helps


    If you really want a VBScript then i can help there too


    Author Comment

    @BSonPosh - I have this utility, however due to the number of records(21,000) the powershell fail with an error of: "more data available"

    @Krys K - Good to know, however I can't show where these objects reside, there are no column selection to show where these computer objects are located.
    LVL 18

    Expert Comment

    That is odd ( I have 380k and it works for me albeit slowly.) you can try this

    $n = 0
    get-qadcomputer -sl 0 -enabled | %{$n++}

    Open in new window


    Author Comment

    @BSonPosh, here's what happens.

    [PS] C:\>$n = 0
    [PS] C:\>get-qadcomputer -sl 0 -enabled | %{$n++}
    Get-QADComputer : A parameter cannot be found that matches parameter name 'enabled'.
    At line:1 char:31
    + get-qadcomputer -sl 0 -enabled  <<<< | %{$n++}
    [PS] C:\>get-qadcomputer -sl 0 | %{$n++}
    Get-QADComputer : More data is available.
    At line:1 char:16
    + get-qadcomputer  <<<< -sl 0 | %{$n++}
    [PS] C:\>
    LVL 12

    Expert Comment

    Hi There

    I have written a scrip that will do what you want

    See how you get on with it.
    Save to notepad as a .VBS file

    Results are saved to C:\ComputerReport.csv


    Option Explicit
    	Call MainScript
    WScript.Echo "Changes complete. Check the report on C: Drive"
    Sub MainScript
    ' Version 1.0
    ' Amended by Krystian Karia
    ' Dated 18-Feb-2009
    ' Script that gets all the computer names
    ' and their DistinguishedNames from AD.
    ' All results are put to a csv file
    	On Error Resume Next
    	Dim objFSO, objReport
    	Dim strReportFile
    	Dim strHeader, strMsg
    	Dim strComputer
    	Dim iSelectedOption
    	Dim arrComputers
    	Const ForWriting = 2
    ' Create needed objects
    	Set objFSO = CreateObject("Scripting.FileSystemObject")
    ' Initialize variables
    	strHeader = "ComputerName,DistinguishedName"
    	strReportFile = "c:\ComputerReport.csv"
    ' Open the report 
    	Set objReport = objFSO.OpenTextFile(strReportFile, ForWriting, True)
    ' Enter the header
    	objReport.WriteLine strHeader
    ' Ask where to get our machine list from
    		strMsg = strMsg & "Select an option by entering a number only!" & vbNewLine & vbNewLine
    		strMsg = strMsg & "1 - Servers Only (From AD)" & vbNewLine
    		strMsg = strMsg & "2 - Desktops Only (From AD)" & vbNewLine
    		strMsg = strMsg & "3 - All Machines (From AD)" & vbNewLine & vbNewLine
    	iSelectedOption = InputBox(strMsg, "Select an Option", "1")
    		Select Case Trim(iSelectedOption)
    			Case "1"
    				arrComputers = GetObjectArrayFromAD("Servers", "")
    			Case "2"
    				arrComputers = GetObjectArrayFromAD("Desktops", "")
    			Case "3"
    				arrComputers = GetObjectArrayFromAD("AllMachines", "")
    			Case Else
    				WScript.Echo "An invalid option was made or you cancelled"
    		End Select
    ' Loop each computer
    	For Each strComputer In arrComputers
    		If strComputer = "" Then
    			Exit For
    		End If 
    		objReport.WriteLine strComputer
    End Sub
    Private Function GetObjectArrayFromAD(sArgComputerType, sArgDCName)
    ' Version 1.0
    ' ~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~
    '	Function Written by Krystian Karia
    '	Description:	Function that searches AD based on the criteria
    '					that you pass to it and returns an Array
    '	Use:			Pass the Machine Type and optional Domain Controller ServerName
    '	Example:		arrMyComputerArray = GetObjectArrayFromAD("servers" | "desktops" | "allmachines" ["dcservername"])
    '	Returns:		An array of all required computer objects found
    '	Version:		Version 1.0		Created on 06-08-2007
    ' ~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~¬~
    	On Error Resume Next
    	Dim oRoot
    	Dim strBase, strFilter, strCriteria, strLevel
    	Dim adoConnection, adoCommand, adoRecordset
    	Dim strQuery, strContents
    	Dim arrResults
    	Dim i
    ' Get the Domain you are currently in
    	Set oRoot = GetObject("LDAP://rootDSE")
    		strBase = oRoot.Get("defaultNamingContext")
    			If Err.Number<> 0 Then
    				WScript.Echo "Unable to get the current domain name - Is the machine this script ran on a part of one?" _ 
    					& VbCrLf & "Error: " & Err.Number _ 
    					& VbCrLf & Err.Source _
    					& VbCrLf & Err.Description
    				GetObjectArrayFromAD = False
    			End If 
    ' Build the Filter string according to our computer type request
    	Select Case UCase(sArgComputerType)
    		Case "SERVERS" 
    			strFilter = "(&(&(&(sAMAccountType=805306369)(objectCategory=computer)(operatingSystem=*Server*))))"
    		Case "DESKTOPS"
    			strFilter = "(&(&(sAMAccountType=805306369)(objectCategory=computer)(!operatingSystem=*Server*)))"
    		Case "ALLMACHINES" 
    			strFilter = "(&(&(&(sAMAccountType=805306369)(objectCategory=computer)(samAccountName=*))))"
    		Case Else
    			Exit Function
    	End Select
    ' Set our Attribute Criteria and Search Level
    	 	strCriteria = "sAMAccountName,distinguishedName"
     		strLevel = "SubTree"
    ' Build our complete query string using the DC Server Name if passed
    	If sArgDCName <> "" Then
    		strQuery = "<LDAP://" & sArgDCName & "/" & strBase & ">;" & strFilter & ";" & strCriteria & ";" & strLevel
    		strQuery = "<LDAP://" & strBase & ">;" & strFilter & ";" & strCriteria & ";" & strLevel
    	End If
    ' Set up the connection to Active Directory using ADO
    	Set adoConnection = CreateObject("ADODB.Connection")
    	Set adoCommand = CreateObject("ADODB.Command")
    		adoConnection.Provider = "ADsDSOObject"
    		adoConnection.Open = "Active Directory Provider"
    		adoConnection.Cursorlocation = 3
    	Set adoCommand.ActiveConnection = adoConnection
    			If Err.Number <> 0 Then
    				WScript.Echo "Unable to open a connection to Active Directory" _
    					& VbCrLf & "Error: " & Err.Number _ 
    					& VbCrLf & Err.Source _
    					& VbCrLf & Err.Description
    				GetObjectArrayFromAD = False
    			End If 
    		adoCommand.CommandText = strQuery
    		adoCommand.Properties("Page Size") = 1000
    		adoCommand.Properties("Timeout") = 30
    		adoCommand.Properties("Cache Results") = False
    ' Get the recordset results of the query to Active Directory
    	Set adoRecordset = adoCommand.Execute
    		adoRecordset.Sort = "distinguishedName"
    			If Err.Number <> 0 Then
    				WScript.Echo "An error occured executing the recordset" _
    					& VbCrLf & "Error: " & Err.Number _ 
    					& VbCrLf & Err.Source _
    					& VbCrLf & Err.Description
    				GetObjectArrayFromAD = False
    			End If 
    ' Loop all the records that were found
    		Do Until adoRecordset.EOF = True
    '			For i = 0 To adoRecordset.Fields.Count - 1
    				If NOT IsNull(adoRecordset.Fields("sAMAccountName").Value) Then ' Remove $ symbol from end of machines
    					strContents = strContents & Left(adoRecordset.Fields("sAMAccountName").Value, Len(adoRecordset.Fields("sAMAccountName").Value) - 1) & ","
    				End If
    				strContents = strContents & Chr(34) & adoRecordset.Fields("distinguishedName").Value & Chr(34) & vbNewLine
    '			Next
    ' Close the Recordset and clear the variables
    	Set adoRecordset = Nothing
    	Set adoCommand = Nothing
    	Set adoConnection = Nothing
    ' Check the contents of the list is not empty
    		If Trim(strContents) <> "" Then
    			arrResults = Split(strContents, vbNewLine)	' Create an array of the list
    				strContents = ""						' Clear the variable as not needed anymore
    			GetObjectArrayFromAD = arrResults
    			GetObjectArrayFromAD = False
    		End If
    End Function 'GetObjectArrayFromAD

    Open in new window

    LVL 70

    Assisted Solution

    by:Chris Dent

    > Get-QADComputer : A parameter cannot be found that matches parameter name 'enabled'

    I don't have that parameter either, but this will return a count of enabled computers:

    (Get-QADComputer -SL 0 -LdapFilter "(!userAccountControl:1.2.840.113556.1.4.804:=2)").Count

    LVL 70

    Expert Comment

    by:Chris Dent

    > I have 380k and it works for me albeit slowly

    Mmm how do you get a job there? ;)

    LVL 18

    Expert Comment

    doh! Correct you are. It is Get-QADUser that has -enabled. userAccountControl was my next bet.

    As for a job... it is a fun place to work with unique challenges, but it requires a special kind of person :) Are you special Chris :P
    LVL 70

    Expert Comment

    by:Chris Dent

    lol most definitely, but perhaps that's not a good thing :)


    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Highfive Gives IT Their Time Back

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    Suggested Solutions

    This article is the result of a quest to better understand Task Scheduler 2.0 and all the newer objects available in vbscript in this version over  the limited options we had scripting in Task Scheduler 1.0.  As I started my journey of knowledge I f…
    This article describes some very basic things about SQL Server filegroups.
    Video by: Steve
    Using examples as well as descriptions, step through each of the common simple join types, explaining differences in syntax, differences in expected outputs and showing how the queries run along with the actual outputs based upon a simple set of dem…
    This tutorial will walk an individual through the process of transferring the five major, necessary Active Directory Roles, commonly referred to as the FSMO roles from a Windows Server 2008 domain controller to a Windows Server 2012 domain controlle…

    761 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    6 Experts available now in Live!

    Get 1:1 Help Now