Count Computer Objects in Active Directory

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
Who is Participating?
BSonPoshConnect With a Mentor Commented:
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
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

ChWCITAuthor Commented:
@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.
Improve Your Query Performance Tuning

In this FREE six-day email course, you'll learn from Janis Griffin, Database Performance Evangelist. She'll teach 12 steps that you can use to optimize your queries as much as possible and see measurable results in your work. Get started today!

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

ChWCITAuthor Commented:
@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:\>
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*))))"
			strFilter = "(&(&(sAMAccountType=805306369)(objectCategory=computer)(!operatingSystem=*Server*)))"
			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

Chris DentConnect With a Mentor PowerShell DeveloperCommented:

> 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

Chris DentPowerShell DeveloperCommented:

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

Mmm how do you get a job there? ;)

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
Chris DentPowerShell DeveloperCommented:

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

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.