Bulk Create AD users with Real user names.

So here goes my first post! [Irony that this Blog is for SharePoint and I start with something in AD and Scripting J]

From time to time, we will come across a requirement where we need to create several thousand [if not hundreds of thousands] users in AD for a variety of stress testing, and repro scenarios. Most scripts that you find online will have user names that run like "User 1", "User 2", etc., and sometimes this may not be sufficient to test the application you are working on.

I was testing one such application – SharePoint User Profile import, and people search, where I needed real world user names in AD. The parameters I was testing was FIM import speed, and crawl benchmarking – for a large profile count. I was shooting for upwards of 200,000 user profiles in SharePoint. And for this to happen, we needed that many user objects in AD. Scripts based on my initial research led me to several samples, but there was a challenge in all of them – Speed. The users were being created sequentially and creating hundreds of thousands of users would have taken days based on the benchmarking I performed on my test virtual machines [which had poor performance to begin with].

As a work around, I came up with the below script to speed up the process. The first and last names are fetched using a couple of input files [that can be modified as per your requirement]. The names are combined in all combinations possible to create a full name. Post this we use multi-processing to divide and conquer – with the limit being the hardware your Domain Controller is running on.

Have a go at what I have shared below and let me know if what you think!

Cheers.

 

 

#THIS IS NOT RECOMMENDED FOR A PRODUCTION ENVIRONMENT.

#Ensure the DC has upwards of 4 CPU cores and 4GB ram. This script s resource intensive, the more the merrier.

#Do NOT run the entire script in one shot unless the DC has surplus processing power.

#It can take several hours to a whole day to complete depending on the performance of the server.

#Run the script one section at a time from within PowerShell ISE [select the section and hit F8 (Run Selection)]

#Create two files firstname.txt, and lastnames.txt to a folder -> c:\CREATEDUSERS\. These would be the dictionary through which the Full name is constructed based on combinations.

#The more names you enlist in either file, the more users you get.

#Sample names files are linked at the end of this post.

 
 

 
 

###SECTION1###

#First break down the first name list to smaller lists to run instance per starting letter alphabet.

 
 

Set-Location C:\CREATEADUSERS

 
 

$file = Get-Content firstname.txt

foreach($item in $file)

{

switch($item.substring(0,1))

{

A {$item | out-file -FilePath firstname_a.txt -Append}

B {$item | out-file -FilePath firstname_b.txt -Append}

C {$item | out-file -FilePath firstname_c.txt -Append}

D {$item | out-file -FilePath firstname_d.txt -Append}

E {$item | out-file -FilePath firstname_e.txt -Append}

F {$item | out-file -FilePath firstname_f.txt -Append}

G {$item | out-file -FilePath firstname_g.txt -Append}

H {$item | out-file -FilePath firstname_h.txt -Append}

I {$item | out-file -FilePath firstname_i.txt -Append}

J {$item | out-file -FilePath firstname_j.txt -Append}

K {$item | out-file -FilePath firstname_k.txt -Append}

L {$item | out-file -FilePath firstname_l.txt -Append}

M {$item | out-file -FilePath firstname_m.txt -Append}

N {$item | out-file -FilePath firstname_n.txt -Append}

O {$item | out-file -FilePath firstname_o.txt -Append}

P {$item | out-file -FilePath firstname_p.txt -Append}

Q {$item | out-file -FilePath firstname_q.txt -Append}

R {$item | out-file -FilePath firstname_r.txt -Append}

S {$item | out-file -FilePath firstname_s.txt -Append}

T {$item | out-file -FilePath firstname_t.txt -Append}

U {$item | out-file -FilePath firstname_u.txt -Append}

V {$item | out-file -FilePath firstname_v.txt -Append}

W {$item | out-file -FilePath firstname_w.txt -Append}

X {$item | out-file -FilePath firstname_x.txt -Append}

Y {$item | out-file -FilePath firstname_y.txt -Append}

Z {$item | out-file -FilePath firstname_z.txt -Append}

}

}

 
 

 
 

###SECTION2###

#There is no output for this section. It only defines a variable with the script block in it.

#define the script block which should run per alphabet

#Make modifications here to add additional properties to users as per your code logic.

 
 

$scriptblock = {

 
 

Import-Module ActiveDirectory

Set-Location C:\CREATEADUSERS

$filename = "firstname_"+$args+".txt"

$first = get-content -path $filename

$last = Get-Content -Path LastNames.txt

$count = 0

foreach($fn in $first)

{

foreach($ln in $last)

{

$fullname = $fn + " " + $ln

$Un= $fullname.replace(" ","")

$dom = '@contoso.com'

$upn = $un + $dom

$pass = convertto-securestring "pass@word1" -AsPlainText -Force

New-ADUser $fullname -PasswordNeverExpires $true -DisplayName $fullname -SamAccountName $un -AccountPassword $pass -UserPrincipalName $upn -GivenName $fn -Surname $ln -OtherAttributes @{description="PS_scripted_Account";title="PS_scripted_Account";mail=$upn}

Enable-ADAccount $un

$count++

write-host "processed account " $count " : " $fullname

#without the below sleep -> the processors with max out and kill the server

Start-Sleep -Seconds 1

}

}

}

 
 

 
 

###SECTION3###

 
 

#kick off a new process for each starting alphabet of the first name. Parallel Processing.

#each job will create one user per second. So running 10 of them will create 10 users per second. Depending on DC performance, capability, cores -> run as many accordingly

 
 

Start-Job -ScriptBlock $scriptblock -ArgumentList "a"

Start-Job -ScriptBlock $scriptblock -ArgumentList "b"

Start-Job -ScriptBlock $scriptblock -ArgumentList "c"

Start-Job -ScriptBlock $scriptblock -ArgumentList "d"

Start-Job -ScriptBlock $scriptblock -ArgumentList "e"

Start-Job -ScriptBlock $scriptblock -ArgumentList "f"

Start-Job -ScriptBlock $scriptblock -ArgumentList "g"

Start-Job -ScriptBlock $scriptblock -ArgumentList "h"

Start-Job -ScriptBlock $scriptblock -ArgumentList "i"

Start-Job -ScriptBlock $scriptblock -ArgumentList "j"

Start-Job -ScriptBlock $scriptblock -ArgumentList "k"

Start-Job -ScriptBlock $scriptblock -ArgumentList "l"

Start-Job -ScriptBlock $scriptblock -ArgumentList "m"

Start-Job -ScriptBlock $scriptblock -ArgumentList "n"

Start-Job -ScriptBlock $scriptblock -ArgumentList "o"

Start-Job -ScriptBlock $scriptblock -ArgumentList "p"

Start-Job -ScriptBlock $scriptblock -ArgumentList "q"

Start-Job -ScriptBlock $scriptblock -ArgumentList "r"

Start-Job -ScriptBlock $scriptblock -ArgumentList "s"

Start-Job -ScriptBlock $scriptblock -ArgumentList "t"

Start-Job -ScriptBlock $scriptblock -ArgumentList "v"

Start-Job -ScriptBlock $scriptblock -ArgumentList "w"

Start-Job -ScriptBlock $scriptblock -ArgumentList "x"

Start-Job -ScriptBlock $scriptblock -ArgumentList "z"

 
 

 
 

##SECTION4###

 
 

##The below section is optional. It will run continually and poll the jobs and will terminate when all the jobs have completed.

##You can avoid this and manually run get-job command to get the job status. Once

$flag=$false

while(!$flag)

{

$innerflag=$true

for($i=0; $i -le (get-job).count; $i++)

{

if((get-job)[$i].state -eq "running"){$innerflag = $innerflag -AND $false}

}

if($innerflag -eq $false){write-host "creation in progress. Will check back in two minutes"}

else {write-host "Completed!"; $flag = $innerflag}

Start-Sleep -seconds 120

}

 
 

 
 

###SECTION5###

#OPTIONAL

 
 

#get count of created users :

(Get-ADUser -Filter {description -eq "PS_scripted_Account"} ).count

#clean up these scripted users :

Get-ADUser -Filter {description -eq "PS_scripted_Account"} | Remove-ADUser -Confirm:$false

 
 

 
 

###SECTION6###

##CLEANUP

 
 

#Delete the temp files we created

 
 

97..122 | foreach { $filename = "firstname_"+[char]$_+".txt"; remove-item $filename -ErrorAction SilentlyContinue}

 
 

#delete the Jobs we created.

 
 

get-job | Remove-Job

 

Sample First and Last Name files