Alright, so we’re nearly finished with our PowerShell script to create users in bulk in AD with random passwords, but we want to add a last few touches to our (finger painting) work of art. Firstly, let’s add that password back into the $Users variable so we can export it with the passwords afterwards. The idea here is for us to use the same information we imported from the CSV but we want to add the password we generated for each user in a new column.
\\\Write the Password Back
We can accomplish this by using the Add-Member cmdlet inside the ForEach loop. We can pretty much put this anywhere after the $Pwd variable is defined so let’s put it at the end:
$U | Add-Member -MemberType NoteProperty -Name "Initial Password" -Value $Pwd -Force
This line will add the property “Initial Password” with the generated password back to the individual user ($U) in the loop. Once the loop is complete, our $Users variable should now have all of the passwords added for each user just waiting for us to export.
\\\Where Am I?
Now, questions we must ask ourselves (shout out to my boy Yoda)…

Wouldn’t it be nice if we were older? I mean, wouldn’t it be nice if we knew what the script was doing and where we were at? Let’s say we have thousands of users (which is definitely why we want to create users in bulk) in our CSV and we finally press “go” but have no idea if it’s doing anything or not…as the audience stares at our screen patiently waiting for the magic to happen, let’s give them (and ourselves) a little bit of an indication of where we’re at so we don’t have to keep checking task manager to make sure nothing says “Not Responding…” Oh, I’m the only who does that? It’s cool…
\\\Progress Tracking
In the beginning of the loop after we’ve defined the Name Variations (so we can use the $Display variable we’ve defined that contains the First and Last Names), let’s add this line that will tell us which user we’re working on:
Write-Host "Working on $Display..." -ForegroundColor Cyan
And right after New-ADUser (where we actually create the account), let’s add another line to let us know that we successfully created the account:
Write-Host "Successfully created: $Display..." -ForegroundColor Cyan
You don’t have to choose Cyan as the foreground color, but it helps my elder eyes to see something other than the white text. Really, anything except for the daunting and dreadful red scare that we get with PowerShell error messages.
\\\Define Success
Ask more questions we must…What if the user already exists??? Will I break the internet???
Possibly.
But we can wrap the actual New-ADUser cmdlet (And our new Write-Host saying successfully created) in a Try/Catch block, which is very similar to a Do/Do Not But There Is No Try block…I’ll write more on this at a later time, but if you’re familiar with the Try/Catch block, we want to use it to detect errors and tell us what happened. Additionally, we don’t want it to tell us “Hey, everything succeeded!” when, in fact, everything did not succeed. Nobody likes successful messages for unsuccessful actions. Don’t write lies to yourself.
So the Try block will do everything in it until it encounters a terminating error. If there’s a terminating error, it will stop and move to the Catch block. If there are no errors, it will skip over the catch and move right along. As a good practice, we can specify the error action on the New-ADUser cmdlet. Here’s our updated changes with the Try/Catch block, Add-Member, and Write-Host:
#Create New User in AD with the Parameters defined
Try{
New-ADUser @Parameters -ErrorAction Stop
Write-Host "Successfully created $Display!" -ForegroundColor Green
$U | Add-Member -MemberType NoteProperty -Name "Initial Password" -Value $Pwd -Force
}
Catch{
Write-Host "Bro...something went horribly wrong. Does this user already exist?? $Display" -ForegroundColor Red
}
There is definitely more we can do here with writing to specific pipelines and grabbing the specific errors and doing different things based on each, but for now, this will conclude our training in adding just a smidgen of error handling so you can sleep better at night. What? You don’t go to sleep thinking about your scripts? Yeah…of course, not…me uh, neither…
\\\Export Data
Lastly, what do we do with the $Users variable that now has the passwords? At the end of our script (outside of the loop) we can choose to export to the same path and file that we imported (overwriting our original CSV, a Sith move) or we could go with a completely new file (just like a Jedi), it’s up to you. So after the curly brace at the end of our ForEach loop, I’m going to go with a new CSV file so I don’t accidentally overwrite the CSV file that contained my life’s work:
$Users | Export-Csv C:\Users\star.killer\Desktop\TooManyUsers_SamplePwds.csv -NoTypeInformation
\\\Putting it All Together
Finished Script
#####FINAL FORM#####
$ImportPath = "C:\Users\star.killer\Desktop\EmpireUsers_EmpireOnly.csv"
$ExportPath = "C:\Users\star.killer\Desktop\TooManyUsers_WPwds.csv"
$Users = Import-Csv $ImportPath
#Function
#Randomize Passwords the hard way, Option4
function Get-RandomPassword{
Param(
[Parameter(mandatory=$true)]
[int]$Length
)
Begin{
if($Length -lt 4){
End
}
$Numbers = 1..9
$LettersLower = 'abcdefghijklmnopqrstuvwxyz'.ToCharArray()
$LettersUpper = 'ABCEDEFHIJKLMNOPQRSTUVWXYZ'.ToCharArray()
$Special = '!@#$%^&*()=+[{}]/?<>'.ToCharArray()
#For the 4 character types (upper, lower, numerical, and special), let's do a little bit of math magic
$N_Count = [math]::Round($Length*.2)
$L_Count = [math]::Round($Length*.4)
$U_Count = [math]::Round($Length*.2)
$S_Count = [math]::Round($Length*.2)
}
Process{
$Pwd = $LettersLower | Get-Random -Count $L_Count
$Pwd += $Numbers | Get-Random -Count $N_Count
$Pwd += $LettersUpper | Get-Random -Count $U_Count
$Pwd += $Special | Get-Random -Count $S_Count
#If the password length isn't long enough (due to rounding), add X special characters, where X is the difference between the desired length and the current length.
if($Pwd.length -lt $Length){
$Pwd += $Special | Get-Random -Count ($Length - $Pwd.length)
}
#Lastly, grab the $Pwd string and randomize the order
$Pwd = ($Pwd | Get-Random -Count $Length) -join ""
}
End{
$Pwd
}
}
#Loop through each user from the CSV
Foreach($U in $Users){
#Define Name variations and generate a random password
$FirstDotLast = "$($U.First).$($U.Last)"
$Display = "$($U.First) $($U.Last)"
$UPN = "$FirstDotLast@empire.local"
$Pwd = Get-RandomPassword -Length 8
Write-Host "Working on $Display..." -ForegroundColor Cyan
#Define Parameters
$Parameters = @{
Name = $FirstDotLast
GivenName = $U.First
Surname = $U.Last
SamAccountName = $FirstDotLast
DisplayName = $Display
UserPrincipalName = $UPN
AccountPassword = (ConvertTo-SecureString $Pwd -AsPlainText -Force)
Enabled = $true
ChangePasswordAtLogon = $true
Title = $U.Title
OtherAttributes = @{"Allegiance"=$U.Allegiance;"Species"=$U.Species}
}
#Create New User in AD with the Parameters defined above
Try{
New-ADUser @Parameters -ErrorAction Stop
Write-Host "Successfully created $Display!" -ForegroundColor Green
$U | Add-Member -MemberType NoteProperty -Name "Initial Password" -Value $Pwd -Force
}
Catch{
Write-Host "Bro...something went horribly wrong. Does this user already exist?? $Display And did you run this as administrator?" -ForegroundColor Red
}
}
#Export
$Users | Export-Csv $ExportPath -NoTypeInformation
I ran this script with one user in the CSV (Palpatine) and everything looked good. Let’s try it now with multiple users to make sure we’re not building our house on shifting sand.
Here is my CSV with 9 users:

Let’s do this thang! I’ve already created the Emperor from the sample CSV (nobody wants to get on his bad side) so I should expect to see it “catch” the error trying to create the user that already exists. Here’s my output:

Almost brings tears to my eyes it’s so beautiful.
\\\Putting it All Together
And the finale, here is the new CSV file exported. Since I had already created Palpatine and it was caught in the try block, it didn’t update the password. Bigly.

This concludes our 4 part series and you should now know how to bulk create users in AD via PowerShell with random passwords. Thoughts? Stuck? Have something new to teach me? Like Star Wars? Have hands? Comment below!