<#

    ==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