Power Shell Script for Automatic User Creation in AD
#Updated 2018/08/30:
- Fixed a bug where it didn't count the number of newly created users correctly.
- Fixed another bug with the continue statement not working as intended when finding an invalid grade
I wrote this Power Shell script to automate user creation in Active Directory. It's run off of a scheduled task and maintains a log file of everything it does. It handles pretty much everything:
- Copies the export and names by date, also names log by date for easy sorting and retention for debugging if need be
- Rudimentary checking of the export file for date and columns
- Username formatting
- User creation and OU placement
- Group membership
- Home folder creation
- Home folder persmissions
The Export looks like this:
PSNumber Lastname Firstname Grade 1000001000 O'Neill Jack 12 1000001001 Carter Samantha 9 1000001002 Jackson Daniel 11 1000001003 Mal Doran Vala 11 1000001004 McKay Rodney 12 1000001005 Hammond George 12 1000001006 Quinn Jonas 10 1000001007 Mitchell Cameron 12
You'll have to change a few things to fit your environment, but this makes for a good starting point. The script is designed with an OU structure that breaks students down into graduation years.
-Students
-2018
+Student A
+Student B
-2017
-2016
-2015
+Student C
Every student is a member of their respective graduation year group: Students_2018, Students_2017, etc.
Account name is the first six letters of the last name, followed by the last four digits of their student number. The script will also remove some special characters from the names that AD could gripe about.
I hope this helps...
-Mark
#Define editable strings
$WorkingDir = "script path goes here"
$ADDomain = "Domain Name goes here"
$Password = "student"
$BaseOU = "ou=Grad Year,ou=Students,ou=Your User OU,dc=domain name,dc=com"
$BaseHome = "\\yourfileserver\students$\"
$HomeDrive = "H:"
$UserCount = 0
#Define non-editable strings
$LogPath = $WorkingDir + "Log $($LogDate).txt"
$LogDate = Get-Date -UFormat "%Y-%m-%d.%H.%M.%S"
$PSExportPath = $WorkingDir + "student.export.text"
$UserExportPath = $WorkingDir + "User $($LogDate).txt"
$TimeStart = Get-Date
#Create the log file and write the header - file named with date
"Processing started on $($TimeStart)" | Out-File $LogPath -append
"--------------------------------------------" | Out-File $LogPath -append
"" | Out-File $LogPath -append
#Load the Active Directory module
Try{Import-Module ActiveDirectory -ErrorAction Stop}
Catch{
"[CRITICAL] Active Directory module not loaded! Aborting." | Out-File $LogPath -append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Exit
}
#Check for existance of user export file
$FileExists = Test-Path $PSExportPath
If ($FileExists -eq $False){
"[CRITICAL] User export not found! Aborting." | Out-File $LogPath -append
Exit
}
#Check age of user export file and stop script if more than 12 hours old
$PSExportFile = Get-Item $PSExportPath
$Limit = (Get-Date).AddHours(-12)
If ($PSExportFile.LastWriteTime -lt $Limit){
"[CRITICAL] User export is more than 12 hours old! Aborting." | Out-File $LogPath -append
Exit
}
#Copy automated user export file to another name that includes the date
#this preserves the file along with the log, both named by date for debugging purposes
Copy-Item $PSExportPath $UserExportPath | Out-Null
#Import CSV and bust down using a tab delimiter - script stops if this fails
Try{$Users = Import-Csv -Delimiter "`t" -Path $UserExportPath -ErrorAction Stop}
Catch{
"[CRITICAL] Export not formatted properly! Aborting." | Out-File $LogPath -append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Exit
}
#Used to determine fiscal year - most US schools operate on a 9 month calendar year
#because of our SIS system the graduation year is derived from the current year and the student's grade level
#anything after the month of June is considered to be the next calendar year
If ($TimeStart.Month -gt 7) {$FiscalYear = $TimeStart.Year + 1}
Else {$FiscalYear = $TimeStart.Year}
#Function where the magic happens
Function AddUsers{
#Step through each line of the export loaded into $Users
:nextUser foreach ($User in $Users) {
$i++
#Assign each column it's own variable
$UserFirstname = $User.First_Name
$UserLastname = $User.Last_Name
$PSNumber = $User.Student_Number
$Grade = $User.Grade_Level
#Check for blank entries in any of the columns - if any are found then log it and go back to the top of the loop, skipping this user line
If (($UserFirstname -eq "") -Or ($UserLastname -eq "") -Or ($PSNumber -eq "") -Or ($Grade -eq "")){
"[ERROR] Information missing. Check source line $($i)." | Out-File $LogPath -Append
Continue nextUser
}
#Remove special characters that don't play nice in AD from user names
$UserFirstname = $UserFirstname.Replace(".","")
$UserFirstname = $UserFirstname.Replace(" ","")
$UserFirstname = $UserFirstname.Replace("'","")
$UserFirstname = $UserFirstname.Replace("-","")
$UserLastname = $UserLastname.Replace(".","")
$UserLastname = $UserLastname.Replace(" ","")
$UserLastname = $UserLastname.Replace("'","")
$UserLastname = $UserLastname.Replace("-","")
#Generate user's login name - syntax for our environment is first six characters of last name followed by last four digits of student number
If ($UserLastname.Length -lt 6){
$SAM = $UserLastname + $PSNumber.Substring($PSNumber.Length -4,4)
}
ElseIf($UserLastname.Length -ige 6){
$SAM = $UserLastname.Substring(0,6) + $PSNumber.Substring($PSNumber.Length -4,4)
}
#Generate strings for other pieces of user information
$Displayname = $UserFirstname + " " + $UserLastname
$UPN = $SAM + "@" + $ADDomain
#Make sure that grade is within proper bounds - if not, write to the log and continue back to the top of the loop skipping this user from further processing
Switch ($Grade) {
12 {$GradYear = $FiscalYear + 0}
11 {$GradYear = $FiscalYear + 1}
10 {$GradYear = $FiscalYear + 2}
9 {$GradYear = $FiscalYear + 3}
8 {$GradYear = $FiscalYear + 4}
7 {$GradYear = $FiscalYear + 5}
6 {$GradYear = $FiscalYear + 6}
5 {$GradYear = $FiscalYear + 7}
4 {$GradYear = $FiscalYear + 8}
3 {$GradYear = $FiscalYear + 9}
2 {$GradYear = $FiscalYear + 10}
1 {$GradYear = $FiscalYear + 11}
0 {$GradYear = $FiscalYear + 12}
Default {"[ERROR] Grade not valid. Check source line $($i)." | Out-File $LogPath -Append
Continue nextUser}
}
#Generate some more stuff and populate variables
$HomeFolder = $BaseHome + $GradYear + "\" + $SAM
$OU = "ou=" + $GradYear + "," + $BaseOU
$GroupName = "Students_" + $GradYear
#Try block to check for existance of user - if this fails then log it and continue back to the top of the loop, skipping this user from further processing
Try {$UserExists = Get-ADUser -LDAPFilter "(sAMAccountName=$SAM)"}
Catch {
"[ERROR] Unabled to check for duplicate user $(SAM) Source line $($i)." | Out-File $LogPath -Append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Continue nextUser
}
#If user doesn't exist, create said user
If(!$UserExists){
#Try block to create user - if this fails then log it and continue back to the top of the loop, skipping this user from further processing
Try{
New-ADUser -Name $SAM -DisplayName $Displayname -SamAccountName $SAM -UserPrincipalName $UPN -GivenName $UserFirstname -Surname $UserLastname -HomePhone $PSNumber -Description $GradYear -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -ChangePasswordAtLogon $true -PasswordNeverExpires $false -Path $OU -HomeDirectory $HomeFolder -HomeDrive $HomeDrive -ErrorAction Stop
}
Catch{
"[ERROR] User $($SAM) not created. Source line $($i)." | Out-File $LogPath -Append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Continue nextUser
}
#Count the number of users added for later use in the log
$Global:UserCount = $Global:UserCount + 1
"[sUCCESS] User $($SAM) created. Source line $($i)." | Out-File $LogPath -Append
#Try block to add newly created user to the appropriate student graduation group - if this fails then log it and continue back to the top of the loop, skipping this user from further processing
Try{Add-ADGroupMember -Identity $GroupName -Members $SAM -ErrorAction Stop}
Catch{
"[ERROR] User $($SAM) not added to group $($GroupName). Source line $($i)." | Out-File $LogPath -Append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Continue nextUser
}
"[sUCCESS] User $($SAM) added to group $($GroupName). Source line $($i)." | Out-File $LogPath -Append
#Try block for creating user's home folder and setting permissions - if this fails then log it and continue back to the top of the loop, skipping this user from further processing
Try{
New-Item -ItemType "Directory" -Path $HomeFolder -ErrorAction Stop
$Acl = (Get-Item $HomeFolder).GetAccessControl('Access')
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule($SAM, "Modify",'ContainerInherit,ObjectInherit', 'None', 'Allow')
$Acl.SetAccessRule($Ar)
Set-Acl -path $HomeFolder -AclObject $Acl
}
Catch{
"[ERROR] User $($SAM) home folder messed up. Source line $($i)." | Out-File $LogPath -Append
"`t $($_.Exception.ItemName)" | Out-File $LogPath -Append
"`t $($_.Exception.Message)" | Out-File $LogPath -Append
Continue nextUser
}
"[sUCCESS] User $($SAM) home folder created. Source line $($i)." | Out-File $LogPath -Append
}
Else{
"[iNFO] User $($SAM) already exists. Source line $($i)." | Out-File $LogPath -Append
Continue nextUser
}
}
#Give a half second between creating users to let AD catch its tail
Start-Sleep -Milliseconds 500
}
Addusers
#Write statistics to the end of the log
$TimeEnd = Get-Date
$ElapsedTime = $TimeEnd - $TimeStart
"" | Out-File $LogPath -Append
"Processing Finished on: $($TimeEnd)" | Out-File $LogPath -Append
"Total processing time: $($ElapsedTime)" | Out-File $LogPath -Append
"Users created: $($UserCount)" | Out-File $LogPath -Append
#Debug function
Function Debug {
Write-Host "Username: " $SAM
Write-Host "OU: " $OU
Write-Host "Grad Year: " $GradYear
Write-Host "Home Folder: " $HomeFolder
#Write-Host $UPN
#Write-Host $GApps
Write-Host
}
Edited by Duke5A

0 Comments
Recommended Comments
There are no comments to display.
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now