Thanks, that really helped.
> Hi,
> You should not be using the PutEx method to set attribute values (unless the
> attribute is multi-valued, and none of the ones you deal with are). You
> should use the Put method. Replace:
> oUser.PutEx 2, "displayName", Array(aCSVArgs(4))
> with:
> oUser.Put "displayName", aCSVArgs(4)
> When displayName has a space, the Array function converts it to two entries,
> and there cannot be two entries for the displayName attribute. I'm surprised
> it works when there are no spaces.
> If no value is specified for an attribute, why not just skip it? I don't
> think it would be wise to set the value to Chr(34). If you want to "blank"
> out an attribute, use this instead:
> Const ADS_PROPERTY_DELETE = 4
> oUser.PutEx ADS_PROPERTY_DELETE, "displayName", 0
> In fact, I often use code like this:
> If UCase(Trim(aCSVargs(4))) = ".DELETE" Then
> oUser.PutEx ADS_PROPERTY_DELETE, "displayName", 0
> Else if Trim(aCSVArgs(4)) <> "" Then
> oUser.Put "displayName", Trim(aCSVArgs(4))
> End If
> Next, you have a lot of SetInfo statements. There is a tradeoff here.
> Everytime you do a SetInfo it takes time to flush the cache and update AD
> over the network. It is much faster to make many changes and then SetInfo at
> the end. The downside is that if there is an error, you don't know which
> attribute caused it - it could be any attribute updated since the last
> SetInfo. I generally compromise and update several attributes at a time,
> then SetInfo.
> Finally, you are going to a lot of trouble to retrieve the distinguishedName
> of each user from the sAMAccountName. One ADO search to find the DN of one
> user is one thing, but to repeat it many times seems inefficient. You might
> want to use the NameTranslate object instead:
> strNetBIOSDomain = "MyDomain"
> Set objTrans = CreateObject("NameTranslate")
> strNTName = "TestUser" ' sAMAccountName of user
> objTrans.Init 1, strNetBIOSDomain
> objTrans.Set 3, strNetBIOSDomain & "\" & strNTName
> strUserDN = objTrans.Get(1)
> Set oUser = GetObject("LDAP://" & strUserDN)
> In your script, this might look like this:
> Set objRootDSE = GetObject("LDAP://RootDSE")
> strDNSDomain = objRootDSE.Get("defaultNamingContext")
> ' Use the NameTranslate object to find the NetBIOS domain name from the
> ' DNS domain name.
> Set objTrans = CreateObject("NameTranslate")
> objTrans.Init 3, strDNSDomain
> objTrans.Set 1, strDNSDomain
> strNetBIOSDomain = objTrans.Get(3)
> strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)
> objTrans.Init 1, strNetBIOSDomain
> do until fCSVfile.AtEndOfStream
> sLine = fCSVfile.ReadLine
> aCSVargs = split(sLine, ",")
> objTrans.Set 3, strNetBIOSDomain & "\" & aCSVArgs(0)
> strUserDN = objTrans.Get(1)
> Set oUser = GetObject("LDAP://" & strUserDN)
> ...
> I hope this helps.
> --
> Richard
> Microsoft MVP Scripting and ADSI
> http://www.rlmueller.net
> --
>>I would appreciate some assistance with the script below. I wrote this
>>to update user accounts in AD using a CSV file. It works, but errors
>>out if there are spaces in certain fields, such as the 'display name'.
>>Any help/comments is appreciated.
>>TIA
>>-------------------------
>>On Error Resume Next
>>Const OpenAsDefault = -2
>>Const OpenAsASCII = 0
>>Const OpenAsUnicode = -1
>>Const CreateIfNotExist = -1
>>Const ForReading = 1
>>Const FailIfNotExist = 0
>>Const ForWriting = 2
>>Const ForAppending = 8
>>Dim strNTPath, strQuery
>>Dim oDirObject, oUser
>>Dim aCSVargs, test
>>Set aCon = CreateObject("ADODB.Connection")
>>Set aCmd = CreateObject("ADODB.Command")
>>Set oFS = CreateObject("Scripting.FileSystemObject")
>>Set oRootDSE = GetObject("LDAP://RootDSE")
>>Set oMyDomain = GetObject("LDAP://" &
> oRootDSE.Get("defaultNamingContext"))
>>aCon.Provider = "ADsDSOObject"
>>aCon.Open
>>aCmd.ActiveConnection = aCon
>>Set oFSO = CreateObject("Scripting.FileSystemObject")
>>sCSVFile = wscript.arguments.item(0)
>>if oFSO.FileExists(sCSVFile) then
>>err.clear
>>set fCSVfile =
>>oFSO.OpenTextFile(sCSVFile,ForReading,FailIfNotExist,TristateUseDefault)
>>If Err Then
>>WScript.Echo(Err.Number & " - " & Err.Description)
>>WScript.Quit
>>End If
>>Else
>>WScript.Echo("File: " & sCSVFile & " does not exist.")
>>WScript.Quit
>>end if
>>do until fCSVfile.AtEndOfStream
>>sLine = fCSVfile.ReadLine
>>aCSVargs = split(sLine, ",")
>>aCmd.CommandText = "<LDAP://" & oMyDomain.distinguishedname &
>>">;(&(objectClass=user)(SamAccountName=" & aCSVArgs(0) &
>>"));distinguishedName;subTree"
>> aCmd.Properties("Page Size") = 500
>> Err.Clear
>> Set aRst = aCmd.Execute()
>> If Err Then
>> wscript.echo( "Error: Couldn't execute query in AD.")
>> wscript.echo( "Error: " & Err.Number & " " & Err.Description)
>> WScript.Quit(2)
>> End If
>> Err.Clear
>> Set oUser = GetObject("LDAP://" & aRst.Fields("distinguishedName"))
>> If Err Then
>> wscript.echo( "Error: Couldn't find username in AD.")
>> wscript.echo( "Error: " & Err.Number & " " & Err.Description)
>> WScript.Quit(2)
>> End If
>> oUser.GetInfo
>>If aCSVargs(1) = "" Then
>>oUser.put "givenName", Chr(32)
>>else
>> oUser.PutEx 2, "givenName", Array(aCSVArgs(1))
>> End If
>> oUser.SetInfo
>> If aCSVargs(2) = "" Then
>> oUser.Put "initials", Chr(32)
>> else
>> oUser.PutEx 2, "initials", Array(aCSVArgs(2))
>> end If
>> oUser.SetInfo
>> If aCSVargs(3) = "" Then
>> oUser.Put "sn", Chr(32)
>> else
>> oUser.PutEx 2, "sn", Array(aCSVArgs(3))
>> End If
>> oUser.SetInfo
>>If aCSVargs(4) = "" Then
>>oUser.Put "displayName", Chr(32)
>>else
>> 'oUser.PutEx 2, "displayName", Array(aCSVArgs(4))
>> set oContainer = GetObject(oUser.Parent)
>>oContainer.MoveHere oUser.AdsPath, "cn=" & aCSVArgs(4)
>> End If
>> oUser.SetInfo
>>If aCSVargs(5) = "" Then
>>oUser.Put "physicalDeliveryOfficeName", Chr(32)
>>else
>> oUser.PutEx 2, "physicalDeliveryOfficeName", Array(aCSVArgs(5))
>> End If
>> oUser.SetInfo
>>If aCSVargs(6) = "" Then
>>oUser.put "telephoneNumber", Chr(32)
>>else
>> oUser.PutEx 2, "telephoneNumber", Array(aCSVArgs(6))
>> End If
>> oUser.SetInfo
>>Loop
>>fCSVfile.Close
>>----------------------------