<#
==Synopsis==
This script takes a mass export of students and creates accounts in Active Directory and then
sets them up with Office 365 licenses.
==Critical Notes==
1. AD samAccountName has a unchangeable max of 20 characters.
2. Processing is dependent on CSV headers matching up. PowerSchool doesn't export header row.
3. UserPrincipalName uses @stu.elps.us for Office 365
4. Email uses #elps.us for Google
==Synopsis==
1. Start a transcript for reviewing errors.
2. Check if the export from PowerSchool exists or looks unusually small
3. Check AD OUs. Create if missing.
4. Existing users have their passwords updated.
5. Missing Active Directory users and home directories are created.
6. Users missing either a graduation year or a password will be skipped
7. After local AD accounts finish the script will pause to allow Office 365 sync to complete
8. Office 365 licenses will be applied to students.
Author: Andrew Schott
Company: Joletec, Inc.
Last Modified: 2020-12-28
#>
$transcriptPath = 'C:\Script\ImportStudentsAD.log'
$studentsFile = 'C:\Script\ImportStudentsAD.csv'
$AD = 'MTCPS'
$ADou = 'OU=Stu,OU=Users,OU=MTCPS,DC=mtcps,DC=local'
$emailDomain = '@stu.mtcps.org'
$upnDomain = '@stu.mtcps.org'
$HomeDriveLetter='U:'
$FileServer = '\\fs-student\studentusers'
[int]$year = (Get-Date -Format "yyyy")
$O365CredUser = "admin@mtcpsorg.onmicrosoft.com"
$O365CredPass = "<PASSWORD>."
$AccountSkuId = "MTCPS:STANDARDWOFFPACK_IW_STUDENT"
$VerbosePreference="Continue"
# Get number of lines from CSV
$csvMeasure = Import-Csv $studentsFile | Measure-Object
[int]$csvCount = $csvMeasure.Count
# First record is line zero
$csvCount++
function Clean-Name{
param(
[string]$name
)
if($name -match '-'){
$nameClean = $name.Substring(0, $name.IndexOf('-')) # Remove anything after the hyphen
}else{
$nameClean = $name -Replace "( Jr| JR| II| III| IV| V|[',.\s])" # Remove any characters or suffixes that might cause issues in the username
}
return $nameClean
}
function AD-User-Exists{
param(
[string]$SamAccountName
)
# Check if samAccountName exists in AD
if(dsquery user -samid $SamAccountName){
return $True
}else{
return $False
}
}
function Connect-O365{
# Connection Credentials
$O365CredPassword = ConvertTo-SecureString $O365CredPass -AsPlainText -Force
$O365Cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $O365CredUser,$O365CredPassword
# Create Connection
Connect-MsolService -Credential $O365Cred
}
Start-Transcript -path $transcriptPath -append
Import-module ActiveDirectory
# Check if CSV is too small to be safe
IF ((Get-Item $studentsFile).length -lt 75kb){
Write-Verbose "ERROR - File Too Small: $studentsFile is less than 75kb and is likely a bad export"
# Exit
}
#AD OU check. Create if missing
$ou = $year
While ($ou -ne ($year+15)){
Write-Verbose "Check AD OU $ou,$ADou"
if(-Not([adsi]::Exists("LDAP://OU=$ou,$ADou"))){
#Create missing OU
NEW-ADOrganizationalUnit $i –path $ADou
Write-Verbose "Created AD OU $ou"
}else{
Write-Verbose "OU $ou already exists"
}
$ou++
}
# Track progress through CSV per line
$i = 1
# Active Directory User
import-csv $studentsFile -Header first_name,last_name,middle,grad_year,password | % {
$GivenName = Clean-Name -name $_.first_name
$GivenNameClean = Clean-Name -name $GivenName
$Initials = if($_.middle){$_.middle.Substring(0,1)}else{echo ''} # If a middle name exists, grab the first character
$SurName = $_.last_name
$SurNameClean = Clean-Name -name $SurName
$DisplayName = "$GivenName $SurName"
Write-Verbose "Display name $DisplayName"
$SamAccountName = "$GivenNameClean.$SurNameClean" # Username is first.last
Write-Verbose "Username $SamAccountName"
[int]$GradYear = $_.grad_year
$Email = "$SamAccountName$emailDomain"
$UserPrincipalName = "$SamAccountName$upnDomain"
$Path = "OU=$GradYear,$ADou"
$HomeDrive = $HomeDriveLetter
$HomeDirectory = "$FileServer\$GradYear\$SamAccountName"
$Password = $_.password
filter timestamp {"$(Get-Date -Format G): -- $i/$csvCount $_"}
# Clear any errors from last record
$error.clear()
if($GradYear -gt 2000 -And $Password){
Try{
Set-ADAccountPassword -Identity $SamAccountName -NewPassword (ConvertTo-SecureString $Password -AsPlainText -force)
if (!$error){
Write-Output "-- Reset password for $SamAccountName" | timestamp
}
}Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]{
# AD user doesn't exist
Write-Output "-- User not found. Creating user: $SamAccountName" | timestamp
# Clear any errors
$error.clear()
Try{
New-ADUser -GivenName $GivenName -Initials $Initials -SurName $SurName -Name $DisplayName -DisplayName $DisplayName -SamAccountName $SamAccountName -Email $Email -UserPrincipalName $UserPrincipalName -CannotChangePassword $TRUE -Path $Path -homeDrive $HomeDrive -homeDirectory $HomeDirectory -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -force) -Department $Department -Enabled $true -ErrorAction Stop
# Set AD email field
Set-ADUser -Identity $SamAccountName -Add @{ProxyAddresses="SMTP:"+$Email}
if (!$error) {
# If no new error
# Create home directory
Write-Output "-- Checking Home Directory: $HomeDirectory" | timestamp
If(Test-Path -Path $HomeDirectory){
Write-Output "-- Home Directory already exists: $HomeDirectory" | timestamp
}else{
Try{
Write-Verbose (($HomeDirectory.Split("\") |measure-object).Count -1)
if((($HomeDirectory.Split("\") |measure-object).Count -1) -gt 3){
New-Item –path $HomeDirectory -type directory -force
$colRights = [System.Security.AccessControl.FileSystemRights]"FullControl"
$InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
$objType =[System.Security.AccessControl.AccessControlType]::Allow
$objUser = New-Object System.Security.Principal.NTAccount($AD+'\'+$SamAccountName)
$objACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($objUser, $colRights, $InheritanceFlag, $PropagationFlag, $objType)
$objACL = Get-ACL $HomeDirectory
$objACL.AddAccessRule($objACE)
Set-ACL $HomeDirectory $objACL
}
}Catch{
Write-Output "-- Failed! Home directory could not be created: $HomeDirectory" | timestamp
}
}
}
}Catch{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
Write-Verbose "-- ERROR - $FailedItem - $ErrorMessage" | timestamp
}
}
}else{
if(-not($GradYear -gt 2000)){
Write-Verbose '-- ERROR - Missing grad_year' | timestamp
}
if(-not($Password)){
Write-Verbose '-- ERROR - Missing password' | timestamp
}
}
$i++
}
# Clear any errors
$error.clear()
# Sync AD Users to Office365
Write-Verbose "`n`n`n`nSyncing accounts..."
# Start-ADSyncSyncCycle -PolicyType Delta
# Pause to allow time for sync
#Start-Countdown -Seconds 90 -Message "Allowing time to sync"
# Set Office 365 License
Write-Verbose "`nSetting licenses..."
# Connection to Office 365
#Connect-O365
import-csv $studentsFile -Header first_name,last_name,middle,grad_year,password | % {
$GivenName = Clean-Name -name $_.first_name
$GivenNameClean = Clean-Name -name $GivenName
$SurName = $_.last_name
$SurNameClean = Clean-Name -name $SurName
$SamAccountName = "$GivenNameClean.$SurNameClean"
[int]$GradYear = $_.grad_year
$Password = $_.password
$UserPrincipalName = "$SamAccountName$upnDomain"
Write-Verbose $UserPrincipalName
if(AD-User-Exists -SamAccountName $SamAccountName -eq $True -And $GradYear -gt 2000 -And $Password){
# Set Office365 Location and License
# Set-MsolUser -UserPrincipalName $UserPrincipalName -UsageLocation 'US'
# Set-MsolUserLicense -UserPrincipalName $UserPrincipalName -AddLicenses $AccountSkuId
}
}
Stop-Transcript