Powershell Foreach usage and syntax - powershell

I'm attempting to script the creation of accounts in active directory using a csv file. Unfortunately I'm new to PowerShell and scripting in general and am facing difficulty managing a foreach() loop which is intended to handle each of the columns in the csv document I import.
I suspect that I cannot define my variables in one block after foreach() like I have, but am unsure and would appreciate some guidance. Specifically, the purpose of the code is read a csv document and assign each item to a variable that it then uses to create a service account with those values.
The Ideal situation is one where I can create a csv with several hundred rows, execute the script and end with several hundred matching service accounts.
$SVC = (import-csv C:\users\me\desktop\Test.csv -header("Name", "Pass", "WhatDo", "Location", "Domain")) `
foreach($variable in %SVC) {
$name = $SVC.Name
$Pass = $SVC.Pass
$WhatDo = $SVC.WhatDo
$Location = $SVC.Location
$Domain = $SVC.Domain
New-ADuser `
-Name $name `
-AccountPassword (Convertto-SecureString $Pass -AsPlainText -Force) `
-CannotChangePassword $true `
-Description $WhatDo `
-DisplayName $name `
-Enabled $true `
-GivenName $name `
-PasswordNeverExpires $True `
-Office $Location `
-Path "OU=Service-Accounts, Ou=Accunts, OU=_CORP, DC=$Domain, DC=net" `
-SamAccountName $name `
-UserPrincipleName $name + "#" + $domain + ".net" `
Start-Sleep -Seconds 15
Get-ADUser `
-Identity $name | Add-ADPrincipalGroupMembership `
-MemberOf "Group1","Group2","Group3"
}

There are quite a few things wrong in your code, not just the foreach.
But let's start with that: foreach ($variable in $SVC) means that $variable will have the the current item inside your loop, yet you are accessing $SVC in your loop which is still referring to the original collection. $variable is not a good name either, so you should change that to something more meaningful. Also, you wrote %SVC instead of $SVC.
You are also using backtick (`) a lot, sometimes incorrectly. You should only use it when your cmdlet invokation spans multiple lines. In the case of Import-Csv it's not, yet there's backtick at the end. There's also one on the last line of New-ADUser. Some prefer to use Parameter Splatting instead of backticks, but's thats a matter of taste.
Considering you are creating service accounts, I would write the first part like this:
$serviceAccounts = Import-Csv C:\users\me\desktop\Test.csv -Header Name,Pass,WhatDo,Location,Domain
foreach($serviceAccount in $serviceAccounts) {
Then inside your loop you can access the indivdual properties through $serviceAccount:
$name = $serviceAccount.Name
Also, PowerShell expands variables when using double quotes, so -UserPrincipleName can be written like this: -UserPrincipleName "$name#$domain.net"

I prefer using ForEach-Object rather than foreach.
It would be something like:
$SVC = (Import-CSV C:\users\me\desktop\Test.csv -header("Name", "Pass", "WhatDo", "Location", "Domain"))
$SVC | ForEach-Object {
New-ADuser `
-Name $_.Name `
-AccountPassword (Convertto-SecureString $_.Pass -AsPlainText -Force) `
-CannotChangePassword $true `
-Description $_.WhatDo `
-DisplayName $_.Name `
-Enabled $true `
-GivenName $_.Name `
-PasswordNeverExpires $True `
-Office $_.Location `
-Path "OU=Service-Accounts, Ou=Accunts, OU=_CORP, DC=$Domain, DC=net" `
-SamAccountName $_.Name `
-UserPrincipleName $_.Name + "#" + $_.Domain + ".net"
Start-Sleep -Seconds 15
Get-ADUser `
-Identity $_.Name | Add-ADPrincipalGroupMembership `
-MemberOf "Group1","Group2","Group3"
}
$_ represents the current item in the pipeline. ($SVC in your case, which was the wrong variable anyways.) It's less code and I think it's a cleaner way of doing things!

Rename $SVC to $SVCs then foreach ($SVC in $SVCs)

Here is an example how you can do it.(Don't forget the delimiter)
$csv = Import-Csv -Path C:\temp\csv.csv -Header "a","b","c" -Delimiter ";"
foreach($row in $csv){
$row.a
$row.b
$row.c
}
Here are some more examples how foreach works:
Take a look https://ss64.com/ps/foreach.html
Examples
Loop through an array of strings:
$trees = #("Alder","Ash","Birch","Cedar","Chestnut","Elm")
foreach ($tree in $trees) {
"$tree = " + $tree.length
}
Loop through a collection of the numbers, echo each number unless the number is 2:
foreach ($num in 1,2,3,4,5) {
if ($num -eq 2) { continue } ; $num
}
Loop through a collection of .txt files:
foreach ($file in get-ChildItem *.txt) {
Echo $file.name
}

Related

can't create userS via powershell

I can't import users in powershell with a script via an csv file, but If I print the parameters on the screen,it shows them as it should.
what I am doing wrong? in my life plenty with that mustache, but plis focus on the script.
is running windows server 2016 on the powershell ise, on virtualbox
The Script:
If(-Not(Get-ADOrganizationalUnit -Filter {Name -eq "991-5D"}))
{New-ADOrganizationalUnit "991-5D" -Path (Get-ADDomain).DistinguishedName}
If(-Not(Get-ADOrganizationalUnit -Filter {Name -eq "911-5V"}))
{New-ADOrganizationalUnit "911-5V" -Path (Get-ADDomain).DistinguishedName}
$domain=(Get-ADDomain).DNSRoot
Import-Csv -Path "C:\Alumnos.csv" | foreach-object {
[int]$number= $_.X
If($number -ge 10 -and $number -le 26)
{
$UO="991-5D"
}
//there are many others O.U.
$ou= "UO="+$UO+","+$domain
$UPN = $_.LETRA+$_.PATERNO+$_.X+"#"+ "$domain"
$CUENTA= $_.LETRA+$_.PATERNO+$_.X
New-ADUser -SamAccountName $CUENTA -UserPrincipalName $CUENTA -Name $_.NOMBRE
-SurName $_.PATERNO -GivenName $_.NOMBRE -EmailAddress $UPN -AccountPassword
(ConvertTo-SecureString "Leica666" -AsPlainText -force) -Path $ou
-Enabled $true -ChangePasswordAtLogon $true -Verbose}
the data:
X,PATERNO,MATERNO,NOMBRE,SEGUNDO,LETRA
10,ARÉVALO,CORNEJO,NICOLÁS,ALEJANDRO,N
11,BARRIOS,MONTERO,BENJAMÍN,IGNACIO,B
12,BUSTAMANTE,LOYOLA,IGNACIO,HERNANDO,I
13,BUSTOS,GARRIDO,ARTURO,IGNACIO,A
this are the results on each line:
+ New-ADUser -SamAccountName $CUENTA -UserPrincipalName $CUENTA -Name $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo:NotSpecified: (CN=IGNACIO,UO=9...da.com:String)
[New-ADUser], ADException
+ FullyQualifiedErrorId : ActiveDirectoryServer:8335,
Microsoft.ActiveDirectory.Management.Commands.NewADUser
the head:
X,PATERNO,MATERNO,NOMBRE,SEGUNDO,LETRA
echo:
#{X=42; PATERNO=PAYACÁN; MATERNO=ZAPATA; NOMBRE=NICOLÁS; SEGUNDO=N; LETRA=}.NOMBRE
I know that reads the file and instead of reading just the column reads all the line($_), and then prints whatever I wrote next to it(".name", ".section", etc).
I've made some variable and format changes to make this code more successful.
$domain=Get-ADDomain
Import-Csv -Path "C:\Alumnos.csv" |
Foreach-Object {
[int]$number= $_.X
If($number -ge 10 -and $number -le 26)
{
$UO="991-5D"
}
$ou = "OU={0},{1}" -f $UO,$domain.DistinguishedName
$UPN = "{0}{1}{2}#{3}" -f $_.LETRA,$_.PATERNO,$_.X,$domain.DNSRoot
$CUENTA= "{0}{1}{2}" -f $_.LETRA,$_.PATERNO,$_.X
New-ADUser -SamAccountName $CUENTA -UserPrincipalName $UPN -Name $_.NOMBRE `
-SurName $_.PATERNO -GivenName $_.NOMBRE -EmailAddress $UPN `
-AccountPassword (ConvertTo-SecureString "Leica666" -AsPlainText -force) -Path $ou `
-Enabled $true -ChangePasswordAtLogon $true -Verbose
}
Explanation:
$domain: I've made this an ADDomain object. This allows the DistinguishedName and DNSRoot properties to be accessed where appropriate.
-f operator: I used the format operator to make it easier to read the string concatenation attempts.
$ou: This is constructed using the DistinguishedName of the domain. This is the proper format for the OU path.
$UPN: This is constructed using the DNSRoot of the domain. It can obviously be different than your domain, but must be in an email address or FQDN format.
Additional Comments:
You are setting -Name to be $_.NOMBRE. This could be problematic because Name must be unique in each OU. Name is used to build the CN, which is where uniqueness is required. If you have NICOLAS in OU 991-5D, you are going to get an error if you try to create another NICOLAS in the same place. IMHO, I would do something different. You could also implement the use of splatting for building the properties of your New-ADUser command, but that is only for readability purposes. Below is an example of splatting:
$NewUserProperties = #{
SamAccountName = $CUENTA
UserPrincipalName = $UPN
Name = $_.NOMBRE
Surname = $_.PATERNO
GivenName = $_.NOMBRE
EmailAddress = $UPN
AccountPassword = (ConvertTo-SecureString "Leica666" -AsPlainText -force)
Path = $ou
Enabled = $true
ChangePasswordAtLogon = $true
}
New-ADUser #NewUserProperties -Verbose

Bulk import AD users from csv using powershell without user intervention

I'm trying to import users from a csv file using ADUser powershell cmdlet and here's the script
Import-Module ActiveDirectory
$csvcontent = Import-CSV -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\import_create_ad_users_2a.csv"
foreach ($user in $csvcontent) {
$samAccountName = $user.GivenName.substring(0,1).ToLower()+$user.LastName.ToLower()
$userPrincinpal = $samAccountName+"#mmc.local"
New-ADUser
-AccountPassword (ConvertTo-SecureString -AsPlainText $user.Password -force)`
-ChangePasswordAtLogon $false`
-Company “mmc LLP.”`
-DisplayName ($user.GivenName+""+$user.Lastname)`
-userprincipalname $userPrincinpal`
-SamAccountName $samAccountName` -Name ($user.GivenName+""+$user.Lastname)`
-Path “CN=Users,DC=mmc,DC=local”`
-state $user.County`
-givenname $user.GivenName`
-surname $user.Lastname`
-description ($user.Description)`
-Enabled $true`
Add-ADGroupMember "mmc_Users" $samAccountName;
}
But when I run the command in powershell, I get a prompt as listed below and I would like to import all the users listed in the csv file without any user intervention.
cmdlet New-ADUser at command pipeline position 1
Supply values for the following parameters:
Name:
Please review the script and let me know how to fix this.
FYI - Powershell beginner
Thanks,
Karthik
Backticks are generally worth avoiding. They work by escaping the next character, which on the end of a line is the newline character so it allows the command to continue. However its too easy to end up with a space after the backtick that you can't see, which then ends up getting escaped and not the newline. That doesn't seem to be the case above, but as TessellatingHeckler pointed out you were missing one after New-ADUser.
A better solution (to keep the code from going too far horizontal) would be to use splatting like this:
Import-Module ActiveDirectory
$csvcontent = Import-CSV -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\import_create_ad_users_2a.csv"
foreach ($user in $csvcontent) {
$samAccountName = $user.GivenName.substring(0,1).ToLower()+$user.LastName.ToLower()
$userPrincinpal = $samAccountName+"#mmc.local"
$NewUserParams = #{
AccountPassword = (ConvertTo-SecureString -AsPlainText $user.Password -Force)
ChangePasswordAtLogon = $false
Company = “mmc LLP.”
DisplayName = ($user.GivenName+""+$user.Lastname)
userprincipalname = $userPrincinpal
SamAccountName = $samAccountName
Name = ($user.GivenName+""+$user.Lastname)
Path = “CN=Users,DC=mmc,DC=local”
state = $user.County
givenname = $user.GivenName
surname = $user.Lastname
description = ($user.Description)
Enabled = $true
}
New-ADUser #NewUserParams
Add-ADGroupMember "mmc_Users" $samAccountName
}
This works by creating a hashtable #{ } with each of the parameters in it that you want to set and then sending that hashtable to the cmdlet with the special # character.
Few things that I think look wrong, but lets try to fix it. Changing the name is best done after the user has been created. This will limit the script from failing.
Backticks can be used for someone who is just learning how to code and it allows you to see the code in a more logical way. You could also create an array as suggested, but that can get complicated and not give correct results.
Lets break down the script below. First we call ActiveDirectory Module, then we call the CSV. That part works great.
We can test it by using the following code that was provided:
Import-Module ActiveDirectory
$csvcontent = Import-CSV -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\import_create_ad_users_2a.csv"
$csvcontent | Out-GridView
This should display something with your raw data, but an example is:
GivenName | LastName | Password | Description | Country
Karthik | CSVScript | 79HKJ#p8 | UserTest | Norway
Once we can confirm that the columns are correct. We can run the script
When you use the Import-CSV it imports the columns that you defined as a pipline($_.GivenName). This allows us not to create another variable. Calling it from the Import-CSV cmdlet will only use the fields that you provide in the raw data(CSV file).
You can save the following as a PS_Script called something like NewUser_CSV.ps1
The script below will only look at what you put into the columns. If something is not correct, that means the data in the CSV is wrong. This is a basic add AD users using a CSV file with no major error handling.
We will use the Transcript cmdlet to gather a log
#RUN AS ADMIN!
Start-Transcript -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\import_create_ad_users_2a.log"
Import-Module ActiveDirectory
$csvcontent = Import-CSV -Path "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\import_create_ad_users_2a.csv"
$csvcontent | ForEach-Object {
$sam = $_.GivenName.substring(0,1)+$_.Lastname
$setpass = ConvertTo-SecureString -AsPlainText $_.Password -force
Try
{
New-ADUser $samAccountName `
-Path "CN=_s,DC=mmc,DC=local" `
-GivenName $_.GivenName `
-Surname $_.LastName `
-UserPrincipalName ($samAccountName + "#mmc.local")`
-DisplayName ($_.GivenName + " " + $_.LastName) `
-Description $_.Description `
-Enabled $TRUE `
-Company "mmc LLP." `
-State $_.Country `
-AccountPassword $setpass `
-ChangePasswordAtLogon $False `
-AccountPassword $setpass
$newdn = (Get-ADUser $samAccountName).DistinguishedName
Rename-ADObject -Identity $newdn -NewName ($_.GivenName + " " + $_.LastName)
}
Catch
{
Write-Host "[ERROR]`t Oops, something went wrong: $($_.Exception.Message)`r`n"
}
}
Stop-Transcript
I really hope this helps you out and gets the task done for you. Good luck with learning PowerShell.

Edit value in CSV using powershell

For a small project, I want to create AD users from a small CSV file. I made jobs (PowerShell scripts) that run every few minutes, to pick-up the user creation based on the status of the user I define in the script. Per example; when a user is created in the AD, I change the status to addmailbox. Then another job will come and add the mailbox.
Everything is going well, but I noticed a bug. The way I am editing the status in the CSV file is wrong, because I change the status for all users in the CSV when I only want to change one. But I can't seem to get any other method working.
#When encountering any error, stop the script.
$ErrorActionPreference = "Stop";
#Check if there is a data file.
$FileExists = Test-Path C:\inetpub\wwwroot\melle\data.csv
if($FileExists -eq $true) {
$Users = Import-Csv -Path "C:\inetpub\wwwroot\melle\data.csv"
foreach ($user in $Users) {
$Status = $User.Status;
$userPrincipalName = $User.userPrincipalName;
$SAMAccountName = $User.SAMAccountName;
$userInstance = $User.userInstance;
$Name = $User.Name;
$displayName = $User.DisplayName;
$Path = '"' + $User.Path + '"';
$GivenName = $User.GivenName;
$Surname = $User.Surname;
$SIP = $userPrincipalName;
if ($Status -eq "CreateUser") {
try {
#create user
Import-Module ActiveDirectory;
New-ADUser -SAMAccountName $SAMAccountName -Instance $userInstance -Name $name -DisplayName $displayName -Path "correct.path.com" -GivenName $givenname -Surname $surname -userPrincipalName $userprincipalname -AccountPassword (ConvertTo-SecureString -String "bla" -AsPlainText -Force) -PassThru | Enable-ADAccount;
#change status
(Get-Content C:\inetpub\wwwroot\melle\data.csv) | Foreach-Object {$_ -replace 'CreateUser','AddMailbox'} | Out-File C:\inetpub\wwwroot\melle\data.csv
#exit on completion
Exit(Write-Host 'User was created in AD.');
} Catch {
#write any errors to error log.
$_ | Out-File C:\inetpub\wwwroot\melle\errors.log -Append;
}
} else {
Exit(Write-Host 'No user with status CreateUser was found.');
}
}
}else {
Exit(Write-Host 'No data.csv file was found.');
}
The way I do it now is (Get-Content C:\inetpub\wwwroot\melle\data.csv) | Foreach-Object {$_ -replace 'CreateUser','AddMailbox'} | Out-File C:\inetpub\wwwroot\melle\data.csv but I want to define it for only the row that the script is talking to in the foreach.
I tried searching for a solution on here and different sites, but I wasn't able to get the solutions others are using to work on my script. Some scripts were too advanced for me to understand.
What would be the correct approach to only change the status for the line I'm working on in the loop?
UPDATE: Solved
Working script:
#Check if there is a data file.
$FileExists = Test-Path C:\inetpub\wwwroot\melle\data.csv
if($FileExists -eq $true) {
$Users = Import-Csv -Path "C:\inetpub\wwwroot\melle\data.csv"
$UsersThatNeedToBeCreated = $Users | Where-Object {$_.Status -eq 'CreateUser'};
# Check that we have users that need to be created, might need fine-tuning.
if($UsersThatNeedToBeCreated -eq $null -or $UsersThatNeedToBeCreated.Count -eq 0){
# Write-Host doesn't have a meaningful return code, so you can separate those lines.
Exit(Write-Host 'No user with status CreateUser was found.');
}else{
# This way it's only run once
Import-Module ActiveDirectory;
}
$Users | ForEach-Object {
if($_.Status -eq 'CreateUser'){
try {
#create user
New-ADUser -SAMAccountName $_.SAMAccountName -Instance "'" + $_.userInstance + "'" -Name $_.name -DisplayName $_.displayName -Path "working.path.here" -GivenName $_.givenname -Surname $_.surname -userPrincipalName $_.userprincipalname -AccountPassword (ConvertTo-SecureString -String "Welcome01" -AsPlainText -Force) -PassThru | Enable-ADAccount;
#change status
$_.Status = 'AddMailbox';
} Catch {
#write any errors to error log.
$_ | Out-File C:\inetpub\wwwroot\melle\errors.log -Append;
}
}
}
$Users | ConvertTo-Csv | Out-File 'C:\inetpub\wwwroot\melle\data.csv'
Exit(Write-Host 'User was created in AD.');
}else {
Exit(Write-Host 'No data.csv file was found.');
}
As you already noticed, your current approach doesn't work. You're grabbing the whole content of the CSV and replace every instance. That Import-Csv statement actually gives you a data structure that allows you to change values. You just need to write it back afterwards.
This approach still is going to be error prone and you will run into issues with it. If I'm understanding you correctly, you want to keep track of the state and have multiple scripts that do different things. Sooner or later you will encounter situations where they overwrite each others changes and/or lock due to competing access requests. If you want to do it this way you should consider using a database that supports row based locking (most probably do). Otherwise you will need to find a way to make them run sequentially or implement row based locking yourself.
That said, one possible solution could look like the following. I haven't run it but the basic structure should be right. An example with this for overwriting changes would be the long time it can take to create a mailbox. As the file is only read at the start of the script and written at the end, it might change in-between.
#When encountering any error, stop the script.
$ErrorActionPreference = "Stop";
#Check if there is a data file.
$FileExists = Test-Path C:\inetpub\wwwroot\melle\data.csv
if($FileExists -eq $true) {
$Users = Import-Csv -Path "C:\inetpub\wwwroot\melle\data.csv"
$UsersThatNeedToBeCreated = $Users | Where-Object {$_.Status -eq 'CreateUser'};
# Check that we have users that need to be created, might need fine-tuning.
if($$UsersThatNeedToBeCreated -eq $null -or $UsersThatNeedToBeCreated.Count -eq 0){
# Write-Host doesn't have a meaningful return code, so you can separate those lines.
Write-Host 'No user with status CreateUser was found.'
Exit;
}else{
# This way it's only run once
Import-Module ActiveDirectory;
}
$Users | ForEach-Object {
$Status = $User.Status;
$userPrincipalName = $User.userPrincipalName;
$SAMAccountName = $User.SAMAccountName;
$userInstance = $User.userInstance;
$Name = $User.Name;
$displayName = $User.DisplayName;
$Path = '"' + $User.Path + '"';
$GivenName = $User.GivenName;
$Surname = $User.Surname;
$SIP = $userPrincipalName;
if($_.Status -eq 'CreateUser'){
try {
#create user
New-ADUser -SAMAccountName $SAMAccountName -Instance $userInstance -Name $name -DisplayName $displayName -Path "correct.path.com" -GivenName $givenname -Surname $surname -userPrincipalName $userprincipalname -AccountPassword (ConvertTo-SecureString -String "bla" -AsPlainText -Force) -PassThru | Enable-ADAccount;
# change status
$_.Status = 'AddMailbox';
} Catch {
# write any errors to error log.
$_ | Out-File C:\inetpub\wwwroot\melle\errors.log -Append;
}
}
}
$Users | ConvertTo-Csv -NoTypeInformation | Out-File 'C:\inetpub\wwwroot\melle\data.csv'
Write-Host 'User was created in AD.'
Exit
}else {
Write-Host 'No data.csv file was found.'
Exit
}

Move AD User using powershell

I know I can move an AD user using powershell. What i want to accomplish is moving a bunch of users based on their description. I have a csv file and in that csv their is a year of graduation column. I want all users that have a YOG from 2016 to 2022 moved to the High School OU.
I haven't tried writing the code yet. I was successful in powershell of grabbing user accounts based on dept but not description. Here is a some same data
"ID","FNAME","LNAME","BDATE","GRD","SCHID"
"111111","TEst","student1","19980601","2016","1480"
"222222","test","Student2","19980522","2017","1480"
"333333","test","Student3","19970813","2025","1479"
I've gone ahead and added the schoolcode to the csv file. I think this will be a lot easier to move the students to the correct ou based on this file. 1480 being elem, 1479 hs. Also here is the code I'm using toe create the AD accounts.
# Import active directory module for running AD cmdlets
Import-Module activedirectory
#Store the data from ADUsers.csv in the $ADUsers variable
$ADUsers = Import-csv userimport.csv
#Store report in log file in the $log variable
$log = "log.txt"
#Loop through each row containing user details in the CSV file
foreach ($User in $ADUsers)
{
#Read user data from each field in each row and assign the data to a variable as below
$Username = $User.ID
$Password = $User.BDATE
$Firstname = $User.FNAME
$Lastname = $User.LNAME
$Department = $User.GRD
$Company = $User.SCHID #This field refers to the OU the user account is to be moved to
#Check to see if the user already exists in AD
if (Get-ADUser -F {SamAccountName -eq $Username})
{
#If user does exist, give a warning
Write-Warning "A user account with username $Username already exist in Active Directory."
}
else
{
#User does not exist then proceed to create the new user account
"Processing started (on " + $date + "): " | Out-File $log -append
"--------------------------------------------" | Out-File $log -append
#Account will be created in the OU provided by the $OU variable read from the CSV file
New-ADUser `
-SamAccountName $Username `
-UserPrincipalName "$Username#clasd.net" `
-Name "$Firstname $Lastname" `
-GivenName $Firstname `
-Department "$Department" `
-Company "$Company" `
-EmailAddress "$Username#clasd.net" `
-Surname $Lastname `
-Enabled $True `
-Scriptpath "login.vbs" `
-DisplayName "$Firstname $Lastname" `
-Path "ou=users,ou=hs,dc=clasd,dc=net" `
-AccountPassword (convertto-securestring $Password -AsPlainText -Force) `
-ChangePasswordAtLogon $true
# Add User to Groups
#Add-ADPrincipalGroupMembership -Identity $Username -MemberOf "Elem","Elem Students"
Start-Sleep 3
# Move Users to appropiate OU based on School Code
$usr = import-csv userimport.csv
foreach ($User in $usr) {
if ($user.grd -in 2016){
Get-ADUser $User.ID | Move-ADObject -TargetPath 'OU=users,ou=hs,dc=clasd,dc=net'
}
}
}
}
As their AD Username is unique and already contained in your CSV, it's simply a case of checking if the GRD field is in the range 2016-2022 and then moving the account using the ID field:
$filepath = "C:\path\to\data.csv"
$csv = Import-CSV $filepath
foreach ($user in $csv) {
if ($user.GRD -in 2016..2022) {
Get-ADUser $user.ID | Move-ADObject -TargetPath 'OU=High School,DC=domain,Dc=com'
}
}
EDIT: Didn't see your comment that YOG is the Description field, and I've used GRD instead, let me know if this isn't correct?
EDIT2: My answer above would be run after every account is created not during your existing script, it is more efficient to put the account in the correct OU at creation like so:
foreach ($User in $ADUsers)
{
#Read user data from each field in each row and assign the data to a variable as below
$Username = $User.ID
$Password = $User.BDATE
$Firstname = $User.FNAME
$Lastname = $User.LNAME
$Department = $User.GRD
$Company = $User.SCHID #This field refers to the OU the user account is to be moved to
# Choose OU
Switch ($Department)
{
"2016" {$OU = 'OU=users,ou=hs,dc=clasd,dc=net'}
"2017" {$OU = 'OU=2017,OU=users,ou=hs,dc=clasd,dc=net'}
}
#Check to see if the user already exists in AD
if (Get-ADUser -F {SamAccountName -eq $Username})
{
#If user does exist, give a warning
Write-Warning "A user account with username $Username already exist in Active Directory."
}
else
{
#User does not exist then proceed to create the new user account
"Processing started (on " + $date + "): " | Out-File $log -append
"--------------------------------------------" | Out-File $log -append
#Account will be created in the OU provided by the $OU variable read from the CSV file
New-ADUser `
-SamAccountName $Username `
-UserPrincipalName "$Username#clasd.net" `
-Name "$Firstname $Lastname" `
-GivenName $Firstname `
-Department "$Department" `
-Company "$Company" `
-EmailAddress "$Username#clasd.net" `
-Surname $Lastname `
-Enabled $True `
-Scriptpath "login.vbs" `
-DisplayName "$Firstname $Lastname" `
-Path $OU `
-AccountPassword (convertto-securestring $Password -AsPlainText -Force) `
-ChangePasswordAtLogon $true
# Add User to Groups
#Add-ADPrincipalGroupMembership -Identity $Username -MemberOf "Elem","Elem Students"
Start-Sleep 3
}
}

New-Aduser : The object name has bad syntax

I have a script which i use to create bulk users from a csv file which works fine.
Import-Csv e:\temp\newemps.csv | %{
$ou = $_.ou
$firstname = $_.first
$lastName = $_.last
$accountName = $("{0}{1}" -f $firstname.Substring(0,1),$lastName).ToLower()
$description = $_.desc
$password = "Welcome1"
$name = "$firstName $lastName"
New-AdUser -SamAccountName $accountName -GivenName $firstName -UserPrincipalName "$accountName#ba.net" -Surname $lastName -DisplayName $name -Name $name -AccountPassword (ConvertTo-SecureString -AsPlainText $password -Force) -Enabled $true -Path $ou -Description $description -ChangePasswordAtLogon:$False
If ($_.Group -ne ""){
Add-adgroupmember -identity $_.group -members $accountName
}
If ($_.email -eq "y"){
Enable-Mailbox -Identity $accountName -Alias $accountName
Set-Mailbox $accountName -MaxSendSize 10mb -MaxReceiveSize 10mb
Get-CasMailbox $accountName -OwaEnabled:$false -ActiveSyncEnabled:$false
}
}
I was trying modify this script so that i could create some generic accounts that would not follow our typical convention. The input is a here-string as supposed to a csv as the only unique item is an Airport code. I have shortened the here-string for brevity.
$bases = #"
YAB
YEK
YYH
YHI
"#
$bases.Split("`n") | %{
$ou = "CN=Users,DC=BA,DC=NET"
$firstname = "$_".ToString()
$lastName = "Counter"
$accountName = "$_" + "Counter"
$description = "Base Front Counter"
$password = "Welcome1"
$name = "$firstName $lastName"
New-AdUser -SamAccountName $accountName -GivenName $firstName -UserPrincipalName "$accountName#ba.net" -Surname $lastName -DisplayName $name -Name $name -AccountPassword (ConvertTo-SecureString -AsPlainText $password -Force) -Enabled $true -Path $ou -Description $description -ChangePasswordAtLogon:$False
}
There is something about using a here-string that I am not accounting for. The only account it successfully creates is the one for YHI (The last one of the here-string). For all others it gives New-AdUser : The object name has bad syntax. Internet research shows many errors for csv-imports where the data has whitespace and other issues there but im not sure what the issue is here.
In the end I just made a csv file instead of using the here-string but I would like to know what i was doing wrong.
This worked for me. got rid of the null values and the new line values and just gave me each string value from each line. Seams there may have been some white space or some other characters that interfere if you just do split "`n"
$test = #"
user1
user2
user3
"#
$test.split(“`r`n”) | ForEach-Object {if($_){get-aduser $_}}