I am trying to import a CSV export from one system and import into AD. I have a series of things to handle, but essentially, I just need to create the OU's and Groups if they don't exist (To build out the framework/structure of the environment). Then run through and check for users, adding them if they aren't there. Ideally I would update the users if they were already in AD.
Here is the script thus far. Everything looks ok when I dump it using Out-GridView. This is what it looks like using Out-Default:
Name : 11506
SamAccountName : 11506
DisplayName : Jon Aber
GivenName : Jon
Surname : Aber
MiddleInitial : T
EmailAddress : ******@student.devdc.com
Description : 11506
Path : OU=11,OU=705,OU=Students,DC=DEVDC,DC=COM
PasswordNeverExpires : True
Enabled : True
ChangePasswordAtLogon : False
AccountPassword : System.Security.SecureString
The Script:
<#
This script will take the exported file from PowerSchool
and add the headers then process the file.
Any changes should be able to be made in the top block
environmental variables and paths.
#>
<#
Set our Preference Variables and
create the transcript log
#>
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path latest.log
<#
Adding old fallbacks just in case
#>
Import-Module ActiveDirectory -ErrorAction SilentlyContinue
<#
Add any variables that we need
for the process here.
These should be able to be managed and changed easily
for any changes made throughout time.
#>
$global:basePath = "C:\SftpRoot\loginid\"
$global:fileName = "student-ad.csv"
$global:csvPath = $basePath + $fileName
$global:saveFile = "ADNEW.csv"
$global:missingHeaders = @("last_name","first_name","middle_name","student_number","grade_level","schoolID") # Add all column headers here.
$global:subDomain = "student" # Email purposes only. Use "" if nothing.
$global:studentGroups = '802.1x Student','Domain Users' # Add Groups in that the students should be added to.
$global:schools = @(
[pscustomobject]@{Name='ES';Grades=@('1','2','3','4')}
[pscustomobject]@{Name='NW';Grades=@('1','2','3','4')}
[pscustomobject]@{Name='SR';Grades=@('1','2','3','4')}
[pscustomobject]@{Name='EC';Grades=@('PK','K')}
[pscustomobject]@{Name='PI';Grades=@('5','6')}
[pscustomobject]@{Name='MS';Grades=@('7','8')}
[pscustomobject]@{Name='HS';Grades=@('9','10','11','12')}
)
$global:schoolName = $null
# Build email path
if($subDomain -eq "" -or $subDomain -eq $null){
$global:emailPath = '@' + $env:USERDNSDOMAIN.ToLower()
}else{
$global:emailPath = '@' + $subDomain + '.' + $env:USERDNSDOMAIN.ToLower()
}
<# /VARIABLES #>
<###########################################
Add any functions/methods that we need
for the process here.
These should NOT be edited
###########################################>
<#
Name: makePassword
Params: $fn
$mn
$ln
$sid
Instructions: Call function and provide First Name,
Middle Name, Last Name, and Student ID so we can
create the new student password.
#>
Function makePassword($fn,$mn,$ln,$sid){
if($mn -eq $null -or $mn -eq ""){
$pw = $fn.substring(0,1) + $mn.substring(0,1) + $ln.substring(0,1) + $sid
return $pw
}else{
$pw = $fn.substring(0,1) + $ln.substring(0,1) + $sid
return $pw
}
} # END makePassword
<#
Name: CreateOUs
Params: NA
Instructions: Call function to verify and create
Organizational Units in AD.
#>
Function CreateOUs() {
# Create Inner Variables
$sPath = 'DC='+$env:USERDNSDOMAIN.Substring(0,$env:USERDNSDOMAIN.Length-4)+',DC='+$env:USERDNSDOMAIN.Substring($env:USERDNSDOMAIN.Length-3)
# Check for and create the Students OU first
$studentsExists = ([adsi]::Exists("LDAP://OU=Students,$sPath"))
if ($studentsExists -eq $true) {
Write-Host "Students OU already exists." -foregroundcolor Yellow
} else {
Write-Host "Students OU being created." -foregroundcolor Green
$tPath = 'DC='+$env:USERDNSDOMAIN.Substring(0,$env:USERDNSDOMAIN.Length-4)+',DC='+$env:USERDNSDOMAIN.Substring($env:USERDNSDOMAIN.Length-3)
New-ADOrganizationalUnit -Name 'Students' -Path $tPath -ProtectedFromAccidentalDeletion $true
}
# Check for the schools OU paths
$schools | ForEach-Object {
$scPath = 'OU=Students,DC='+$env:USERDNSDOMAIN.Substring(0,$env:USERDNSDOMAIN.Length-4)+',DC='+$env:USERDNSDOMAIN.Substring($env:USERDNSDOMAIN.Length-3)
$scName = $_.'Name'
$schoolExists = ([adsi]::Exists("LDAP://OU=$scName,$scPath"))
if ($schoolExists -eq $True){
Write-Host "$scName OU already exists." -foregroundcolor Yellow
} else {
Write-Host "$scName OU is being created." -foregroundcolor Green
New-ADOrganizationalUnit -Name "$scName" -Path $scPath -ProtectedFromAccidentalDeletion $false
}
foreach($grade in $_.'Grades'){
# Check for the grades OU paths
$gradeExists = ([adsi]::Exists("LDAP://OU=$grade,OU=$scName,$scPath"))
if ($gradeExists -eq $true) {
Write-Host "$grade OU already exists." -foregroundcolor Yellow
} else {
Write-Host "$grade OU being created." -foregroundcolor Green
$gPath = "OU=$scName,$scPath"
New-ADOrganizationalUnit -Name $grade -Path $gPath -ProtectedFromAccidentalDeletion $false
}
}
}
} # END CreateOUs
<#
Name: CreateGroups
Params: NA
Instructions: Call function to verify and create
Organizational Groups in AD.
#>
Function CreateGroups() {
# Check for and create the Groups in the provided array above
$studentGroups | ForEach-Object {
# Create Path variable
$gPath = 'CN=Users,DC='+$env:USERDNSDOMAIN.Substring(0,$env:USERDNSDOMAIN.Length-4)+',DC='+$env:USERDNSDOMAIN.Substring($env:USERDNSDOMAIN.Length-3)
$gName = $_
$groupExists = try { [ADSI]::Exists('LDAP://CN=' + $gName + ',' + $gPath) } catch { $False }
if($groupExists -eq $true){
Write-Host "Group $gName already exists. Skipping..." -foregroundcolor Yellow
}else{
New-ADGroup -Name $gName -Path: $gPath -SamAccountName: $gName -GroupCategory: Security -GroupScope: Global
Write-Host "Group $gName did not exsist. It has now been been created in $gPath" -foregroundcolor Green
}
}
} # END CreateGroups
<##################################
This is where it all begins
##################################>
# Log the date
Get-Date
# Create the OUs if they don't exist
CreateOUs
# Create the Groups if they don't exist
CreateGroups
# Import out CSV file and process it
Import-Csv $csvPath -Header $missingHeaders | Select-Object `
@{name='Name';expression={$_.'student_number'}}, `
@{name='SamAccountName';expression={$_.'student_number'}}, `
@{name='DisplayName';expression={($_.'first_name'+' '+$_.'last_name')}}, `
@{name='GivenName';expression={$_.'first_name'}}, `
@{name='Surname';expression={$_.'last_name'}}, `
@{name='MiddleInitial';expression={($_.'middle_name').Substring(0,1)}}, `
@{name='EmailAddress';expression={($_.'student_number'+$emailPath)}}, `
@{name='Description';expression={$_.'student_number'}}, `
@{name='Path';expression={"OU="+$_.'grade_level'+",OU="+$_.'schoolID'+",OU=Students,DC="+$env:USERDNSDOMAIN.Substring(0,$env:USERDNSDOMAIN.Length-4)+",DC="+$env:USERDNSDOMAIN.Substring($env:USERDNSDOMAIN.Length-3)}}, `
@{name='PasswordNeverExpires';expression={$true}}, `
@{name='Enabled';expression={$true}}, `
@{name='ChangePasswordAtLogon';expression={$false}}, `
@{name='AccountPassword';expression={ConvertTo-SecureString "makePassword $_.'first_name' $_.'middle_name' $_.'last_name' $_.'student_number'" -AsPlainText -force}} |
Out-GridView
<#
Let's wrap it up now!!!
Give the date (should be the same)
and stop the transcript log.
#>
# Log the date
Get-Date
# Stop the transcript log
Stop-Transcript
- Here is a sample of how the data comes in. (student-ad.csv) Thumb,Tom,Tiny,11506,11,705
Biden,Joe,Schmoe,11722,5,125
Trump,Donald,,10405,8,510
Jill,Jack,Paul,11215,6,125
When I try to change out the pipe cmdlet Out-GridView with New-ADUser I get the following output:
PS C:\Windows\System32\WindowsPowerShell\v1.0>student-ad.ps1
Transcript started, output file is latest.log
Wednesday, May 19, 2021 12:03:14 PM
Students OU already exists.
ES OU already exists.
1 OU already exists.
2 OU already exists.
3 OU already exists.
4 OU already exists.
NW OU already exists.
1 OU already exists.
2 OU already exists.
3 OU already exists.
4 OU already exists.
SR OU already exists.
1 OU already exists.
2 OU already exists.
3 OU already exists.
4 OU already exists.
EC OU already exists.
PK OU already exists.
K OU already exists.
PI OU already exists.
5 OU already exists.
6 OU already exists.
MS OU already exists.
7 OU already exists.
8 OU already exists.
HS OU already exists.
9 OU already exists.
10 OU already exists.
11 OU already exists.
12 OU already exists.
Group 802.1x Student already exists. Skipping...
Group Domain Users already exists. Skipping...
New-ADUser : Directory object not found
At C:\SftpRoot\loginid\student-ad.ps1:190 char:5
+ New-ADUser
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CN=11506,OU=11,...DC=DEVDC,DC=COM:String) [New-ADUser], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.NewADUser
New-ADUser : Directory object not found
At C:\SftpRoot\loginid\student-ad.ps1:190 char:5
+ New-ADUser
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (CN=11722,OU=5,O...DC=DEVDC,DC=COM:String) [New-ADUser], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.NewADUser
What am I doin wrong and why is it trying to create a CN for the User rather than add them to the OU specified?