Modify Group attributes using CSV input file.

Good evening,

I think I have wasted enough of one day. I have not been able to find any script close to this, except for modification of user accounts. There are vague references to Powershell solutions which will be great if that is what is needed, but I am hoping for a VBS solution. I am being put into a situation where I am essentially being forced to learn scripting.

I need to edit this to use the sAMAccountNames in the input file to query over 1,700 groups (distribution lists) and MODIFY the displayName, distinguishedName, CN, as well as the sAMAccountName. The output file results in generated text but it seems it is simply output; not an indication that groups were modified. The displayNames are blank currently but the distinguishedNames and the sAMAccountNames have values. I was told that after querying for the sAMAccountName, I could change the line or add a line to query and bind to for CN, in order to modify the sAMAccounNames.

Ideally, I need to remove the "z-" that is used to begin the sAMAccountNames as well as the DN, and CN for all these groups and then use the sAMAccountNames to write the vaules for displayNames with (XXXX) after them.. and then "establish email addresses" by specifying the second part of the SMTP address to be But I would be content for now just to get a solution for the first paragraph. Thank you!

Dim objConnection,objCommand,objRootLDAP,strDNSDomain,strUserorMachine
DIM OldName

On Error Resume Next

'file constants
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

'LDAP Constants

Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"

Set objCommand =   CreateObject("ADODB.Command")
Set objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000

Set objRootLDAP = GetObject("LDAP://RootDSE")
strDNSDomain = objRootLDAP.Get("DefaultNamingContext")

'Here read from the source file to get a sAMAccountName and then loop for each one

strInputFile = inputbox("Please enter the Mapping File", "Input")
'This will be the extract of sAMAccountName

strOutputFile = inputbox("Please enter the Output File", "Input")
'This will be the resulting output file that contains the Accounts processed

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile(strInputFile, ForReading)
Set objFile = objFSO.GetFile(strInputFile)

If objfso.fileexists(strinputfile) then

Set objCreateFile = objFSO.CreateTextFile(strOutputFile)

'check to see if the file is empty
If objFile.Size > 0 Then
Do Until objTextFile.AtEndOfStream
    strNextLine = objTextFile.Readline
    arrUidList = Split(strNextLine , "*")

'here we set the ldap query

objCommand.CommandText= "<LDAP://dc=XXX,dc=XXXXX,dc=XXX>; (&(objectclass=group)(sAMAccountName=" & arrUidList(0) & ")); name,cn,distinguishedName,displayName;subtree"

Set ObjRecordSet = objCommand.Execute

'Bind using distinguishedName

While Not objRecordSet.EOF

'go to the next looked up uid but there should never be one

'Enable the Account

set objUser = GetObject("LDAP://" & strUserDN)

'can set the displayName to specified value in file
'objuser.displayname= arrUidList(1)

'this appends a value to existing displayName
'be sure and test with sample file                                  

'option to update sAMAcountName using second column in mapping file

OldName = objuser.displayname
objuser.displayname = OldName & " (XXXX)"
OldNamecn = = OldNamecn & " (XXXX)"

Set objOutputFile = objFSO.OpenTextFile(strOutputFile, ForAppending, True)
'Here we would output the variables that we looked up

objOutputFile.WriteLine(strcovname & "," & objuser.displayname & "," &

OldName = ""
OldNamecn = ""
arrUidList = ""

'end of read loop

'finalize the connection

' if the file was empty let us know
    Wscript.Echo "The file is empty."
End If

Wscript.echo "Accounts Updated!"

    Wscript.Echo "Mapping file does not exist."
End If
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

yo_beeDirector of Information TechnologyCommented:
So if I am understanding your situation.
You want to change DN,SAM and CN?
So you want to query all users and replace ZZZZ with XXXX.
What error and line is this failing?
kontrariankidAuthor Commented:
Good morning yo_bee. Thanks for replying. For clarification, I just placed the XXXXs to keep company identity hidden. Actually, the DN, SAM, and CNs do have values such as "z-Brambleton" for example. So the values for attributes DN, SAM, and CN are all the same, say "z-Brambleton". After all is complete, this is what needs to happen:

distinguishedName = CN=Brambleton (XXXX),OU=XXXX,OU=Distribution Lists,OU=Enterprise Production,DC=xxx,DC=xxxxxx,DC=xxx
cn = Brambleton (XXXX)
displayName = Brambleton (XXXX)
sAMAccountName = Brambleton

So of the four, the displayName is currently the only empty attribute and needs to be populated with the same value of the SAM + (XXXX). In other words, I need to concatenate or append " (XXXX)" to each of the displayNames AND the CNs, so the old names for example "z-Brambleton" must become "Brambleton (XXXX)".

Lastly, I need to email enable-enable these, same as right-clicking, Exchange tasks, Establish E-mail Address on Groups. The SMTP address would become

I will try to keep on top of this today to provide any further feedback for you in case you are not sleeping at this time. Thank you.
yo_beeDirector of Information TechnologyCommented:
is your Domain XXXXXX.XXX?
Big Business Goals? Which KPIs Will Help You

The most successful MSPs rely on metrics – known as key performance indicators (KPIs) – for making informed decisions that help their businesses thrive, rather than just survive. This eBook provides an overview of the most important KPIs used by top MSPs.

kontrariankidAuthor Commented:
The domain is the entire (Actually, the SMTP suffix needs to be "" whereas it defaults to when email-enabling an account manually.) Also, looking again at your reply last night, the script does not appear to fail, because it writes to the output text file, but it DOES FAIL because it is not updating the three test accounts I have in the input file.

INPUT FILE, example:

OUTPUT FILE, example:
z-Brambleton, (XXXX),z-Brambleton (XXXX)
z-Crambleton, (XXXX),z-Crambleton (XXXX)
z-Drambleton, (XXXX),z-Drambleton (XXXX)

Brambleton,Brambleton (XXXX),Brambleton (XXXX)
Crambleton,Crambleton (XXXX),Crambleton (XXXX)
Drambleton,Drambleton (XXXX),Drambleton (XXXX)

I think this is in the format of "name, displayName, cn", based on this line:
objOutputFile.WriteLine(strcovname & "," & objuser.displayname & "," &
Is that correct? And what is "name" attribute exactly?
yo_beeDirector of Information TechnologyCommented:
What I am asking is if the XXX are real part of the DC=,DC= or is it just a replacement for posting on this forum?
yo_beeDirector of Information TechnologyCommented:
The original question that I inquired was does it error and if so what line?
kontrariankidAuthor Commented:
Ah. No it is not real.. the xxx's are for concealment purposes since this is publicly accessible.
yo_beeDirector of Information TechnologyCommented:
can you use as the domain?
kontrariankidAuthor Commented:
Ok. Sure. And no, it does not error. Refer to my comment Posted on 2012-04-10 at 10:25:55ID: 37827889
yo_beeDirector of Information TechnologyCommented:
Name is the how AD/LDAP displays it in the MMC.

For example:
Display name is  SN, & CN
Where Name could be CN & SN
kontrariankidAuthor Commented:
Ah. So 'name' is a combination of attributes, even though it is also itself an attribute? Makes sense. Any thoughts as to why the script is not modifying the intended accounts as provided by the input text file?
yo_beeDirector of Information TechnologyCommented:
Not 100% sure.
I know when you create a new user object in AD the wizard asks for the First, Middle Initial and Last.
during this process you will notice that the Full Name field is populated.
This populated field are the same initial values as Display Name and Name and CN.

You can change the display name to be Last, First (which is SN, CN)
This will not change the Name attribute.

You can also have the Full name default to SN, CN by modifying the Schema User object.  This is would then by default set the displayname, CN and Name to SN, CN.
kontrariankidAuthor Commented:
Hmm. Those are not available options. I cannot change anything to do with Schema or the way that displayName is defined. Our domain services over 70 different organizations and the OPS team handles such tasks anyhow. I am a part of the migration team.
yo_beeDirector of Information TechnologyCommented:
Once the DisplayName or Name is created it will not use the CN or SN values.
They are their own attribute at that point.

So you are looking to create a CSV file with the audit of the original DN, CN and Name then update the values and then append those values.

Is that correct?
kontrariankidAuthor Commented:
Yes. That sounds correct; although the displayName and cn are appended only with the " (XXXX)", as should be specified by these lines:

OldName = objuser.displayname
objuser.displayname = OldName & " (XXXX)"
OldNamecn = = OldNamecn & " (XXXX)"
yo_beeDirector of Information TechnologyCommented:
You want the (xxx)  brackets in the name.  
I am not sure how this will work.
I will test on when I get home.
kontrariankidAuthor Commented:
Yes. Output should be in this format.. Brambleton, followed by one space and then the (XXXX), like so..

Brambleton,Brambleton (XXXX),Brambleton (XXXX)
Crambleton,Crambleton (XXXX),Crambleton (XXXX)
Drambleton,Drambleton (XXXX),Drambleton (XXXX)
kontrariankidAuthor Commented:
you_bee, Thanks for your diligent efforts. At this point, I don't care what script type is used. Whether it is PS, VB, batch.. as long as it reads from an input file and actually modify the DLs to desired output per above details.
yo_beeDirector of Information TechnologyCommented:
I will get you something by morning?
yo_beeDirector of Information TechnologyCommented:
He is the primarily script for testing output.
This will output to the command windows.
to run this first copy the script to a text editor and save as a VBS file.
Then open CMD and run: cscript scriptname.vbs >c:\output.csv
once confirmed then we can work on the manipulation of the attributes.

Dim oShell
Set oShell = WScript.CreateObject ("WScript.Shell")

Dim objRootDSE
Dim objSchemaContainer
Dim strSchemaPath
Dim objConnection
Dim ojRS
Dim StrAttr
Dim strLDAP
        Dim objConn 'ADO Connection object
        Dim objRS 'ADO Recordset object
        Dim strAlt ' As Boolean
        Dim strName, StrADs, strclass
        Dim strSam, strobjFilter, strattrFilter 
        Dim objWMIService, objitem, objUser
'Get the Root DSE from a random DC
Set objRootDSE = GetObject("LDAP://RootDSE")

'Connect to the schema container on a random DC
strDNSDomain = objRootDSE.Get("defaultNamingContext")

wscript.echo strDNSDomain
wscript.echo "CN,Name,DN,NewDN"       
 'Makes a connection to AD using ADODB (ADSI)
       set objConnection = CreateObject("ADODB.Connection")
       Set objCommand = CreateObject("ADODB.Command")
       objConnection.Provider = "ADsDSOObject"
       objConnection.Open("Active Directory Provider")
       objCommand.ActiveConnection = objConnection

'Gather users
Strfilter=inputbox("Enter what group you want to filter" & vbcrlf & _
"Note: * is used for wildard characters" & vbcrlf & _
"example: z-*") 

Set objRS  = objConnection.Execute("<LDAP://" & strDNSDomain & ">;(&(objectCategory=group)(name=" & Strfilter & ")" _
& "(objectClass=group));Name,ADsPath,cn,distinguishedName;SubTree")
While Not objRS.EOF
	set ObjUser = GetObject(objRS.Fields.Item("ADsPath").Value)
	Set regEx = New RegExp	
'wscript.echo & vbtab & & vbtab & objuser.distinguishedName
	StroldName =
	StroldDN= objuser.distinguishedName

wscript.echo StrOldname & "," & stroldcn & "," & stroldDN & "," & ReplaceTest(strOldCN, stroldCN & "(xxxx)") 

'objuser.put "name",  stroldName & "(xxxx)"
'objuser.put "cn", stroldCN & "(xxxx)"
	Set objRS = Nothing

Function ReplaceTest(patrn, replStr)
  Dim regEx, str1

  str1 = StroldDN

  ' Create regular expression.
  Set regEx = New RegExp
  regEx.Pattern = patrn
  regEx.IgnoreCase = True

  ' Make replacement.
  ReplaceTest = regEx.Replace(str1, replStr)
End Function

Open in new window

kontrariankidAuthor Commented:
yo_bee, I apologize for the delay. I was instructed to assist with other tasks today. Here is the output that your script produced:

Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

yo_beeDirector of Information TechnologyCommented:
No groups ?
kontrariankidAuthor Commented:
correct. no groups. when the input box popped up, i typed "z-" and hit ok.
yo_beeDirector of Information TechnologyCommented:
are you putting the *?
kontrariankidAuthor Commented:
no. oops! i will try again using z-* in the input popup.
kontrariankidAuthor Commented:
it produced 1,000 lines of output, but i forgot to change the XXXX to the organization code, and it did not put a space in front of the (XXXX). trying to understand what i need to change or undo.
yo_beeDirector of Information TechnologyCommented:
this code just output currently I did not want to run the update portion until the output looks correct.
kontrariankidAuthor Commented:
ok good thing you put that precaution in there. thank you. i see that nothing was modified yet. this is an example of one of the lines of output. when it is complete, it should look something like this: Brambleton (xxxx); not this: Brambleton(xxxx). so this "(xxxx)") should be changed to this right: " (xxxx)") ?

CN=z-Brambleton,z-Brambleton,CN=z-Brambleton,OU=VDOT,OU=Distribution Lists,OU=Enterprise Production,DC=xxx,DC=contoso,DC=com,CN=z-Brambleton(xxxx),OU=VDOT,OU=Distribution Lists,OU=Enterprise Production,DC=xxx,DC=contoso,DC=com
kontrariankidAuthor Commented:
leaving office now. will be home in two hours or so if i need to respond again. thank you yo_bee. i actually already updated most of the groups displayName attribute with the (XXXX), using ADModify. i used this also to add an SMTP address of "" and make that the Primary SMTP address, but it seems that all of the accounts were not updated. many still reflect the old primary SMTP address. it seems "hit and miss". so if i use this script to update all, i will need it to REPLACE the current displayName rather than appending anything which could result in "Brambleton (XXXX) (XXXX)". at any rate, i will still be able to use the script to rename from "z-Brambleton (XXXX)" to "Brambleton (XXXX)" or from "z-Brambleton" to "Brambleton (XXXX)".
yo_beeDirector of Information TechnologyCommented:
Play around with the attributes yourself for a while and see what you can learn from this.
I am here to assist if need be.

The one issue you will with wanting this as a CSV rather than a tab delimited is that the DN will be split.
kontrariankidAuthor Commented:
True! I do not need it to be a CSV. I apologize if I made that impression. Can I use a tab delimited instead? You are referring only to the output though, correct? Also, what changes must be made to the script in order to produce modifications to the groups?
yo_beeDirector of Information TechnologyCommented:
Objuser.put "attribute", value

I would not do that just yet.  I would first change the output file to a tab delimited run a find and  Replace "," with vbtab.
Change the output.csv to output.txt
kontrariankidAuthor Commented:
Do I simply need to replace this portion wscript.echo? But what must it be replaced with? Or maybe you will be providing more input after I discover more?
kontrariankidAuthor Commented:
Ah. Thank you. I do see where you commented out the "Objuser". So "Objuser.put" is actually the command that causes modifications? This was missing from my original script that I posted. Maybe that was a big problem? Or is "Objuser.put" only one modification command?

I see where this...
Objuser.put "attribute", value

Refers to...
'objuser.put "name",  stroldName & " (XXXX)"
'objuser.put "cn", stroldCN & " (XXXX)"

But I do not see "Objuser.setinfo" anywhere in your script. What is that?
yo_beeDirector of Information TechnologyCommented:
how are things going?
Your next step is to build a test.  
Once you click the button you may want to revert back.
Once in place and you run it, you need to know you can get yourself out.

So what I would do now is either build a Virtual Domain.
You can do this with free tools.

Do you have a box you can build it on this would be a good tool for future projects.
If so I would Download Windows Server 2008 R2 with Service Pack 1  trial add the Hyper-V role (Hyper-V Getting Started Guide).

Once you have it built you can use that same trial for your new AD and test your AD attribute project.

If not I would add a Test_OU to your AD and create 5 or so accounts and test on them.

You did have the Put, Setinfo as part of your script, but it was remarked out.

set objUser = GetObject("LDAP://" & strUserDN)

'can set the displayName to specified value in file
'objuser.displayname= arrUidList(1)
kontrariankidAuthor Commented:
Thanks yo_bee. I cannot run anything at the moment because I upset our FIM guy yesterday when using ADModify to update primary SMTP addresses. He was concerned that I might "take down FIM".

I have used VM Workstation before but currently have Windows 7 and do not have local admin rights on my own laptop because until the Security team figures something out for our team. I do have a test workstation in the domain that I can probably install a VM on.

I do have an OU that I can use to isolate for this purpose.

Will let you know when I have the green light to modify more accounts. But I probably will not be able to do anything else until tonight.
yo_beeDirector of Information TechnologyCommented:
What were you updating?
kontrariankidAuthor Commented:
I was updating the primary SMTP address, but using ADModify, it was hit and miss. So I first tried to remove a proxyaddress of, and after confirming on a few accounts thta it was removed, I THEN updated the primary SMTP address with the desired value. I was also able to update displayName on these z- accounts to add " (XXXX)". But it still seemed to be hit and miss.

Now I am being told by OPS that they plan to run processes this weekend, so they are telling me I cannot update the required hundreds of accounts until Monday after COB.

This is the output produced after replacing "," with vbtab:

CN=z-Group_Name      z-Group_Name      CN=z-Group_Name,OU=XXXX,OU=Distribution Lists,OU=Enterprise Production,DC=aaa,DC=constoso,DC=com      CN=z-Group_Name (XXXX),OU=XXXX,OU=Distribution Lists,OU=Enterprise Production,DC=aaa,DC=contoso,DC=com

Is this the line that produces above output?
wscript.echo StrOldname & vbtab & stroldcn & vbtab & stroldDN & vbtab & ReplaceTest(strOldCN, stroldCN & " (XXXX)")

If so, then I can see that this is outputting as such...
Old-name   Old-cn   Old-distinguishedName   (ReplaceTest(stroldCN, stroldCN & " (XXXX)")

                                                      But I am trying to understand the purpose of this function. Is this only for testing purposes?

I need also to update the displayName, so I edited as such ok?

added this line after line 47:
      strolddisplayName = objuser.displayName

and added this line after line 52:
'objuser.put "displayName", strolddisplayName & " (XXXX)"
yo_beeDirector of Information TechnologyCommented:
You can also use Exchange System manager > Policies to push an addition address to all AD objects.

To address the question at hand:
Are you asking what this Replacetest is being used for?

ReplaceTest(strOldCN, stroldCN & " (XXXX)")
kontrariankidAuthor Commented:
Yes sir. I was curious about that ReplaceTest.

I ran your script against only one account and this is the resulting output (without my added line to update displayName):

>cscript EE_Group-Modify.vbs > EE_output.txt
D:\VDOT_DLs\EE_VDOT-DL-Modify.vbs(54, 1) Microsoft VBScript runtime error: Wrong
 number of arguments or invalid property assignment: 'put'

Per above error message, this is line 54 and 55...
yo_beeDirector of Information TechnologyCommented:
Since you are pulling the DN down.

"cn=user1,OU=Test,DC=Contoso,DC=com" how would you change the CN=User1 to CN=user1(xxxx) without affecting the entire string?
That is why were are running this Replace function to read the entire script cache it and the run a replace

Does that make sense
yo_beeDirector of Information TechnologyCommented:
What is your ultimate goal here?
Just to add or replace the smtp address?
kontrariankidAuthor Commented:
> What is your ultimate goal here? Just to add or replace the smtp address?

      I would like to replace one smtp address with another and make the new one the Primary SMTP; although that is not necessary the goal of this posting on EE. It is equally as important so would be a nice plus, but not expected.

> That is why were are running this Replace function to read the entire script cache it and the run a replace. Does that make sense

      Yes. So that is the provision that will update the distinguishedName? I was wondering about that. It was not apparent to me how there was a connection being made to distinguishedName. Is line 63 where that is being done as follows?

      str1 = StroldDN

> You can also use Exchange System manager > Policies to push an addition address to all AD objects.

      Are you referring to the Recipient Update Service? I understand I can right-click and choose "Update Now" but it is not my place to run that as our domain includes more than just the accounts that I am working with. We already have a Recipient Policy for "". Anyhow, RUS should have updated my accounts by now, so I think it needs to be done by script at this point.
kontrariankidAuthor Commented:
yo_bee, per Comment ID: 37843351, I commented out line 54 as follows:


As a result, I did not receive the error mentioned, but the account that I tested was not updated.
yo_beeDirector of Information TechnologyCommented:
I will see what the error  is when I get home
yo_beeDirector of Information TechnologyCommented:
between all the back and forth i lost sight of what attributes you are looking for again

Can you list them?
You might not need to address the DN, but I want make sure.
yo_beeDirector of Information TechnologyCommented:
I think I have been feeding you incorrect info.

We can not use the .put method when dealing with CN renaming.
We need to use the .MoveHere method.

I would try an iron out the MoveHere portion.  You give me all your attributes you would like to change.
Some may MoveHere and some will need the Put method depending on the Attribute you wish to address.
yo_beeDirector of Information TechnologyCommented:
Did you get my last reply?
kontrariankidAuthor Commented:
Hey yo_bee. I'm sorry. I do not remember seeing an email notification that you had replied. The attributes that I need to update are...

      name, cn, sAMAccountName, distinguishedName (unless you discover that it reads from other updated attributes).

This attribute is empty but needs the same value as the others: displayName

Lastly, after I email-enable these DLs, will need to update the Primary SMTP to change from to since it is defaulting to the wrong one.
kontrariankidAuthor Commented:
I just re-ran the script after replacing "put" with "MoveHere" first on line 53 and then on 54 as follows:

>cscript EE_XXXX-DL-Modify.vbs > EE_output.txt
D:\XXXX_DLs\EE_XXXX-DL-Modify.vbs(53, 1) Active Directory: An invalid directory
pathname was passed

>cscript EE_XXXX-DL-Modify.vbs > EE_output.txt
D:\XXXX_DLs\EE_XXXX-DL-Modify.vbs(54, 1) Microsoft VBScript runtime error: Wrong
number of arguments or invalid property assignment: 'MoveHere'
yo_beeDirector of Information TechnologyCommented:
There is more to this.
I will need to play around with it
kontrariankidAuthor Commented:
yo_bee, I think I have found a solution by using a script from "charast", link provided here:
by: charast, Posted on 2009-09-21 at 14:18:46ID: 25385811

The key, as "charast" discovered, was using more than one input file, and then reading from the related file(s) as necessary.

I am only able to test for now against a few accounts, but I even was able to modify the mail attribute but added this line.. and then since I had already updated the SamAccountName and displayNames, I commented two lines out per below to update only the mail attribute (Primary SMTP); although looking at the proxyaddresses, the old address is still highlighted and set to (capital) SMTP. We should have only a few of those to change though. The great thing about this script is that it can be very flexible and used going forward to manipulate. For example, I can add a line for mailNickName to update the first part of email addresses, thus removing any "z-". Just need to ensure the input files are consistent with what the script is trying to do.

Set objGroupNewSMTP = objFSO3.OpenTextFile("D:\XXXX_DLs\Rename Groups\Testing\grouplistnewsmtp.txt")

'       objUser.SamAccountName = newGroup
'       objUser.displayName = newGroup
       objUser.mail = newSMTP

I will give you some credit because you spent lots of time helping me mentally walk through thoughts and understanding. Thank you you_bee!

you_bee's profile...

My edited copy of charast's script is attached.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
kontrariankidAuthor Commented:
I found a solution by editing and adding to a script from "charast", link provided here:
by: charast, Posted on 2009-09-21 at 14:18:46ID: 25385811

The key, as "charast" discovered, was using more than one input file, and then reading from the related file(s) as necessary.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Active Directory

From novice to tech pro — start learning today.