OPTION EXPLICIT ' Variables must be declared ' ************************************************* ' * Instructions ' ************************************************* ' Edit the variables in the "Setup" section as required. ' Run this script from a command prompt in cscript mode. ' e.g. cscript usermod.vbs ' You can also choose to output the results to a text file: ' cscript usermod.csv >> results.txt ' ************************************************* ' * Constants / Decleration ' ************************************************* Const adOpenStatic = 3 Const adLockOptimistic = 3 Const adCmdText = &H0001 Const ADS_PROPERTY_CLEAR = 1 DIM strSearchAttribute DIM strCSVHeader, strCSVFile, strCSVFolder DIM strAttribute, userPath, csvHasHDR DIM searchAttributePos,pos,userChanges DIM cn,cmd,rs DIM objUser DIM oldVal, newVal ' ************************************************* ' * Setup ' ************************************************* ' The Active Directory attribute that is to be used to match rows in the CSV file to ' Active Directory user accounts. It is recommended to use unique attributes. ' e.g. sAMAccountName (Pre Windows 2000 Login) or userPrincipalName ' Other attributes can be used but are not guaranteed to be unique. If multiple user ' accounts are found, an error is returned and no update is performed. strSearchAttribute = "sAMAccountName" 'User Name (Pre Windows 2000) ' Change the CSV header to match your CSV file ' See http://www.wisesoft.co.uk/Scripts/activedirectoryschema.aspx for attribute names ' The searchAttribute specified above must appear in the list. ' You can enter "null" for columns in the csv that are not to be included in the update strCSVHeader = "sAMAccountName,givenName,initials,sn,displayName,description,physicalDeliveryOfficeName," & _ "telephoneNumber,mail,wWWHomePage,cn" ' Folder where CSV file is located strCSVFolder = "C:\" ' Name of the CSV File strCSVFile = "usermod.csv" ' Does the CSV text file have a header row? Options: "Yes", "No" csvHasHDR = "No" ' ************************************************* ' * Validation ' ************************************************* ' Find the position of the search attribute column in the CSV file searchAttributePos = -1 pos = 0 for each strAttribute in SPLIT(strCSVHeader,",") if strAttribute = strSearchAttribute then searchAttributePos = pos end if pos = pos + 1 next ' Make sure the search attribute exists in the CSV header. if searchAttributePos = -1 then err.raise "'" & strSearchAttribute & "' attribute must be specified in the CSV header." & _ vbcrlf & "The attribute is used to map the data the csv file to users in Active Directory." end if ' ************************************************* ' * Start Script ' ************************************************* ' Setup ADO Connection to CSV file Set cn = CreateObject("ADODB.Connection") Set rs = CreateObject("ADODB.Recordset") cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & strCSVFolder & ";" & _ "Extended Properties=""text;HDR=" & csvHasHDR & ";FMT=Delimited""" rs.Open "SELECT * FROM [" & strCSVFile & "]", _ cn, adOpenStatic, adLockOptimistic, adCmdText ' Read CSV File Do Until rs.EOF ' Get the ADsPath of the user by searching for a user in Active Directory on the search attribute ' specified, where the value is equal to the value in the csv file. ' e.g. LDAP://cn=user1,cn=users,dc=wisesoft,dc=co,dc=uk userPath = getUser(strSearchAttribute,rs(searchAttributePos)) ' Check that an ADsPath was returned if LEFT(userPath,6) = "Error:" then wscript.echo userPath else wscript.echo userPath ' Get the user object set objUser = getobject(userpath) pos = 0 userChanges = 0 ' Update each attribute in the CSV string for each strAttribute in SPLIT(strCSVHeader,",") oldval = "" newval = "" ' Ignore the search attribute (this is used only to search for the user account) if strAttribute <> strSearchAttribute and strAttribute <> "null" then newVal = rs(pos) ' Get new attribute value from CSV file if ISNULL(newval) then newval = "" end if ' Special handling for common-name attribute. If the new value contains ' commas they must be escaped with a forward slash. if strAttribute = "cn" then newVal = REPLACE(newVal,",","\,") end if IF LCASE(strAttribute) = "manager_samaccountname" THEN ' special handling to allow update of manager attribute using sAMAccountName (UserName) ' instead of using the distinguished name DIM objManager, managerPath managerPath = GetUser("sAMAccountName",newVal) IF LEFT(managerPath,6) = "Error:" THEN wscript.echo "Error resolving manager DN:" & managerPath ' Set oldval = newval (don't update) oldval = "" newval = "" ELSE SET objManager = GetObject(managerPath) newVal = objManager.Get("distinguishedName") SET objManager = NOTHING strAttribute = "manager" on error resume next ' Ignore error if value is null ' Get old attribute value oldVal = objUser.Get(strAttribute) on error goto 0 END IF ELSE on error resume next ' Ignore error if value is null ' Get old attribute value oldVal = objUser.Get(strAttribute) on error goto 0 END IF ' Check if the value has changed if oldval <> newval then wscript.echo "Change " & strAttribute & " from '" & oldVal & "' to '" & newVal & "'" if newval = "" then ' Special handling to clear an attribute objUser.PutEx ADS_PROPERTY_CLEAR, strAttribute, null else SELECT CASE LCASE(strAttribute) CASE "cn" 'Special handling required for common-name attribute DIM objContainer set objContainer = GetObject(objUser.Parent) on error resume next objContainer.MoveHere objUser.ADsPath,"cn=" & newval ' The update might fail if a user with the same common-name exists within ' the same container (OU) if err.number <> 0 then wscript.echo "Error changing common-name from '" & oldval & "' to '" & newval & _ "'. Check that the common-name is unique within the container (OU)" err.clear end if on error goto 0 CASE ELSE ' Any other attribute ' Update attribute objUser.put strAttribute,newVal END SELECT end if ' Used later to check if any changes need to be committed to AD userChanges = userChanges + 1 end if end if ' Keeps track of current attribute position in the CSV string pos = pos + 1 next ' Check if we need to commit any updates to AD if userChanges > 0 then ' Allow script to continue if an update fails on error resume next err.clear ' Save Changes to AD objUser.setinfo ' Check if update succeeded/failed if err.number <> 0 then wscript.echo "Commit Changes: Failed. " & err.description err.clear else wscript.echo "Commit Changes: Succeeded" end if on error goto 0 else wscript.echo "No Changes" end if end if userPath = "" rs.MoveNext Loop ' Cleanup rs.close cn.close ' ************************************************* ' * Functions ' ************************************************* Function getUser(Byval strSearchAttribute,strSearchValue) ' Function to return the ADsPath of a user account by searching ' for a particular attribute value ' e.g. LDAP://cn=user1,cn=users,dc=wisesoft,dc=co,dc=uk DIM objRoot DIM getUserCn,getUserCmd,getUserRS on error resume next set objRoot = getobject("LDAP://RootDSE") set getUserCn = createobject("ADODB.Connection") set getUserCmd = createobject("ADODB.Command") set getUserRS = createobject("ADODB.Recordset") getUserCn.open "Provider=ADsDSOObject;" getUserCmd.activeconnection=getUserCn getUserCmd.commandtext=";" & _ "(&(objectCategory=person)(objectClass=user)(" & strSearchAttribute & "=" & strSearchValue & "));" & _ "adsPath;subtree" set getUserRs = getUserCmd.execute if getUserRS.recordcount = 0 then getUser = "Error: User account not found" elseif getUserRS.recordcount = 1 then getUser = getUserRs(0) else getUser = "Error: Multiple user accounts found. Expected one user account." end if getUserCn.close end function