Creating a Script to import users from a CSV to AD - powershell

I'm trying to build a script that will take a CSV with the fields
firstname, lastname, password
and create a user in AD in a specific OU with that info. I've done a bunch of googling, and this is what I've come up with (from this blog):
Import-Csv .\userImport.csv | ForEach-Object {
New-ADUser
-Name $_.DisplayName
-UserPrincipalName $_.UserPrincipalName
-SamAccountName $_.Username
-FirstName $_.FirstName
-DisplayName $_.DisplayName
-LastName $_.Lastname
-Path $_.Path
-AccountPassword (ConvertTo-SecureString $_.Password -AsPlainText -force)
-Enabled $True
-PasswordNeverExpires $True
-PassThru
}
I have a few questions:
I want to specify the OU in my command, instead of having it be in the CSV. Can I just change it to:
-Path OU=MyOU,DC=Domain,DC=Local
What is the -PassThru line for?
Is the -AccountPassword line correct? I got that from a blog that suggested this is the right way to take a password and set it as my AD user's password.
Do I need the PrincipalName, SamAccountName and DisplayName all as separate fields? This can be as minimal as possible, at least for now.
Any tips or changes you would make? This is my first time doing a script like this so I'm willing to learn.

Yes, you can specify parameters whichever way you like, they don't need to come from the input file.
-PassThru makes New-ADUser echo the created user object. By default the cmdlet doesn't return anything.
Yes, the -AccountPassword argument is correct, provided the password field from the CSV contains the plaintext password.
You don't necessarily have to have a separate CSV field for each parameter argument if you can construct an argument from existing field values. For instance, you most likely can create values like DisplayName or SamAccountName from first and last name, e.g. like this:
-SamAccountName ($_.firstname.Substring(0,1) + $_.lastname).ToLower()
-DisplayName ('{0} {1}' -f $_.firstname, $_.lastname)
You also don't need to specify every argument. For instance, the UPN (User Principal Name) will automatically be generated when omitted, and the display name will default to the name.
You can't wrap the lines like you have. PowerShell can't read your mind and won't know that you intend to continue the statement in the next line unless you tell it that or the statement is obviously incomplete. Use backticks to escape the linebreaks. Also, the parameters for first and last name are -GivenName and -Surname, not -FirstName and -LastName.
$csv = '.\userImport.csv'
$ou = 'OU=MyOU,DC=Domain,DC=Local'
Import-Csv $csv | ForEach-Object {
$name = '{0} {1}' -f $_.firstname, $_.lastname
$acct = ($_.firstname.Substring(0,1) + $_.lastname).ToLower()
$pw = ConvertTo-SecureString $_.password -AsPlainText -Force
New-ADUser -Name $name `
-SamAccountName $acct `
-GivenName $_.firstname `
-Surname $_.lastname `
-Path $ou `
-AccountPassword $pw `
-Enabled $true `
-PasswordNeverExpires $true `
-PassThru
}

OU - If you want them all in the same OU, you can hard code it (remember the quotes)
-Path "OU=MyOU,DC=Domain,DC=Local"
-PassThru
The -PassThru parameter lets you request output from cmdlets that return no output by default. (The PassThru Parameter: Gimme Output)
i.e. Instead of New-ADUser just executing and then returning you to the next line, it will actually print out the new user created info to the prompt.
Yes the -AccountPassword takes a SecureString as the argument. The command ConvertTo-SecureString converts a plain text string to a SecureString, which then can be passed to the -AccountPassword parameter
You don't need -UserPrincipalName. You do need -SamAccountName. -DisplayName can be changed to:
-DisplayName "$($_.FirstName) $($_.Lastname)"
This is a pretty standard script for mass producing accounts, so it is pretty good the way it is. The only change I would look at is -PasswordNeverExpires $True You typically only really set the Password Never Expires on Service accounts, so if you are creating plain old user accounts, you wouldn't need it.

Related

Powershell Instance Parameter

I am automating the creation of user accounts in our Windows AD. I am trying to copy the permissions from one account to another,(like you would if you right click and copied a user inside of the "Active Directory Users and Computers" application) but when using the cmdlet 'New AD-User' and passing in a variable to the 'instance' parameter, it does nothing different than if I do not pass the variable at all.
This is what I am using to obtain the $userInstance variable:
$userInstance = Get-ADUser -Identity $department User
This is the code I am using to create a new user:
New-ADUser `
-SamAccountName $userName `
-UserPrincipalName "$userName#123.COM" `
-Name "$firstName $lastName" `
-GivenName $firstName `
-Surname $lastName `
-Enabled $true `
-DisplayName "$firstName $lastName" `
-City $city `
-PostalCode $zip `
-Company $company `
-State $state `
-EmailAddress $email `
-Department $department `
-Instance $userInstance `
-AccountPassword (ConvertTo-SecureString "1234" -AsPlainText -Force)
When I run this command, it does the same exact thing as if I ran this command without the instance parameter.
New-ADUser `
-SamAccountName $userName `
-UserPrincipalName "$userName#123.COM" `
-Name "$firstName $lastName" `
-GivenName $firstName `
-Surname $lastName `
-Enabled $true `
-DisplayName "$firstName $lastName" `
-City $city `
-PostalCode $zip `
-Company $company `
-State $state `
-EmailAddress $email `
-Department $department `
-AccountPassword (ConvertTo-SecureString "1234" -AsPlainText -Force)
Am I missing something? I do not understand what the 'instance' parameter is supposed to be doing if it only copies certain attributes that are easily obtainable(state, company, city). Is there something out there that actually copies a template account or do I need to write a loop that goes through every single attribute, permission, and group in the template account that provides some sort of meaning to my organization and assign them manually?
What exactly do you mean by "permission"?
Permissions on resources are set based on the objectSid of a user. Since this is unique to every user you can never "copy" them (and related permissions) to a new user.
Group memberships are stored on groups not on users. The memberOf attribute is just a "backLink" so this won't be copied neither.
Group membership needs to be added in a separate step, e.g. by using
Add-ADGroupMember
cmdlet in PowerShell...
"Permissions" might not have been the word I was looking for necessarily. I wanted to create the user and assign them the same groups and directory location as a previous User. I was able to add group membership to my new users by using the method stated by #Oliver Hauck earlier
Add-ADGroupMember
This aided me in my findings, but what I desired was to not have to write long, repetitive switch code for each new employee type, along with their groups, we could onboard. In hopes that someone sees this and doesn't feel intrigued in writing super long, boring switch code, I wanted to share how I achieved this if it helps anyone else in the future. I still obtained the $userInstance variable in the same way, but adding the -Property parameter defined to MemberOf
$userInstance = Get-ADUser -Identity $department User -Properties MemberOf
I then used the $userInstance variable to obtain the properties I needed from it (Groups to copy, Directory Path)
//Obtains the Path from the copied User, without their common name (CN) attached
$path = $userInstance.DistinguishedName.split(",",2)[-1]
I still created the new user with the same command as above but added the -Path parameter to assign the directory path to the New-ADUser cmd
New-ADUser `
-SamAccountName $userName `
-UserPrincipalName "$userName#123.COM" `
-Name "$firstName $lastName" `
-GivenName $firstName `
-Surname $lastName `
-Enabled $true `
-DisplayName "$firstName $lastName" `
-City $city `
-PostalCode $zip `
-Company $company `
-State $state `
-Path $path `
-EmailAddress $email `
-Department $department `
-AccountPassword (ConvertTo-SecureString "1234" -AsPlainText -Force)
And here is how I obtained and assigned the Group Membership to the New User
//Obtains the groups to be copied from the existing User
$refGroups = $userInstance.MemberOf
//Adds AD Group Membership to User
$refGroups | Add-ADGroupMember -Members $userName

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

Take two variables and put them on the same line

I have a script (thanks in largely to this site) that takes names of people from a text file and splits them into FullName, FirstName, LastName and FirstLetter.
I now plan on importing these into AD and largely, I know what I am doing.
However, I am struggling with the following section
New-ADUser -Name
I would like to do something like this
$result.ForEach({
New-ADUser -Name $_.FirstName + $_.LastName -GivenName $_.FirstName -Surname
$_.LastName -AccountPassword
(ConvertTo-SecureString -AsPlainText "APassword!" -Force)
-PasswordNeverExpires $True -UserPrincipalName
"$_.FirstLetter+$_.LastName#vennershipley.co.uk"
-SamAccountName "$_.FirstLetter $_.LastName"
-Path 'OU=Users,OU=London,OU=Sites,DC=MyCompany,DC=local'
})
This returns a error stating 'The name provided is not a properly formed account name'. Now I presume this is because, if I do this
$result.FirstName + $result.LastName
It returns the 3 first names and the 3 last names on seperate lines, so I would presume it is trying to name each person with a name on two seperate lines like
FirstName
LastName
So how would I make the result display on one line, presuming this is the issue?
Also, if there are better ways of doing the AD Creation then please advise, I am still learning!
Enclose the two variables in parentheses to get the results of the addition just like you did in the ConvertTo-SecureString part:
$result.ForEach({
New-ADUser -Name ($_.FirstName + "" + $_.LastName) -GivenName $_.FirstName -Surname
$_.LastName -AccountPassword
(ConvertTo-SecureString -AsPlainText "APassword!" -Force)
-PasswordNeverExpires $True -UserPrincipalName
"$_.FirstLetter+$_.LastName#vennershipley.co.uk"
-SamAccountName "$_.FirstLetter $_.LastName"
-Path 'OU=Users,OU=London,OU=Sites,DC=MyCompany,DC=local'
})
Now, as you asked for better ways, see few possibilities including Splatting parameters and string.format (-f) Also notice the differents between the string formatting in the Name and SamAccountName Parameters:
foreach ($user in $result)
{
$Params = #{
Name = "$($user.FirstName) $($user.LastName)"
GivenName = $user.FirstName
Surname = $user.LastName
AccountPassword = (ConvertTo-SecureString -AsPlainText "APassword!" -Force)
PasswordNeverExpires = $true
UserPrincipalName = "{0}{1}#vennershipley.co.uk" -f $user.FirstName.Chars(0),$_.Lastname
SamAccountName = "{0}{1}" -f $user.FirstName.Chars(0),$_.Lastname
Path = 'OU=Users,OU=London,OU=Sites,DC=MyCompany,DC=local'
}
New-ADUser #Params
}
One more thing: to check everything is good just before executing this in production, i suggest you to add the -WhatIf parameter to the New-ADUser cmdlet, it will demonstrate the operation but will not run it

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.

Creating Bulk Users in AD With CSV

I am working on a Power Shell script that will create bulk users in Active Directory. As stated in a previous post, I'm fairly new to Power Shell and want to be safe before I go live with anything. Below is the script, some of it borrowed. It will be reading data from the .csv noted in the Import-CSV cmdlet. Ideally, this would create the user and define the user's full name, first name, last name, username, SAM name, e-mail, title, description and manager. It would also set a password.
I would love any feedback on how the below script looks. Please let me know if you have any questions or need any additional information.
Import-Module activedirectory
$ADUsers = Import-CSV C:\scripts\hourlyimport.csv
foreach ($User in $ADUsers)
{
#read user data from each field in each row and assign the data to a variable as below
$Username = $User.username
$Firstname = $User.firstname
$Lastname = $User.lastname
$Password = $User.password
$OU = $User.ou
$Title = $User.title
$Manager = $User.manager
#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. Say wha?!?"
}
else
{
#if user does not exist then proceed to create the new user account
#account will be created in the OU provided by the $OU variable read from the CSV file
New-ADUser `
-SamAccountName $Username `
-UserPrincipalName "$Username#thredup.com" `
-Email "$Username#thredup.com" `
-Name "$Firstname $Lastname" `
-GivenName $Firstname `
-Surname $Lastname `
-Enabled $True `
-DisplayName "$Lastname, $Firstname" `
-Path $OU `
-Description "$Title" `
-Title "$Title" `
-Manager "$Manager" `
-AccountPassword (convertto-securestring $Password -AsPlainText -Force)
}
}
Looks pretty good to me. You are somewhat inconsistent with the use of ", for example you don't need to write -Title "$Title", you can leave away the " in this case.
You could probably do some fancy optimization with splatting here, reducing the assignments, but since it is a quite unknown feature among many readers I wouldn't go for it here.
One thing I'm missing is error handling. With the default settings, your script will print out errors when something goes wrong, but continue the loop. Is this intended? It is often good practice to state your intention explicitly by setting $ErrorActionPreference at the start of your script.