Active Directory: VBscript to enumerate nested Active Directory groups from an Excel sheet

Posted October 4th, 2011 in groups by dirk adamsky

Haven’t done much scripting lately…..
The script for today is made for Ananth Kumar.
He asked me to make an extension to the “enumerate nested groups script” so that multiple nested groups can be enumerated based on an input file.
I did choose Excel for the input file so that i could reuse previous code.

Follow the next steps to run the script (no admin rights needed):

  • find the distinguished names of the nested groups (adsiedit.msc)
  • put them in an Excel sheet in the first column ans save the sheet as c:\temp\groups.xls
  • open your favorite text editor
  • copy and paste the script below into the editor (you can use the icons in the upper rights corner of the code)
  • save the script (for example c:\temp\enumeratenestedgroupsfromexcelsheet.vbs)
  • open a command prompt
  • go to “c:\temp”
  • give “cscript enumeratenestedgroupsfromexcelsheet.vbs” (without quotes) and enter

The script:

' Name : enumeratenestedgroupsfromexcelsheet.vbs
' Description : script to enumerate nested Active Directory groups from an Excel sheet
' Author : dirk adamsky - deludi bv
' Version : 1.0
' Date : 04-10-2011

Set objExcel = CreateObject("Excel.Application")
Set objWorkbook = objExcel.Workbooks.Open("C:\temp\groups.xls")
intRow = 2
Do Until objExcel.Cells(intRow,1).Value = ""
strGroupDN = objExcel.Cells(intRow, 1).Value
If strGroupDN <> "" Then
wscript.echo strGroupDN
EnumNestedgroup "LDAP://" & strGroupDN
End If
intRow = intRow + 1
Loop
objExcel.Quit
Set objWorkbook = Nothing
Set objExcel = Nothing

Function EnumNestedgroup(strGroupDN)
Set objGroup = GetObject(strGroupDN)
For Each objMember in objGroup.Members
If (LCase(objMember.Class) = "group") Then
EnumNestedgroup objMember.AdsPath
Else
Wscript.Echo objGroup.cn & " ; " & objMember.DisplayName & " ; " & objMember.Mail
End If
Next
Set objGroup = Nothing
End Function

When you have a modified version or problems/questions that you want to share please post it at the comments below.

Happy scripting.

Dirk Adamsky

Active Directory: VBscript to enumerate the home directories and their sizes of all users in Active Directory

Posted July 12th, 2011 in home directories by dirk adamsky

Update: This script has some issues (path not found) with users with very large home folders and or homefolders with long pathnames. This is due to limitations of the Filesystem Object. I will see if i can make a “better solution”.

Dave asked me for a script to enumerate all AD users, their home directories and the size of them.
I already had the script to do that for roaming profiles.
This script is a modified version.

Follow the next steps to run the script (admin rights needed for access to the home directories):

* open your favorite text editor
* copy and paste the script into the editor
* save the script (for example c:\temp\homedirectorysize.vbs)
* open a command prompt
* go to “c:\temp”
* give “cscript homedirectorysize.vbs” (without quotes) and enter

The script:

' Name : homedirectorysize.vbs
' Description : script to enumerate the home directories and their sizes of all users in Active Directory
' Author : dirk adamsky - deludi bv
' Version : 1.00
' Date : 12-07-2011
' Level : intermediate

arrAttributes = Array("homeDirectory","displayname","mail") 

Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

Set objRootDSE = GetObject("LDAP://RootDSE")
strBase = "<LDAP://" & objRootDSE.Get("defaultNamingContext") & ">"
Set objRootDSE = Nothing

strFilter = "(&(objectCategory=person)(objectClass=user)(homeDirectory=*))"
strAttributes = Join(arrAttributes,",")
Wscript.Echo Join(arrAttributes,";") & " ; home directory size in MB"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
Set adoRecordset = adoCommand.Execute
Do Until adoRecordset.EOF
	On Error Resume Next
	strTempOutput = ""
	For i = 0 To Ubound(arrAttributes)
		strTempOutput =  strTempOutput & " ; " & adoRecordset.Fields(arrAttributes(i)).Value
		strOutput = Mid(Ltrim(strTempOutput),3)
	Next
	Wscript.Echo strOutput & " ; " & Foldersize (adoRecordset.Fields(arrAttributes(0)).Value) & " MB"
	adoRecordset.MoveNext
Loop
adoRecordset.Close
adoConnection.Close
Set adoRecordset = Nothing
Set adoConnection = Nothing
Set adoCommand = Nothing

Function Foldersize(strPath)
	On Error Resume Next
	Set objFSO = CreateObject("scripting.filesystemobject")
	Set objFld = objFSO.GetFolder(strPath)
	Foldersize = Round(objFld.Size/1048576,2)
	Set objFld = Nothing
	Set objFSO = Nothing
End Function

When you have problems/questions please post a reply. Also can alo give a ‘star’ rating.

Happy scripting.

Best regards,

Dirk Adamsky – Deludi BV

Active Directory: VBscript to enumerate the local profile size of all computers and users in Active Directory

Posted June 28th, 2011 in localprofiles by dirk adamsky

This script is made for Mike.
He asked for a script to enumerate all local profiles and their size of the computers in his network.
Complicating factor is the use of both Windows XP and Windows 7 clients.
As you probably know that they have different local profile paths:

Windows XP – “c:\documents and settings”

Windows 7 – “c:\users”

The script has to do:

  • get all Windows XP and Windows 7 clients from Active Directory
  • check if they are online
  • get the local profiles and their sizes from each machine
  • write the values to a central logfile

Follow the next steps to run the script (local admin rights needed for access to the target pc’s):

* open your favorite text editor
* copy and paste the script into the editor
* change the logfile location in line 73 (now c:\temp)
* save the script (for example c:\temp\localprofiles.vbs)
* open a command prompt
* go to “c:\temp”
* give “cscript localprofiles.vbs” (without quotes) and enter

The script:

' Name : localprofiles.vbs
' Description : script to enumerate the local profile size of all computers and users in Active Directory
' Author : dirk adamsky - deludi bv
' Version : 1.00
' Date : 28-06-2011

Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
Set objRootDSE = GetObject("LDAP://RootDSE")
strBase = "<LDAP://" & objRootDSE.Get("defaultNamingContext") & ">"
strFilter = "(&(objectCategory=computer)(|(operatingSystem=Windows XP Professional)(operatingSystem=Windows 7*)))"
strAttributes = "name, operatingSystem"
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False

Set adoRecordset = adoCommand.Execute

Do Until adoRecordset.EOF
	strHostname = adoRecordset.Fields("name").Value
	If CheckStatus(strHostname) = True Then
		If Instr(adoRecordset.Fields("operatingSystem").Value, "XP") > 0 Then
			strLocalProfilePath = "\Documents and Settings\"
		ElseIf Instr(adoRecordset.Fields("operatingSystem").Value, "7") > 0 Then
			strLocalProfilePath = "\users\"
		End If
		GetLocalProfileSize strHostname, "\\" & strHostname & "\c$" & strLocalProfilePath
	End If
	adoRecordset.MoveNext
Loop

adoRecordset.Close
adoConnection.Close

Set adoRecordset = Nothing
Set objRootDSE = Nothing
Set adoConnection = Nothing
Set adoCommand = Nothing

Function CheckStatus(strAddress)
	Dim objPing, objRetStatus
	Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}").ExecQuery _
      ("select * from Win32_PingStatus where address = '" & strAddress & "'")
	For Each objRetStatus In objPing
        If IsNull(objRetStatus.StatusCode) Or objRetStatus.StatusCode <> 0 Then
			CheckStatus = False
        Else
			CheckStatus = True
        End If
    Next
	Set objPing = Nothing
End Function

Function GetLocalProfileSize(strTargetMachine, strFolder)
	Set objFSO = CreateObject("Scripting.FileSystemObject")
	Set objFolder = objFSO.GetFolder(strFolder)
	For Each SubFolder in objFolder.SubFolders
		Logprint strTargetMachine & " ; " & SubFolder.Name & " ; " & SubFolder.Path & " ; " & Round(SubFolder.Size/1048576,2) & " MB"
	Next
	Set objFolder = Nothing
	Set objFSO = Nothing
End Function

Function LogPrint(Message)
Const ForAppending = 8
strDate = Replace(Date,"/","-")
Set ObjFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = ObjFSO.OpenTextFile("c:\temp\" & strDate & "-localprofiles.csv", ForAppending, True)
    objTextFile.WriteLine Message
    objTextFile.Close
Set objTextFile = Nothing
Set ObjFSO = Nothing
End Function

When you have problems/questions please post a reply. Also can also give a ‘star’ rating.

Happy scripting.

Best regards,

Dirk Adamsky – Deludi BV

Active Directory and WMI: VBscript to enumerate a sorted list of all mailboxes and their size in your AD domain

Posted May 17th, 2011 in email by dirk adamsky

Today’s script is made for Gavin.
It is an extension of my previous script to enumerate all Exchange mailboxes and their size.
Gavin asked for a sorted list based on mailbox size.

My first attempt was to use the VB Arraylist object (.Net needed on the script machine).
Here’s an Arraylist example by Rob van der Woude.
The problem with the Arraylist object is that it is not made for sorting multi dimensional arrays.
I can do some tricks by concatenating all values to a superstring.
The problem is that sorting an Arraylist with superstrings will be next to impossible.

Luckily I found a better solution by using a disconnected recordset
(= a recordset without database connection).
One thing to check is to use the right datatype for each variable.
I declared the “size” variable as a “double precision floating point”.
The other 2 were delared as “null-terminated character strings”.
With the disconnected recordset you can do a lot of funky stuff like sorting, filtering and so on.
I will certainly use the disconnected recordset object in new scripts.

I have tested the script in a large environment (~ 8500 mailboxes).
It worked flawless (okay I had to test and modify it for half an hour or so).

What the script does:

  • get all exchange servers from your AD domain
  • make a wmi connection to each server and create a list of the mailboxes and their size
  • put all values in a disconnected recordset, sort and output to the screen

The script is tested in a win2003/exchange2003 environment.

Follow the next steps to run the script (admin rights needed):

  • copy and paste the script in your favorite text editor
  • save the script (for example c:tempsortedlistofallmailboxes.vbs)
  • open a command prompt
  • go to “c:temp”
  • give “cscript sortedlistofallmailboxes.vbs” (without quotes) and enter

The script:

' Name : sortedlistofallmailboxes.vbs
' Description : script to enumerate all mailboxes and their size in your AD domain
' Author : dirk adamsky - deludi bv
' Version : 1.00
' Date : 17-05-2011
' Level: intermediate

Set DataList = CreateObject("ADOR.Recordset")
DataList.Fields.Append "Servername", 200, 255
DataList.Fields.Append "DisplayName", 200, 255
DataList.Fields.Append "Size", 5
DataList.Open

Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection

Set objRootDSE = GetObject("LDAP://RootDSE")
strBase = "<LDAP://" & objRootDSE.Get("configurationnamingcontext") & ">"
strFilter = "(objectCategory=msExchExchangeServer)"
strAttributes = "name"

strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 3
adoCommand.Properties("Cache Results") = False

Set adoRecordset = adoCommand.Execute

Do Until adoRecordset.EOF
 Set objWMIExchange = GetObject("winmgmts:{impersonationLevel=impersonate}!//"&_
 adoRecordset.Fields("name").Value & "/root/MicrosoftExchangeV2")
 Set colExchangeMailboxes = objWMIExchange.InstancesOf("Exchange_Mailbox")
 For Each objExchangeMailbox in colExchangeMailboxes
 If Left(objExchangeMailbox.StorageGroupName, 5) <> "Recov" Then
 DataList.AddNew
 DataList("Servername") = adoRecordset.Fields("name").Value
 DataList("DisplayName") = objExchangeMailbox.MailboxDisplayName
 DataList("Size") = Round(objExchangeMailbox.Size/1024,0)
 Datalist.Update
 End If
 Next
 Set colExchange_Mailboxes = Nothing
 Set objWMIExchange = Nothing
 adoRecordset.MoveNext
Loop

adoRecordset.Close
adoConnection.Close

Set adoRecordset = Nothing
Set objRootDSE = Nothing
Set adoConnection = Nothing
Set adoCommand = Nothing

DataList.Sort = "Size DESC"
DataList.MoveFirst

Do Until DataList.EOF
 Wscript.Echo DataList.Fields.Item("Size") & " MB ; " & DataList.Fields.Item("DisplayName") & " ; " &_
 DataList.Fields.Item("Servername")
 DataList.MoveNext
Loop

Datalist.Close
Set DataList = Nothing

When you have problems/questions please post a reply or give a ‘star’ rating.

Happy scripting.

Best regards,

Dirk Adamsky – Deludi BV