Select Page

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
Here is the finished script including the function with only a couple of changes (changed the paths for importing and exporting to be variables you can easily change at the beginning of the script). You can also get your hands on this script via GitHub!

#####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!

OTHER POSTS YOU WANT TO READ

Spice Up HTML Emails with PowerShell – Part III

So far in this series we've fumbled our way around the kitchen and tried to wing it when sending HTML emails with PowerShell. It was clunky to say the least. We then went through our spice rack and built an HTML template, highlighting the nuances of each spicy element...

Spice up HTML Emails with PowerShell – Part II

In Part I of our scrumptious concoction we put our script into the oven to let it bake. But we forgot to add our secret sauce that's sure to leave our recipients drooling, which is clearly our goal. In this post we'll continue to spice up HTML emails with PowerShell...

Spice Up HTML Emails with PowerShell – Part I

I live in the South, specifically in God's country AKA TEXAS BABAY! There's plenty of amazing things about Texas and definitely some reasons to loathe being from Houston, but it's hard to knock our food. I mean, is there really even a debate between Whataburger vs...

Disable O365 Apps in License (PowerShell)

If it's free, it's better. This is basically my mantra for life and a really easy one to follow at that. You can apply it to all sorts of things: ice cream, candy, food. Okay, maybe just free food tastes better when you know you didn't have to pay for it. Especially...

Font Installer Script (PowerShell)

Things have smells. I know, this is a revolutionary idea and you may need to stop right here and take a breather while you process this massive revelation. Things that are brand new have a particular smell that vanishes shortly after hitting your nostrils. It's...
%d bloggers like this: