Create BULK Mailbox users – Powershell – [Exchange Server 2010]
Hello Everyone,
Time for my second blog, i was working on and off for the last few days on the powershell script, using which you can provision new users.
Script?
For what? – Create new mailbox enabled AD users
Input Method? – a CSV file
First of all thanks to “Don Jones” for writing such an eloborate blog on technet on how to setup this provisioning, you can read Don’s blog from the below link.
http://technet.microsoft.com/en-us/magazine/2009.03.windowspowershell.aspx?pr=blog
For those newbies like me to powershell, POWERGUI is a cool little editor for writing powershell scripts, you can download it from the below link.
http://www.powergui.org/downloads.jspa
Now lets get to the tasks ahead.
First lets take a look at the CSV file, see the screenshot below:
Note the Header of each field, those don’t look like standard AD attribute name, well we will tackle them when we actually write the powershell script.
Script will consist of 2 blocks , the work of the first block is just to read the CSV file and for each and every line of the CSV will be converted into an HASHTABLE and this hashtable will be fed in to the second script block.
Below is the complete code:
Function ReadCSV{
Param([string]$fileName)
$users = Import-Csv $fileName
foreach ($user in $users){
$ht = @{
'givenName'=$user.fn
'sn'=$user.ln
'displayName'=$user.dispname
'alias'=$user.alias
'samAccountName'=$user.alias
'userPrincipalName' = $user.upn
'database' = $user.Database
'organizationalUnit' = $user.ou
'name' = ($user.fn + $user.sn)
}
Write-Output $ht
}
}
Function CreateUser{
Param($userInfo)
$secureString = ConvertTo-SecureString "K1ll31ll$1234" -AsPlainText –Force
New-Mailbox -Name $userInfo['name' ]`
-Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] `
-SamAccountName $userInfo['alias'] -Database $userInfo['Database']`
-FirstName $userInfo['givenName'] -LastName $userInfo['sn'] `
-OrganizationalUnit $userinfo['organizationalUnit']`
-DisplayName $userInfo['DISPLAYNAME'] -Password $secureString -ResetPasswordOnNextLogon $true
}
Function CreateMailbox{
PROCESS
{
CreateUser $_
}
}
ReadCSV c:\Scripts\UserList_10.csv | CreateMailbox
Lets take a look the script blocks closely.
Function ReadCSV {
Param([string]$fileName)
$users = Import-Csv $fileName
foreach ($user in $users){</span>
$ht = @{
'givenName'=$user.fn
'sn'=$user.ln
'displayName'=$user.dispname
'alias'=$user.alias
'samAccountName'=$user.alias
'userPrincipalName' = $user.upn
'database' = $user.Database
organizationalUnit' = $user.ou
'name' = ($user.fn + $user.sn
}
Write-Output $ht
I guess, you all came to know the purpose of the function from the function name itself, well you are right, this function takes a csv file path as the input and then imports that csv file.
Using the command Import-Csv $fileName.
Output of this command is stored on to the $users variable, in the next line you can see that using a for each loop, each line of the csv is fed into the $ht hashtable
For example, as you have in the screenshot of the csv file, displayNAme value of the hastable will be picked from the CSV file and stored onto the $ht hashtable, in this scenario it will be “Bhat, Shridhar”
Once all the fields mentioned here are loaded to the the $ht hashtable, then using the write-output command it is passed on to the next pipeline
Just by the name you may wonder, that the purpose of “Write-Output” is simply to write out some output, but that is not the case, it will feed each hashtable entry to the proceeding pipeline, in our case the second script block which will actually use this info and create the mailboxes.
You can read about “Write-Output” here.
Lets jump to the next script block.
Function CreateUser{
Param($userInfo)
$secureString = ConvertTo-SecureString "K1ll31ll$1234" -AsPlainText –Force New-Mailbox -Name $userInfo['name' ]`
-Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] ` -SamAccountName $userInfo['alias'] -Database $userInfo['Database']`
-FirstName $userInfo['givenName'] -LastName $userInfo['sn'] `
-DisplayName $userInfo['DISPLAYNAME'] `
-Password $secureString -ResetPasswordOnNextLogon $true
}
Notice this function takes in a parameter $userinfo , meaning the hashtable from the previous script block, you will understand better, when we look at the last step of this script, for now, it takes in a parameter.
Then, all it does is that , it uses the “New-Mailbox” cmdlet and then feeds in the parameter which it recieved from the hastable and then uses them as a parameter for the “New-Mailbox” cmdlet.
Notice this line –
$secureString = ConvertTo-SecureString "K1ll31ll$1234" -AsPlainText –Force
This for me not wanting to enter a password for each and every user, so i am forcing the script to use this plain text as a password.
Function CreateMailbox{
PROCESS{
CreateUser $_
}
}
This is just a blanket function from which we call the CreateUser function, this is basically to modularise the script.
Lets look at the final bit, which is the actual flow of the script.
ReadCSV c:\Scripts\UserList_10.csv | CreateMailbox
Notice, first we are calling the ReadCSV function and give it a csv file path as a parameter and then it is piped to the CreateMailbox function.
So when the first line of the csv file is read, it take all the user details into a hashtable and then feeds that info to the CreateMailbox function, which in turn , using the new-mailbox cmdlet creates the mailbox enabled AD user.
Output of the Script:
Actually i used mutiple names in the CSV files, which i didnt show in the first screenshot.
Below is the screenshot from “Active Directory Users and Computers” showing the user objects.
I user Windows Server 2008 R2 + Exchange 2010″
This one is from the Exchange 2010 Management Console.
Time to sleep, it is 6AM, i better sleep now
.
~F0x
1 |
thiyagu :: Feb.23.2010 :: PowerShell :: 73 Comments »



Thank you for your posting but i have some problem. Our usernames contains Turkish Character (ö,ü,?,?,?…) . So this characters not implemented correctly. These are implemented ? character. Can you solved this problem
Hello,
Nice script. It really looks usefull. I need you to clarify something for me though. Where should i run this script on ? exchange or active directory ?
you need to run on exchange server.
Fantastic post – helped me quite a bit. Thank you!
Hey, I got a question.
We’re migrating from an older mailserver to a new (not exchange) and we’re using Active Directory. I want to create mailboxes using this method but what happens if I already have AD accounts and just want to create Exchange mailboxes for them? Is this what this script does? Or does this script create a whole new user?
this script creates a whole new user, in your scenario, you can change this script to ur need by changing the cmdlet new-mailbox to enable-mailbox
Great script. What if there are other ldap attributes such as telephone number to add along with everything else. Can we just add the correct ldap attribute to the CSV file?
yes you can, just add the required property in the csv file and then in the hash table add a property for that , then in the creation of the mailbox, set that property.
I’m getting this:
Missing expression after unary operator ‘-’.
At C:\Scripts\add-user.ps1:23 char:3
+ - <<<< Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] `
+ CategoryInfo : ParserError: (-:String) [], ParseException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
can you post that full line over here?
@thiyagu
Missing expression after unary operator ‘-’.
At C:\Scripts\add-user.ps1:23 char:3
+ – <<<< Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] `
+ CategoryInfo : ParserError: (-:String) [], ParseException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
I think it may have to do with the fact that I get this:
code]Add-PSSnapin : The Windows PowerShell snap-in ‘Microsoft.Exchange.Management.PowerShell.Admin.’ is not installed on thi
s machine.
At line:1 char:13
+ Add-PSSnapin <<<< Microsoft.Exchange.Management.PowerShell.Admin.
+ CategoryInfo : InvalidArgument: (Microsoft.Excha…werShell.Admin.:String) [Add-PSSnapin], PSArgumentEx
ception
+ FullyQualifiedErrorId : AddPSSnapInRead,Microsoft.PowerShell.Commands.AddPSSnapinCommand
[/code]
After I try to run this:
Sorry. I get this:
when I try to load the excahnge management tools using this:
yep, your are right, you need that to be installed for this script to work.
the cmdlet new-mailbox in the script needs this powershell snapping.
Well, I ran the install CD and management tools are installed. Any ideas?
needed to run this:
was ur issue solved? u have to run this on a machine where you have rights on the exchange box + run in the powershell session where you have the above mentioned snaping loaded.
Yes. I didn’t realize that the add-pssnapin had to be run *every* time you open Powershell.
This script puts the users into Users Container of Active Directory. The first Function defines ‘organizationalUnit’ = $user.ou but does it use that data from the CSV file?
Okay, You got to add this to the New-Mailbox cmdlet in the function CreateUser
thanks for that josh
updated it.
[...] LinkedIn [...]
i was hoping someone might be able to help me
i have a problem using an exchange 2k3 in 2k3 Server Forest where a powershell script has used RUS to create mailboxes for AD accounts after populating homemdb mta and storagegroups properties
but the problem i have is that the created accounts don`t have an exchange alias
( viewable from the exchange general tab in AD with Exchnage management tools installed)
how do i programmatically access and populate the alias field using powershell.
the mailboxes have been created but without an Exchange alias the access the end result is a fail
also the AD accounts have an alias set on the AD object i am not using any quest-ad plug ins
and the accounts are useable apart from exchange access
Thank you for your help
Is it possible to set different password instead of using the same password for all accounts ? soforth how
add a new column to the csv file and then put the password there , read the line in the hash table and the “$secureString = ConvertTo-SecureString “K1ll31ll$1234″ -AsPlainText –Force”
use that to change it to ur required needs .
@thiyagu
Dear Thiyagu,
Its unclear for me – pretty newbie to exchange .. what is this part “K1ll31ll$1234? is it the password string ?
gud script, but it will be better if you bit elobrate where to put script,the path, what will be the CSV file name and script name…
@Warsa, yes that is the password that is set for the users which are being created.
@anni, if you see the last line of the script, it has the path for the .csv file which is read and then imported to create the bulk users.
script name could be anything you want.
Hi,
This is a great script! Thanks so much for putting it out there, it is really helping me learn a lot.
I am trying to use a CustomAttribute to store Employee ID’s, but I cant seem to find or figure out the right syntax for that. Before we had Exchange 2010 in our environment, we used the employeeID attribute in AdsiEdit. The following article explains why I was looking to store the employeeID in a CustomAttribute:
http://technet.microsoft.com/en-us/library/ee423541.aspx#CA
If I manually put in the value for a CustomAttribute, in AdsiEdit it appears to be with the extensionAttribute. But If I look at the value with the Exchange Shell it appears to be with CustomAttribute.
Thank you for any help!
whatever u see in the adsiedit is the actual attribute, the exchagne shell may have customattirbute but actual name is extensionattribute
yes, u just have to modify the script to add that
is that what you are looking for…??
I modified the script to use the extensionattribute. It looks like im having a similar issue to Tuffy, but I am running the script on the Exchange 2010 server.
Missing expression after unary operator ‘-’.
At C:\script.ps1:34 char:3
+ – <<<< extensionattribute1 $userInfo['extensionattribute1']`
+ CategoryInfo : ParserError: (-:String) [], ParseException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
Is there a way to set msExchHideFromAddressLists=True on all the new users in this script so that they do not appear in the GAL? At what place would that have to be added in the script?
Is it an attribute that can’t be set until the mailbox is actually created?
yes, only after the enable-mailbox cmdlet has run the attribute will be avaiable.
why do u want to set this? if this is a new mailbox?
I work for a college and our policy has been not to include our students in the GAL. It has definately caused some communication problems, but I think people don’t want all the student addresses cluttering up the GAL when they are looking for an employee.
I would prefer to let all the users show up in the GAL but thats not allowed yet. Another address list with just the students in it would probably make the most sense for us.
yeah, another address list is a good approach,
do u still need help with the script to set that hide from gal attribute or u figured it out?
I was just curious about the hide from gal attribute.
I was never able to get around getting the extensionattributes to work. I either get the error I posted above or the following one. I am not sure if it is a syntax error or that I need a PowerShell snap in.
A positional parameter cannot be found that accepts argument ‘-extensionattribute1′.
+ CategoryInfo : InvalidArgument: (:) [New-Mailbox], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,New-Mailbox
A positional parameter cannot be found that accepts argument ‘-extensionattribute1′.
+ CategoryInfo : InvalidArgument: (:) [New-Mailbox], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,New-Mailbox
I am getting the following error .. please help.
WARNING: An unexpected error has occurred and a Watson dump is being generated:
Invalid URI: The hostname could not be parsed.
Invalid URI: The hostname could not be parsed.
+ CategoryInfo : NotSpecified: (:) [New-Mailbox], UriFormatException
+ FullyQualifiedErrorId : System.UriFormatException,Microsoft.Exchange.Management.RecipientTasks.NewMailbox
i am getting the same error as mentioned it here earlier as ”
Missing expression after unary operator ‘-’.
At C:\Scripts\add-user.ps1:23 char:3
+ – <<<< Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] `
+ CategoryInfo : ParserError: (-:String) [], ParseException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
etc….
as said above this is because of the snapins not installed on this machine.
i have windows 2008 r2 and exchange 2010 with powershell managment tool installed.
please guide me..
I am getting the following error:
PS C:\Users\Administrator> C:\scripts\Create_Users.ps1
Missing expression after unary operator ‘-’.
At C:\scripts\Create_Users.ps1:28 char:3
+ – <<<< DisplayName $userInfo['DISPLAYNAME'] -Password $secureString -ResetPasswordOnNextLogon $true
+ CategoryInfo : ParserError: (-:String) [], ParseException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
Thanks, great job !
Hi Thiyagu,
We want to batch mailbox enable EXISTING AD users.. how different would that be to the steps in your post above?
Thanks
Randeep
it will be similar except that you wont be using new-mailbox cmdlet and will be using enable-mailbox and you have to check if the user already has a mailbox or not (just to be sure)
you could also have a list of users in a text file and loop thru it and enable them one by one.
Great post just what I was looking for Thanks! We aew getting the following when running this script on a Hosting enabled Exchange 2010 SP1 server. thoughts?
Unexpected token ‘in’ in expression or statement.
At line:1 char:91
+ Function ReadCSV{ Param([string]$fileName) $users = Import-Csv $fileName foreach ($user in <<<< $users){ $ht =
@{ 'givenName'=$user.fn 'sn'=$user.ln 'displayName'=$user.dispname 'alias'=$user.alias 'samAccountName'=$user.alias 'u
serPrincipalName' = $user.upn 'database' = $user.Database 'organizationalUnit' = $user.ou 'name' = ($user.fn + $user.sn
) } Write-Output $ht }}Function CreateUser{ Param($userInfo) $secureString = ConvertTo-SecureString "K1ll31ll$1234" -As
PlainText -Force New-Mailbox -Name $userInfo['name' ]` -Alias $userInfo['alias'] -UserPrincipalName $userInfo['us
erPrincipalName'] ` -SamAccountName $userInfo['alias'] -Database $userInfo['Database']` -FirstName $userInfo['givenName
'] -LastName $userInfo['sn'] ` -OrganizationalUnit $userinfo['organizationalUnit']` -DisplayName $userInfo['DISPLAYNAME
'] -Password $secureString -ResetPasswordOnNextLogon $true}Function CreateMailbox{ PROCESS { CreateUser $_ }} ReadCSV c
:\Scripts\UserList_10.csv | CreateMailbox
+ CategoryInfo : ParserError: (in:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Hi, I am getting this error message when trying running the script.
Unexpected token ‘&’ in expression or statement.
At C:\Users\lom\AppData\Local\Temp\2\bd80c4ee-88e0-4a68-81ee-4a56923696ff.ps1:5 char:6
+ $ht& <<<< nbsp; = @{
+ CategoryInfo : ParserError: (&:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
@MOLUC,
remove that “&” after $ht and give it a try
Hi, is ther any way to add a Custom attribute of 15 into the user creation? I would like my user to inherit the email address policies as well as the address book policies I created.
Thank you
Regards
kobus
Just wanted to say thanks for this extremely useful article. For my purposes, I had to modify ‘name’ to equal $user.name, since Exch’10 would truncate the last name using the script as is, causing users with the same first name as existing users to fail, with no mailbox created (and making all users that were created show up with just their first name in AD/in the CN field). Otherwise, worked great.
Best, Jim
Is there a way to add the new users to a security/distribution group by specifying the name(s) of the group in the CSV?
New-Mailbox : Cannot bind argument to parameter ‘Name’ because it is null.
At C:\bulkusers.ps1:23 char:20
+ New-Mailbox -Name <<<< $userInfo['name' ]`
+ CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Exchange.Management.RecipientTa
sks.NewMailbox
Anyone ever see this particular issue?
@Dolph92, if you are importing from a CSV file, make sure you don’t have extra commas in the header row. For instance, an extra comma the end of the header row. That’ll hose things up. And, obviously, be sure you have a column called Name.
Thanks for this scrip, it works perfect for my situation.
Good script, it works fine.
Hi Im getting the following error when I try to run this powershell script on the Exchange 2010 EMS:
Unexpected token ‘&’ in expression or statement.
At C:\create.ps1:5 char:6
+ $ht& <<<< nbsp; = @{
+ CategoryInfo : ParserError: (&:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
Any ideas?
Fixed it…When I copied the script off this web page it put in some extra characters where there should be blank spaces in the text of the script. Just deleted those extra characters and ran the script again…Works like a treat. Nice one….
I keep geting this error not able to run it!
Cannot bind argument to parameter ‘Name’ because it is an empty string.
+ CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindingValidationExcepti
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,New-Mailbox
Can anyone give me some light in this?
Hi,
Ha been runing the script but get this error msg.
[PS] C:\script>.\userlist.ps1
Cannot bind argument to parameter ‘Name’ because it is an empty string.
+ CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,New-Mailbox
And also I would like to add this..to the scrip and the csv file
company and physicalDeliveryOfficeName
I´m a beginner of Power Shell and would appricate a how the scrip and csv should look like with these extra fileds.
Regards
/skenebo
Thanks for script, well i had follows all write method ut could not success following error comes up Missing ‘=’ operator after key in hash literal.
+Categoryinfo : parser; {}, parseException
can help out to clear this error
Hi,
Get this error in the scrip I guess the syntax are wrong regarding MBX Server and MBX DB1.
Could anyone give an example of the correct syntac to be used in the csv “MBX Server, MBX DB!”.
PS] C:\script>.\userlist.ps1
Cannot process argument transformation on parameter ‘Database’. Cannot convert value “MailDBSRV-MBX1\MailDB01″ to typ
e “Microsoft.Exchange.Configuration.Tasks.DatabaseIdParameter”. Error: “‘MBX Server\MBX DB1′ is not a valid valu
e for the identity.
Parameter name: Identity”
+ CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindin…mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,New-Mailbox
When I run the script with the exact code above, it does create an AD user and a mailbox in Exchange. The problem is that while it does show the person’s full name (first and last) in Exchange, it doesn’t show their full name in AD (it only shows their first name under the name column in AD). However, when you click on the user in AD, the user does have a first and last name, but it only displays the first name of the user when you first browse to the OU. Has anyone else ran into this problem? How do you get the last name to display as well under the name column in AD?
For example if you create a user named John Doe, in AD the user only shows up as John. I want John Doe to show up under the name column of AD.
Hi,
Greate script it´s now working perfect, thanks.
No experians of scripting and need help with add a attribut” Desription” from the General Tab.
Tried to do it but get this error, see script and error below.
——————————————————————————————————-
A positional parameter cannot be found that accepts argument ‘-description’.
+ CategoryInfo : InvalidArgument: (:) [New-Mailbox], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,New-Mailbox
————————————————————————————————————–
$ht = @{
‘givenName’=$user.fn
‘sn’=$user.ln
‘displayName’=$user.dispname
‘alias’=$user.alias
‘description’=$user.DSP
‘samAccountName’=$user.alias
‘userPrincipalName’ = $user.upn
‘database’ = $user.Database
‘organizationalUnit’ = $user.ou
‘name’ = ($user.fn + $user.sn)
}
Write-Output $ht
}
}
Function CreateUser{
Param($userInfo)
$secureString = ConvertTo-SecureString “Password” -AsPlainText –Force
New-Mailbox -Name $userInfo['name' ]`
-Alias $userInfo['alias'] -UserPrincipalName $userInfo['userPrincipalName'] `
-description $userInfo['description'] `
-SamAccountName $userInfo['alias'] -Database $userInfo['Database']`
-FirstName $userInfo['givenName'] -LastName $userInfo['sn'] `
/Skenebo
Jeff, I had the same problem, there were some extra spaces in line 14 that fixed it for me.
I’m new to powershell, and scripting in general, so I have a few questions.
What I want to do now is take the output of line 14 and format differently. result is fn+sn with an output of fredflintstone, what I would like is flintstone, fred. Can’t seem to figure out how to accomlish it.
I also want to add another field and make sure new imports contains the Department in AD after creation. I tried following the script and adding it in, but it always errors.
Any Assist would be great, and thanks for the script, works well.
I figured it out Matt. For, what you are trying to do you need to change line 14 to ‘name’ = ($user.ln + “,” + ” ” + $user.fn)
Let me know if that works Matt.
Matt,
It is me Jeff by the way.
Nice! Thank you much.
I know it’s small, but I appreciate it. Huge learning curve when I’ve never done any scripting, now I know.
Matt,
What I suggested to change worked?
yep, where did you find it? My problem is not knowing where to go look, or what the verbage is for what I’m asking. I know about help in PS, but no clue how to find that one.
Thanks Again.
I figured it out because I understand the code.
Matt,
Do you know of any other message boards where users will write scripts for you based on what you describe?