This blog has moved to http://ThePowerShellGuy.com
Greetings /\/\o\/\/
In this part sixth part of the AD series we will make a start of the script to import / create users from a CSV file (template generated in part 5 of this series).
# Load the CSV file with users
$newUsers = import-csv C:\PowerShell\NewUsers.csv
# the first user looks like this (see part 5)
PoSH>$newusers[0]
Name : NewUser0003
displayName : Roberto Tamburello
Description : Engineering - Roberto Tamburello
Room :
Telephone :
FirstName : Roberto
Initials :
LastName : Tamburello
Department : Engineering
Company :
HomeDir :
HomeDrive :
LogonScript :
Accountname : $222000-BOCQ2JHU74K1
Mail :
I will start by just echo-ing some of the properties to the screen in the first examples.
and I will start using a filter as we provide the objects on the pipeline :
# most Simple form Filter
filter new-AdUser {
if ($_.Name) {"CN=$($_.name)"} Else {throw "Name is Mandatory"}
}
# Check on the Name Property
PoSH>"foo" | new-AdUser
Name is Mandatory
At line:2 char:45
+ if ($_.Name) {"CN=$($_.name)"} Else {throw <<<< "Name is Mandatory"}
# if objects in pipeline have name property
PoSH>$newusers | new-AdUser
CN=NewUser0003
CN=NewUser0009
CN=NewUser0011
CN=NewUser0012
CN=NewUser0267
CN=NewUser0270
we will later switch to a function for this but I will start with a filter to show the difference
in this first filter you can see that $_ contains the current item and we can access the different field from the CSV file from the object, in this case we just echo it to the screen.
as we have seen in the second part of this series, all we really need to create a User is a CN, but we have also seen that the SamAccountname another mandatory property gets generated in that case and that that is not realy handy, as we most of the time want this the same as the CN name lets add a check for the property and if it's not there lets add it.
# added SamAccountname
filter new-AdUser {
# check for name field :
if ($_.Name) {"CN=$($_.name)"} Else {throw "Name is Mandatory"}
# If accountname is not given make it same as CN
if ($_.Accountname) {"SamAccountName = $($_.Accountname)"} Else {"SamAccountName = $($_.name)"}
}
# objects in pipeline have accountname property
PoSH>$newusers | new-AdUser
CN=NewUser0003
SamAccountName = $222000-BOCQ2JHU74K1
CN=NewUser0009
SamAccountName = $822000-KK9G22LQPGJV
CN=NewUser0011
SamAccountName = $A22000-RFN1CV2D2U5N
CN=NewUser0012
SamAccountName = $B22000-L10CLJU1NCSO
CN=NewUser0267
SamAccountName = $AA2000-R7OSI41L9LHR
CN=NewUser0270
SamAccountName = $DA2000-7UPIT07U0FPV
# Remove accountname property
PoSH>$newUsers |% {$_.accountname = ""}
# Now the SamAccountname will be generated the same as the CN
PoSH>$newusers | new-AdUser
CN=NewUser0003
SamAccountName = NewUser0003
CN=NewUser0009
SamAccountName = NewUser0009
CN=NewUser0011
SamAccountName = NewUser0011
CN=NewUser0012
SamAccountName = NewUser0012
CN=NewUser0267
SamAccountName = NewUser0267
CN=NewUser0270
SamAccountName = NewUser0270
As you can see, you can use this to keep the CSV file simple but extendable (you don't need to provide the samaccountname if you want it to be the same as the CN, but you CAN provide it if this is not the case ).
also as my exported users had generated samaccountname properties, I did clear them all so the samacountnames will be the same as the CN.
now to create the users we also need the the OU where to import the user, I will add this as a parameter to the function, but also make a check for a OU field in the CSV file to overrule this on a per user base.
also I will show some examples of how the OU gets parsed so you can use an OU object or the LDAP string :
# OU to import parameter
PoSH>[System.DirectoryServices.DirectoryEntry]$ImportOu = $mowOu
PoSH>[System.DirectoryServices.DirectoryEntry]$ImportOu = "OU=MowOu,DC=mow,DC=local"
PoSH>$ImportOu
out-lineoutput : Exception retrieving member "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "Unspecified error
"
# LDAP path to import parameter
PoSH>[System.DirectoryServices.DirectoryEntry]$ImportOu = "LDAP://OU=MowOu,DC=mow,DC=local"
PoSH>$ImportOu
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
# list possible constuctors
PoSH>[System.DirectoryServices.DirectoryEntry].GetConstructors() |% {"$_"}
Void .ctor()
Void .ctor(System.String)
Void .ctor(System.String, System.String, System.String)
Void .ctor(System.String, System.String, System.String, System.DirectoryServices.AuthenticationTypes)
Void .ctor(System.Object)
PoSH>[System.DirectoryServices.DirectoryEntry]$ImportOu = "LDAP://OU=MowOu,DC=mow,DC=local"
PoSH>$ImportOu
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
# Take care the LDAP path is CaseSensitive
PoSH>[System.DirectoryServices.DirectoryEntry]$ImportOu = "LDaP://OU=MowOu,DC=mow,DC=local"
PoSH>$ImportOu
out-lineoutput : Exception retrieving member "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "Unknown error (0x80005000)"
PoSH>
# added OU as parameter and as field to the filter
filter new-AdUser ([System.DirectoryServices.DirectoryEntry]$importOU){
# check for name field :
if ($_.Name) {"CN=$($_.name)"} Else {throw "Name is Mandatory"}
# If accountname is not given make it same as CN
if ($_.Accountname) {"SamAccountName = $($_.Accountname)"} Else {"SamAccountName = $($_.name)"}
if ($_.OU) {"OU = $($_.OU)"} Else {"OU = $($ImportOU.distinguishedName)"}
}
# output now looks like this :
PoSH>$newusers | new-AdUser $mowou
CN=NewUser0003
SamAccountName = NewUser0003
OU=MowOu,DC=mow,DC=local
CN=NewUser0009
SamAccountName = NewUser0009
OU=MowOu,DC=mow,DC=local
CN=NewUser0011
SamAccountName = NewUser0011
OU=MowOu,DC=mow,DC=local
CN=NewUser0012
SamAccountName = NewUser0012
OU=MowOu,DC=mow,DC=local
CN=NewUser0267
SamAccountName = NewUser0267
OU=MowOu,DC=mow,DC=local
CN=NewUser0270
SamAccountName = NewUser0270
OU=MowOu,DC=mow,DC=local
# Some extra tricks using select like in part 5 of this series
# using select to add the OU property on the fly
PoSH>$newusers | select *,@{e={"OU=MowOtherOU,DC=mow,DC=local"};name='OU'} | new-adUser
CN=NewUser0003
SamAccountName = NewUser0003
OU = OU=MowOtherOU,DC=mow,DC=local
CN=NewUser0009
SamAccountName = NewUser0009
OU = OU=MowOtherOU,DC=mow,DC=local
CN=NewUser0011
SamAccountName = NewUser0011
OU = OU=MowOtherOU,DC=mow,DC=local
CN=NewUser0012
SamAccountName = NewUser0012
OU = OU=MowOtherOU,DC=mow,DC=local
CN=NewUser0267
SamAccountName = NewUser0267
OU = OU=MowOtherOU,DC=mow,DC=local
CN=NewUser0270
SamAccountName = NewUser0270
OU = OU=MowOtherOU,DC=mow,DC=local
# or combine the standard OU with some overruled users
PoSH>$newusers | select *,@{e={if ($_.name -eq 'NewUser0270'){"OU=MowOtherOU,DC=mow,DC=local"} else {""}};name='OU'} | new-adUser $mowOU
CN=NewUser0003
SamAccountName = NewUser0003
OU = OU=MowOu,DC=mow,DC=local
CN=NewUser0009
SamAccountName = NewUser0009
OU = OU=MowOu,DC=mow,DC=local
CN=NewUser0011
SamAccountName = NewUser0011
OU = OU=MowOu,DC=mow,DC=local
CN=NewUser0012
SamAccountName = NewUser0012
OU = OU=MowOu,DC=mow,DC=local
CN=NewUser0267
SamAccountName = NewUser0267
OU = OU=MowOu,DC=mow,DC=local
CN=NewUser0270
SamAccountName = NewUser0270
OU = OU=MowOtherOU,DC=mow,DC=local
# update the CSV file
PoSH>$newusers | select *,@{e={if ($_.name -eq 'NewUser0270'){"OU=MowOtherOU,DC=mow,DC=local"} else {""}};name='OU'} | e
xport-csv -not c:\powershell\modUsers.csv
PoSH>import-csv c:\powershell\modUsers.csv | ft name,ou
Name OU
---- --
NewUser0003
NewUser0009
NewUser0011
NewUser0012
NewUser0267
NewUser0270 OU=MowOtherOU,DC=mow,DC=local
Note that you can just edit the CSV file but I did use select again like in the export examples in part 5 of the AD series,to show that you don't need to use the object and can nest any kind of script in in.
Now we have all the properties to start lets change the script to not only echo the properties but actualy do something.
#
# the first version that is actualy working :
filter new-AdUser ([System.DirectoryServices.DirectoryEntry]$importOU){
# check for name field :
if ($_.Name) {$CN= $_.name} Else {throw "Name is Mandatory"}
# Use default OU or connect to OU given in CSV file
if ($_.OU) {
$OU = new-object System.DirectoryServices.DirectoryEntry("LDAP://$($_.OU)")
}
Else {
$OU = $ImportOU
}
# create the new user :
$NewUser = $ou.get_Children().add("CN=$($_.name)",'user')
$NewUser.commitChanges()
# If accountname is not given make it same as CN
if ($_.Accountname) {$newUser.sAMAccountName = $_.Accountname} Else {$newUser.sAMAccountName = $_.name}
$NewUser.commitChanges()
}
Now let's create the users in the CSV file, where I will overrule the OU for one account.
# make other OU to test
PoSH>($root.get_Children().Add("OU=MowOtherOU","organizationalUnit")).commitChanges()
# one account on other OU
PoSH>import-csv c:\powershell\modUsers.csv | new-AdUser $mowou
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
SamAccountName = NewUser0003
{OU=MowOu,DC=mow,DC=local}
SamAccountName = NewUser0009
{OU=MowOu,DC=mow,DC=local}
SamAccountName = NewUser0011
{OU=MowOu,DC=mow,DC=local}
SamAccountName = NewUser0012
{OU=MowOu,DC=mow,DC=local}
SamAccountName = NewUser0267
{OU=MowOtherOU,DC=mow,DC=local}
SamAccountName = NewUser0270
# check if the users are there :
PoSH>$mowou.get_Children() |? {$_.name -like "NewUser*"} | ft cn,distinguishedName,sAMAccountName
cn distinguishedName sAMAccountName
-- ----------------- --------------
{NewUser0003} {CN=NewUser0003,OU=MowOu,DC=mow,DC=l... {NewUser0003}
{NewUser0009} {CN=NewUser0009,OU=MowOu,DC=mow,DC=l... {NewUser0009}
{NewUser0011} {CN=NewUser0011,OU=MowOu,DC=mow,DC=l... {NewUser0011}
{NewUser0012} {CN=NewUser0012,OU=MowOu,DC=mow,DC=l... {NewUser0012}
{NewUser0267} {CN=NewUser0267,OU=MowOu,DC=mow,DC=l... {NewUser0267}
{NewUser0270} {CN=NewUser0270,OU=MowOu,DC=mow,DC=l... {NewUser0270}
# Clean up created users for next test
PoSH>$mowou.get_Children() |? {$_.name -like "NewUser*"} |% {$mowou.get_Children().Remove($_)}
PoSH>$mowou.get_Children() |? {$_.name -like "NewUser*"} | ft cn,distinguishedName,sAMAccountName
PoSH>
Thats it for now, in the next post we will add some more properties and enable them etc. as in the third part of this series.also we will add some more checking and errorhandling etc, make it into a function on the way, and will add some more functionality as creating the Homedirectory etc. as the MMC also does.
Enjoy,
Greetings /\/\o\/\/
Tags : Monad msh PowerShell