Jump to content
EduGeek EdSec 2026 is Go! 27th Oct in Derby! Join us for a day of EdTech security focused talks, networking, and an evening social ×
  • entries
    13
  • comments
    3
  • views
    873

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:

 

  1. Copies the export and names by date, also names log by date for easy sorting and retention for debugging if need be
  2. Rudimentary checking of the export file for date and columns
  3. Username formatting
  4. User creation and OU placement
  5. Group membership
  6. Home folder creation
  7. 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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...