To follow up after the last few articles on VBScript fundamentals, this article contains several different code snippets that can be used with very little modification in any Windows Active Directory environment. This article will focus on scripts and can be used to administer users and groups with ADSI. The final example is a list of several different code snippets and a logon script written using VBScript instead of batch files.
The scripts will vary a little in format which is intended to demonstrate the different methods possible in writing scripts. Some scripts declare variables while some don’t, some are broken into sections to demonstrate a template style of scripting while some are not, etc. Obviously, when taking pieces of these snippets and incorporating them into a larger script, it is best to declare variables at the beginning, group subroutines and functions together, group the main body of the script together, add comments, and use a template style of scripting that is easy to read by someone other than the script author.
Previous articles that can be used for reference with the code contained herein are:
Windows Scripting – VBScript Fundamentals and
Windows Scripting – VBScript Fundamentals (ADSI)
The following will give high-level explanations of the different examples in addition to the commented details contained within the scripts themselves:
Enable a disabled user account
- Assign the value of disabled to the userAccountControl attribute flag. (this value will be reversed using a bitwise operator later in the script).
- Bind to the user object with the GetObject method. This script demonstrates two different syntax types for this initial binding; use either LDAP or WinNT, but not both.
- Initialize the user object with the userAccountConrol attribute and the associated flag.
- Use the AND operator to determine if the flag is set to enabled (meaning the account is enabled)
- Use the XOR bitwise operator to reverse the flag on the userAccountControl attribute. Since it was set as a value of 2 (disabled) initially, this changes the flag to enable the account.
'-- LDAP path syntax
'===================
Set objOU = GetObject("LDAP://OU=MIS,dc=mydomain,dc=com")
Set objUser = objOU.Create("User", "cn=jsmith")
objUser.Put "sAMAccountName", "jsmith"
objUser.SetInfo
‘– Domain path syntax
‘=====================
Set objDomain = GetObject(“WinNT://Mydomain”)
Set objUser = objDomain.Create(“user”, “jsmith”)
objUser.SetInfo
‘– Enabling the user account after it has been
‘– created using the flag in the userAccountControl
‘– attribute and the XOR bit.
‘===================================================
Const ADS_UF_ACCOUNTDISABLE = 2
Set objUserACL = GetObject _
(“LDAP://cn=” & objUser & “,ou=MIS,dc=mydomain,dc=com”)
intUAC = objUserACL.Get(“userAccountControl”)
If intUAC And ADS_UF_ACCOUNTDISABLE Then
objUserACL.Put _
& “userAccountControl”, intUAC Xor ADS_UF_ACCOUNTDISABLE
objUserACL.SetInfo
End If
Next
‘– A simpler way to enable a user account
‘=========================================
Set objUser = GetObject _
(“LDAP://cn=jsmith,ou=MIS,dc=mydomain,dc=com”)
objUser.AccountDisabled = FALSE
objUser.SetInfo
Deletes a user account from Active Directory
- Bind to the Active Directory container that contains the user object to be deleted.
- Use the delete method to remove the account.
- The additional example uses an input box for user input when the script is run.
'-- Delete a user object from Active Directory
'=============================================
Set objOU = GetObject(“LDAP://ou=MIS,dc=mycompanydc=com”)
objOU.Delete “User”, “cn=Joe Smith”
‘– Script could also be changed to request input
‘– via a pop-up screen as follows:
‘================================================
Set objOU = GetObject(“LDAP://ou=MIS,dc=mycompanydc=com”)
Set oName = InputBox(“Enter the name of the user to be deleted”)
objOU.Delete “User”, “cn=” & oName
Add a user to a local group
- Bind to the local Administrators group.
- Bind to the user object to be added to the local group.
- Add the user to the local group with the Add method and the IADs path.
'Adds user object to local group by using IADs
'Properties to return AdsPath.
'=============================================
strComputer = "computer_name"
Set objGroup = GetObject _
("WinNT://" & strComputer & "/Administrators,group")
Set objUser = GetObject _
("WinNT://" & strComputer & "/jsmith,user")
objGroup.Add(objUser.ADsPath)
‘Adds user object to local group by specifying
‘object path within domain context.
‘=============================================
DomainString = “mydomain”
UserString = “jsmith”
GroupString = “Administrators”
Set objGroup = GetObject _
(“WinNT://” & DomainString & “/” & GroupString)
objGroup.Add (“WinNT://” & DomainString & “/” & UserString)
Set a user password and force user to change password at next logon.
Set a password
1. Bind to user the object
2. Set the password as specified in script
Change password at next logon
1. Bind to the user object
2. Enable the pwdLastSet attribute on the user account
3. Set the information within AD for the user account.
'-- Set password for a user object
'=================================
Set objUser = GetObject _
("LDAP://cn=jsmith,ou=MIS,dc=mydomain,dc=com")
objUser.SetPassword "P@$$w0rD"
‘– Force user to change password at next logon
‘==============================================
Set objUser = GetObject _
(“LDAP://cn=jsmith,ou=MIS,dc=mydomain,dc=com”)
objUser.Put “pwdLastSet”, 0 ‘change to 1 to disable
objUser.SetInfo
Modify user profile and home directory properties
- Bind to the user object
- Set the properties for the attributes
- Set the information within AD for the user object.
'-- Modify user profile and home directory
'-- properties.
'=========================================
Set objUser = GetObject _
("LDAP://cn=jsmith,ou=MIS,dc=mydomain,dc=com")
objUser.Put "profilePath", "\\ServerA\Profiles\jsmith"
objUser.Put "scriptPath", "logonscript.vbs"
objUser.Put "homeDirectory", "\\ServerA\HomeDirs\jsmith"
objUser.Put "homeDrive", "H:"
objUser.SetInfo
Create 1,000 user accounts for testing purposes
- Bind to the RootDSE of the directory (binds to a DC without specifying the LDAP path)
- Build the ADsPath to the current domain with defaultNamingContext.
- Using a For…Next control loop, a counter is used and a each time a user is created, the counter is incremented by one until it reaches the limit of 1000.
'-- Create 1000 User accounts for testing
'========================================
Set objRootDSE = GetObject("LDAP://rootDSE")
Set objContainer = GetObject("LDAP://cn=Users," & _
objRootDSE.Get("defaultNamingContext"))
For i = 1 To 1000
Set objLeaf = objContainer.Create("User", "cn=User" & i)
objLeaf.Put "sAMAccountName", "User" & i
objLeaf.SetInfo
Next
WScript.Echo "1000 Users created."
Adding users and global groups to a local group using a text file list as input into an array and calling a command line from within the script.
- Declare the variables used in the script
- Bind to the Scripting.FileSystemObject and use the TextFile method to create a text file for output as well as specify the text file to be used as input.
- Bind to the WScript.Shell object to be used in calling the command line executables.
- Initialize the array by using the ReadAll method on the input text file.
- Using a control loop…
- Assign the path to the executable to be called from the command line with the appropriate switches to the commandline variable.
- Use the Run method of the WScript.Shell object to run the command from within the script.
- Bind to the machine accounts in the array to determine local group memberships within the specified group and print the output in the text file.
'-- Examples of adding groups and users to
'-- the local Administrators group.
'=========================================
'-- Declare variables
'====================
Dim fso
Dim outfile
Dim infile
Dim Shell
Dim str
Dim SvrArray
Dim Group
Dim Domain
Dim oDomain
On Error Resume Next
'-- Assign values to variables
'=============================
Set fso = CreateObject("Scripting.FileSystemObject")
Set outfile = fso.OpenTextFile _
("C:\Scripting\AddDomainUsers.txt", 2, True)
Set infile = fso.OpenTextFile _
("C:\Scripting\ComputerNames.txt")
Set Shell = CreateObject("Wscript.Shell")
outfile.writeline " "
outfile.writeline "Addition of MYCOMPANY accounts" _
& "account to Local Administrators "
outfile.writeline "group started at " & Now()
outfile.writeline " "
'-- Initialize and populate array
'================================
str = infile.ReadAll()
SvrArray = Split(str, vbCrLf)
oDomain = "MY_DOMAIN"
Set Domain = GetObject("WinNT://" & oDomain)
'-- Control Loop
'===============
For Each Server In SvrArray
commandline = "C:\WINNT\System32\NET LOCALGROUP " _
& "Administrators MY_DOMAIN\Domain Users /delete"
Shell.Run commandline, 1, True
commandline = "C:\WINNT\System32\NET LOCALGROUP " _
& "Administrators MY_DOMAIN\Desktop Admins /add"
Shell.Run commandline, 1, True
commandline = "C:\WINNT\System32\NET LOCALGROUP " _
& "Administrators MY_DOMAIN\Domain Admins /add"
Shell.Run commandline, 1, True
Set User = GetObject _
("WinNT://" & Server.Name & "/Administrators")
If User.IsMember("WinNT://MY_DOMAIN/Domain Admins") Then
outfile.writeline " MY_DOMAIN\Domain Admins already exists on " _
& Server & " or computer is not reachable."
ElseIf
User.IsMember("WinNT://MY_DOMAIN/Desktop Admins") Then
outfile.writeline " MY_DOMAIN\Desktop Admins already exists on " _
& Server & " or computer is not reachable."
Else
outfile.writeline " Adding accounts to Local Adminstrators on " & Server
User.Add("WinNT://MY_DOMAIN/username")
End If
outfile.writeline " "
Next
outfile.writeline "Script completed at " & Now()
MsgBox "Add_DomainUsers script has completed."
Lists the group memberships of all users within a specified container
This script is best run using cscript your_script.vbs from the command line as it will generate large amounts of data. Another option is to incorporate the TextFile method used in the last example to re-direct the output to a text file.
- Set the value of the constant to the number of the error that will be returned by ADSI if the user is not a member of any groups.
- Bind to the users container in Active Directory.
- Initialize the dynamic array to contain the users within the specified container.
- Using a control loop…
- Obtain the primary group ID
- Initialize another array to contain the group memberships pertaining to current user in the first array. This array uses the GetEX method as users can be members of more than one group making the memberOf attribute of the user a multivalued attribute. (Basically a user can belong to more than one group and since memberOf is the attribute specifying group membership, it may have more than one value requiring the use of GetEX instead of simply Get which is used for single values.
- Check to see if ADSI raised the error mentioned earlier specifying no group membership. If no error is raised, display the memberships of the user.
'-- Lists group membership of all users within the
'-- specified container. Note - This script will generate
'-- A LOT of data and is best run using cscript.
'=========================================================
'=========================================================
'On Error Resume Next
'-- Uncomment the previous line to suppress ADSI run-time
'-- errors as they occur.
'-- Number value of the error return by ADSI if the
'-- memberOf attribute cannot be found.
'==================================================
Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D
'-- Bind to the Users container
'==============================
Set objOU = GetObject _
("LDAP://cn=Users,dc=mydomain,dc=com")
'-- Initialize the array for user accounts.
'==========================================
ObjOU.Filter= Array("user")
'-- Control Loop
'===============
For Each objUser in objOU
Wscript.Echo objUser.cn & " is a member of: "
Wscript.Echo vbTab & "Primary Group ID: " & _
objUser.Get("primaryGroupID")
'-- Use the GetEX method to intialize the array for group
'-- membership. Get method cannot be used as it does not
'-- multivalued attributes (user can be member of many groups.)
'==============================================================
arrMemberOf = objUser.GetEx("memberOf")
'-- If the error is not raised from ADSI, then list the
'-- groups that are entries within the arrMemberOf array.
'-- If error is raised, display notification on screen.
'========================================================
If Err.Number <> E_ADS_PROPERTY_NOT_FOUND Then
For Each Group in arrMemberOf
Wscript.Echo vbTab & Group
Next
Else
Wscript.Echo vbTab & objUser.cn & " is not a member of any groups."
Err.Clear
End If
Next
Determine when a user password was last set.
- Bind to the user object in Active Directory
- Read the passwordLastChanged attribute and display results.
'-- Determine when a user password was last set
'==============================================
oUser = "John Smith"
Set objUser = GetObject _
("LDAP://cn=" & oUser & ",cn=Users,dc=mycompany,dc=com")
oPassVal = objUser.PasswordLastChanged
Wscript.Echo "Password was last set: " & oPassVal
Setting multiple values for multiple user accounts within a single container.
This example might be used if a company was acquired requiring a company name change and email address change.
- Bind to the container containing the user accounts to be modified.
- Initialize the dynamic array.
- Using a control loop…
- Change the company attribute of each user in the array to the name of the new company; in this example… NewCompany.
- Change the email address of each user in the array by concatenating (bringing together) the mailNickName attribute of the user and appending @NewCompany.com to the end.
- Set the information in Active Directory.
- Change the company attribute of each user in the array to the name of the new company; in this example… NewCompany.
- Change the email address of each user in the array by concatenating (bringing together) the mailNickName attribute of the user and appending @NewCompany.com to the end.
- Set the information in Active Directory.
'-- Set multiple values for multiple accounts within
'-- a common Active Directory container.
'===================================================
'-- Change this path to reflect appropriate information.
'=======================================================
Set objOU = GetObject _
("LDAP://cn=Users,dc=mycompany,dc=com")
objOU.Filter = Array("user")
'-- Modify NewCompany and @NewCompany.com to reflect
'-- the appropriate information.
'===================================================
For Each objUser In objOU
WScript.Echo "Modified " & objUser.Name
objUser.Put "company", "NewCompany"
objUser.Put "mail", mailNickname & "@NewCompany.com"
objUser.SetInfo
WScript.Echo "The new company name is: " & _
objUser.Get("company")
WScript.Echo "The new email address is: " & _
objUser.Get("mail")
Next
Additional Code Snippets
This page is simply several different snippets of code that can be used in administering users and groups as well as an example of how VBScript can be used in logon scripting in place of batch files. The code snippets are small, easy to understand, and can be combined to create a larger script performing multiple administrative functions.
'-- Set new value for Maximum Bad Passwords Allowed
'==================================================
DomainName = "Your_Domain"
Set Domain = GetObject("WinNT://" & DomainName)
NewValue = 3 'Change this
Domain.MaxBadPasswordsAllowed = NEW_VALUE
Domain.SetInfo
'-- Set a new value for Maximum Password Age
'===========================================
DomainName = "Your_Domain"
Set Domain = GetObject("WinNT://" & DomainName)
NewValue = 2592000 'Change this
Domain.MaxPasswordAge = NewValue
Domain.SetInfo
'-- Set new value for Minimum Password Age
'=========================================
DomainName = "Your_Domain"
Set Domain = GetObject("WinNT://" & DomainName)
NewValue = 3 'Change this
Domain.MinPasswordAge = NewValue
Domain.SetInfo
'-- Set new value for Minimum Password Length
'============================================
DomainName = "Your_Domain"
Set Domain = GetObject("WinNT://" & DomainName)
NewValue = 6 'Change this
Domain.MinPasswordLength = NewValue
Domain.SetInfo
'-- Set new value for Password History
'=====================================
DomainName = "Your_Domain"
Set Domain = GetObject("WinNT://" & DomainName)
NewValue = 5 'Change this
Domain.PasswordHistoryLength = NewValue
Domain.SetInfo
'-- Enumerate computer accounts within a container
'=================================================
ContainerName = "LDAP_path_to_container"
Set Container = GetObject("LDAP://" & ContainerName)
Container.Filter = Array("Computer")
For Each Computer in Container
WScript.Echo Computer.Name
Next
'-- Enumerate user accounts within a container
'=============================================
ContainerName = "LDAP_path_to_container"
Set Container = GetObject("LDAP://" & ContainerName)
Container.Filter = Array("User")
For Each User in Container
WScript.Echo User.Name
Next
'-- Enumerate groups within a container
'======================================
ContainerName = "LDAP_path_to_container"
Set Container = GetObject("LDAP://" & ContainerName)
Container.Filter = Array("Group")
For Each Group in Container
WScript.Echo Group.Name
Next
'-- Rename a computer account
'============================
oldPC = "Current_name_of_PC"
newPC = "New_name_of_PC"
PCPath = "LDAP_path_container_PC_resides_within"
Set objNewOU = GetObject("LDAP://" & PCPath)
Set objMoveComputer = objNewOU.MoveHere _
("LDAP://CN=" & oldPC & ", OU=MIS,DC=mycompany,DC=com", _
& newPC)
'-- Create a new group
'=====================
NewGroup = "Enter_new_group_name"
Set objOU = GetObject("LDAP://ou=MIS,dc=mycompany,dc=com")
Set objGroup = objOU.Create("group", "cn=" & NewGroup)
objGroup.Put "sAMAccountName", NewGroup
objGroup.SetInfo
'-- Enumerating all disabled user accounts in a container
'-- and list results in a text file.
'========================================================
Const ADS_UF_ACCOUNTDISABLE = 2
Set FSO = CreateObject("Scripting.FileSystemObject")
Set outfile = FSO.OpenTextFile("C:\Scripts\AcctDisabled.txt", 2, True)
ContainerName = "LDAP_path_to_container"
Set Container = GetObject("LDAP://" & ContainerName)
Container.Filter = Array("User")
For Each User in Container
intUAC = User.Get("userAccountControl")
If intUAC AND ADS_UF_ACCOUNTDISABLE Then
outfile.writeline User.Name & " is disabled"
End If
Next
'-- Unlocking a user account
'===========================
UserPath = "LDAP_path_to_container"
UserName = "User_CN_name" 'i.e. John Smith
Set User = GetObject("LDAP://"& UserName & UserPath ,user")
If User.IsAccountLocked = True Then
User.IsAccountLocked = False
User.SetInfo
End If
'-- Enumerate user account expiration information
'================================================
On Error Resume Next
UserPath = "LDAP_path_to_container"
UserName = "User_CN_name" 'i.e. John Smith
Set objUser = GetObject("LDAP://" & UserName & UserPath)
dtmAccountExpiration = objUser.AccountExpirationDate
'-- Number and date is recognized standard for expired accounts.
If err.number = -2147467259 Or dtmAccountExpiration = "1/1/1970" Then
WScript.echo "Account is set to never expire."
Else
WScript.echo "Account expiration: " & objUser.AccountExpirationDate
End If
'-- Forcing Logoff and Computer Shutdown
'=======================================
'0 - Logoff
'1 - Shutdown
'2 - Reboot
'4 - Forced Logoff
'5 - Forced Shutdown
'6 - Forced Reboot
'8 - Power Off
'12 - Forced Power Off
Const SHUTDOWN = 1 'Change to reflect method
strComputer = "." 'Change to relect computer
Set objWMIService = GetObject("winmgmts: {(Shutdown)}" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery _
("SELECT * FROM Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
ObjOperatingSystem.Win32Shutdown(SHUTDOWN)
Next
'-- Example Logon Script
'===============================================
'-- This script maps drives, checks for the existence of SMS and
'-- launches the SMS client installation if it does not exist as
'-- well as logging the computer name to a network text file, automates
'-- the installation of anti-virus via network installation (in this
'-- example, Trend Micro), checks for a RAS connection and bypasses
'-- A/V installation if present, and checks certain computer names
'-- to bypass installations on servers that should be skipped (i.e.
'-- Terminal Servers).
'
'-- Obviously, this would require a bit of modification to tailor to
'-- different environments, but it does illustrate how VBScript can
'-- be used in Logon Scripting instead of batch files.
'===============================================
On Error Resume Next
'-- Set variables --
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = Wscript.CreateObject("WScript.Network")
Set colWinDir = objShell.Environment("System")
Set outfile = objFSO.OpenTextFile("\\ServerA\public\sms\" _
& objNetwork.ComputerName & ".txt", 8, True)
' === START SUBROUTINES ===
' -- SMSSub SubRoutine --
Sub SMSSub
objNetwork.MapNetworkDrive "X:", "\\ServerA\public"
WinTemp = colWinDir("WINDIR")
objBin = WinTemp & "\ms\sms\core\bin\"
objBinA = WinTemp & "\ms\sms\clicomp\apa\bin\"
objBinB = WinTemp & "\ms\sms\clicomp\hinv\"
objBinC = WinTemp & "\ms\sms\clicomp\sinv\"
objBinD = WinTemp & "\ms\sms\clicomp\swdist32\bin\"
If objFSo.FileExists(objBin & "clicore.exe") Then
WScript.Sleep 100
Else SMSCompLog
End If
If objFSo.FileExists(objBinA & "smsapm32.exe") Then
WScript.Sleep 100
Else SMSCompLog
End If
If objFSo.FileExists(objBinB & "hinv32.exe") Then
WScript.Sleep 100
Else SMSCompLog
End If
If objFSo.FileExists(objBinC & "sinv32.exe") Then
WScript.Sleep 100
Else SMSCompLog
End If
If objFSo.FileExists(objBinD & "smsmon32.exe.exe") Then
WScript.Sleep 100
Else SMSCompLog
End If
WScript.Quit
End Sub
' -- SMSCompLog SubRoutine --
Sub SMSCompLog
outfile.writeline "SMS components not installed properly on " _
& objNetwork.ComputerName & vbCrLf
objShell.Run "\\DC-01\netlogon\smsls.bat",,True
End Sub
' === END SUBROUTINES ===
' === BEGIN MAIN SCRIPT ===
'-- Remove Current mapped drives --
objNetwork.RemoveNetworkDrive "F:"
objNetwork.RemoveNetworkDrive "G:"
objNetwork.RemoveNetworkDrive "P:"
objNetwork.RemoveNetworkDrive "V:"
'-- Map Network Drives --
objNetwork.MapNetworkDrive "F:", "\\FS-01\public"
objNetwork.MapNetworkDrive "G:", "\\FS-01\group"
objNetwork.MapNetworkDrive "P:", "\\FS-01\apps"
objNetwork.MapNetworkDrive "V:", "\\FS-01\data"
'-- Check for Terminal Servers and call Subroutine --
If objNetwork.ComputerName = "TERM-SVR-01" Then
WScript.Quit
ElseIf objNetwork.ComputerName = "TERM-SVR-02" Then
WScript.Quit
ElseIf objNetwork.ComputerName = "TERM-SVR-03" Then
WScript.Quit
Else WScript.Sleep 100
End If
'-- Check for RAS using the CheckRAS utility from --
'-- the Resource Kit. --
objShell.Run "\\DC-01\netlogon\checkras.exe",,True
If Err.Number = 1 Then
SMSSub
Else objShell.Run "\\AV-SVR-01\ofcscan\autopcc"
End If
Err.Clear
SMSSub
WScript.Quit