Bulk creation of mailboxes on Microsoft Exchange Server 2007/2010/2013/2016

Administrators of MS Exchange Server 2007/2010/2013/2016 might find themselves in need of creating multiple mail-enabled user accounts at once (e.g. when migrating from an older version of Exchange). Manual creation of even a relatively small number of Active Directory users – followed by assigning a mailbox to every one of them – can take a lot of time, not to mention creating dozens or hundreds of such items. Fortunately there is a way to make this procedure automatic – at least to some extent.

Automatically create Exchange mailboxes for users using bulk creation via PowerShell.

1. Creating a file with the user list.

The first thing that needs to be prepared is a complete list of all new users and mailboxes in a CSV file (Comma Separated Values). The easiest way to do it would be to use Microsoft Excel, but even ordinary Notepad is able to create such a file. In the example below the users have been defined according to the following criteria:

Alias,Name,UPN

Additional values can be added here as well – virtually for every field available in the Active Directory. A detailed how-to explaining that can be found at the end of this article. The example CSV user list looks like that:

Alias,Name,UPN
User_1,User 1,user1@domain
User_2,User 2,user2@domain
User_3,User 3,user3@domain

etc.

 The header of the list is very important – it cannot be omitted. Once the list is ready, it needs to be saved as a CSV file with a relatively simple name – it will be used later in the script pulling data from it. In this example it was called CreateMailboxes.csv.

2. Assigning the password.

The next step is to create a password for all the new users. Manually assigning a new password for every single user will be a great waste of time – it is better to do it automatically using the Exchange Management Shell instead. It can be achieved with the following script:

$Password=Read-Host “Enter Password” –AsSecureString

A notification asking for the password will be displayed. We can now input the desired phrase – it will become the password for all the new users from the CSV list. It can always be changed later according to individual needs.

3. Importing the CSV file and creating the mailboxes.

The final step involves importing the CSV file we have prepared earlier and creating the mailbox-enabled user accounts. To do that, we need to issue the following command in the Exchange Management Shell:

Import-CSV CreateMailboxes.csv | ForEach {New-Mailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -Database “Mailbox Database” -OrganizationalUnit Users -Password $Password}

The script presented above can be modified according to specific needs. The Exchange Management Shell interprets the selected parts of this command in the following way:

  • Import-CSV CreateMailboxes.csv – pulls data from the CSV file we prepared earlier. If the file was saved in a location different from the one Exchange Management Shell is running from,  a full path to the CSV file needs to be included in the script as well, e.g. “c:\My Documents\CreateMailboxes.csv” (quotation marks are required).
  • ForEach – retrieves data from every single line of the CSV file using the first one as the header. All the field names are treated as names of the Active Directory fields. Additional values can be easily added to the command – e.g. when we add a line Company $_.company it will force the script to search the CSV file for a column called Company and pull from it all the data for each row of our user list.
  • New-Mailbox – this item is directly responsible for the creation of new mailboxes. It supports a whole range of parametres that can be definded for each user – a full list of all available values can be found on the Microsoft Technet website: New-Mailbox cmdlet syntax. The necessary values can be added to the CSV file and the script should include an additional command line matching them.
  • OrganizationalUnit – this value defines the Active Directory Organizational Unit all the new users will be added to. In the example script all the users have been included in the main “Users” group. To split users between multiple AD groups, it will be necessary to create an additional column in the CSV list (called for example “OU”), and then complete the script with a command that will pull data from this very column for every single user: -org $_.OU.
  • Password – assigns to each user the password retrieved from the $Password value created before.

I hope that this article will help to save a lot of time and effort that would be required while trying to manually perform all the procedures described above.

Suggested reading

Mailbox cmdlets in Exchange Online/2013
Manage users’ AD photos without PowerShell (free tool)

Tools for Microsoft 365

Recommended articles

How to migrate from Exchange Server 2016/2019 to Microsoft 365

How to migrate from Exchange Server 2016/2019 to Microsoft 365

Migrating Exchange data to the cloud is not rocket science – explore your options and launch the migration stress-free. As you may already know, Exchange Server 2016 and 2019 have reached end of life and are no longer officially supported by Microsoft. If your organization still uses either of these platforms to manage email, contacts, calendars, and tasks, keep in mind that: Your environment may become vulnerable to newly discovered security threats – Microsoft will no longer provide security updates for Exchange 2016 and 2019 (unless you’ve enrolled in the Extended Security Update program, which ends in October 2026). Your emails may get blocked – Microsoft has started to throttle and block emails sent from unsupported Exchange Server versions to Exchange Online (as I covered in this article). That said, migrating to a supported platform is now the only viable long-term option for keeping your organization’s email environment secure, supported, and fully operational. If your organization wants or needs to keep things on‑premises (and continue using Microsoft’s solutions for that), upgrading to Exchange Server Subscription Edition (SE) is the only path forward. But given Microsoft’s clear preference for its cloud services – evident in the faster rollout of new features and the many security capabilities available exclusively in Microsoft 365 (Office 365) – now is a great time to leave your on‑prem environment behind and migrate to Exchange Online as part of Microsoft 365. While switching over to a new platform might seem like a rough ride, I’ll show you some easy ways to follow when migrating mailboxes from Exchange Server 2016/2019 to Microsoft 365. How to prepare for email migration to Microsoft 365 Before you start the migration process, you need to make sure your environment is ready for the move. For this purpose, you can use this guide in the Microsoft 365 admin center – it will help you connect your organization to Microsoft 365 and integrate your existing user accounts with Microsoft Entra ID. Microsoft also recommends completing the steps below: Set up an SPF record to determine valid email sources for your organization’s Microsoft 365 domain. Set up the Exchange Online Protection service as a means of protection against spam and malware. If you’re behind on updates, make sure to install the latest Cumulative Update (CU). And here is my quick, less obvious Microsoft 365 migration checklist: Verify if your software will work in Microsoft 365 (especially when it comes to server software). Microsoft 365 migration might be the time you learn that there is crucial legacy software that half the company uses and which is hard to replace. Encourage the whole company to clean up projects. It’s much easier to do this before the migration and start fresh. Gather as much information about your on‑premises environment as possible. For example, you might need to recreate access roles and permissions from scratch in the cloud or set up mail flow rules. Without prior research, it will be much more difficult. Verify if you need to migrate service accounts. There can be a lot of them on‑premises and in most cases, you won’t need them after the move. Review mailbox size limits in Exchange Online before migration to see which licenses you’ll need and whic
New-ComplianceSearch: how to use the newer version of Search-Mailbox

New-ComplianceSearch: how to use the newer version of Search-Mailbox

Microsoft retired the Search-Mailbox cmdlet – now what? Discover how to use New-ComplianceSearch, its key advantages and how to make the switch seamlessly.
How to start remote PowerShell session to Exchange or Microsoft 365

How to start remote PowerShell session to Exchange or Microsoft 365

One of many features of the PowerShell command line tool is its ability to connect with and manage the Exchange Server remotely. The procedure described below applies to the classic on-prem Exchange server and to the Microsoft 365/Exchange Online version.

Comments

    • avatar
      Adam the 32-bit Aardvark says:

      I’d be happy to help. Though I need to know what exactly didn’t work. Did you get any error? At which point?

    • avatar
      Adam the 32-bit Aardvark says:

      You can use any value that’s a unique identifier for an OU, which includes: Name, Canonical name, Distinguished name, or GUID.

  1. avatar
    Ravi Reddy says:

    Sorry Adam i am still confused. are you saying i must use following? can you explain in details please?

    Import-CSV CreateMailboxes.csv | ForEach {New-Mailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -Database “Mailbox 02” -OrganizationalUnit Users_Testing -Password $Password=P@ssword123}

    • avatar
      Adam the 32-bit Aardvark says:

      Sorry, I’m explaining it a bit more, below:
      The error you have received suggests that you are using the $Password variable which is null. It cannot be null, you must assign a password before you run your script. To assign it, it is best to use this cmdlet:
      $Password=Read-Host “Enter Password” –AsSecureString – it will let you insert the password securely. After you run this one-liner, you can use your original script and it should work with no issues.

  2. avatar
    Ravi Reddy says:

    Hi

    I am getting following error please help me what am i doing wrong?
    Cannot bind argument to parameter ‘Password’ because it is null.
    + CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,New-Mailbox

    my command looks like this.

    Import-CSV CreateMailboxes.csv | ForEach {New-Mailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -Database “Mailbox 02” -OrganizationalUnit Users_Testing -Password $Password}

    • avatar
      Adam the 32-bit Aardvark says:

      It seems that you have not specified any password in the $Password variable. The script should run if you prepend it with
      $Password = YourUltraStrongPassword

  3. Good Day,
    Below is the syntax i used with the data within the CSV file, and works great, but i have gotten a request to add a couple users (about 200) with two different smtp email addresses, so basically, for eg. user John Doe has default email [email protected] and an additional email [email protected]. how do i go about adding that within the syntax i currently use, also what do i add for the user to change their password on first logon. all within this syntax.

    much appreciated. thanks.

    import-CSV userdata.csv | ForEach {New-Mailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -Database “Database name” -OrganizationalUnit users -Password $password}

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Andy,
      to reset the password, add -ResetPasswordOnNextLogon $true switch. The additional email needs to be added with Set-Mailbox:
      import-CSV userdata.csv | ForEach {Set-Mailbox $_.Mailbox -EmailAddresses @{add=$_.NewEmailAddress}}

    • Hi,
      I Used your script to create New-RemoteMailbox
      My script is look like that:
      Import-CSV “c:\CreateMailboxes.csv” | ForEach {New-RemoteMailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -FirstName $_.FirstName -LastName $_.LastName -OnPremisesOrganizationalUnit Students365 -Password $Password}

      My problem is that the first name and last name are null in the user object.

      the csv file is:
      Alias,Name,UPN,FirstName,LastName
      AlmogC,Almog Cohen,[email protected],Almog,Cohen
      EranC,Eran Carmi,[email protected],Eran,Carmi

      what am i doing wrong ?

      Thank you !

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Eiran,

      Make sure that the CSV file is encoded in UTF-8 (e.g. open the file in Notepad, go to File, Save as). Then try importing again, but with the encoding defined as UTF-8:

      Import-CSV “c:\CreateMailboxes.csv” -Encoding:UTF8

      Let me know if this helps!
      Adam

    • Hi Adam,
      Its seems like -Encoding is not exsist in exchange 2010 powershell.

      the csv file encoding is UTF-8
      this is the error :
      Import-Csv : A parameter cannot be found that matches parameter name ‘Encoding’.

      This is the script after the change:
      Import-CSV “c:\CreateMailboxes.csv” -Encoding:UTF8 | ForEach {New-RemoteMailbox -Alias $_.alias -Name $_.name -userPrincipalName $_.UPN -FirstName $_.FirstName -LastName $_.LastName -OnPremisesOrganizationalUnit Students365 -Password $Password}

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Eiran,

      Earlier, when you didn’t use the -Encoding parameter, was the file encoded in UTF-8? If not, please try saving it as UTF-8 now and import without the -Encoding parameter.

      Best regards,
      Adam

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Eliran,

      My money is on some kind of regional formatting of the CSV file (e.g. right-to-left text direction), but it’s very hard to say in this case.

      Best regards,
      Adam

  4. Hi all,

    I’m searching for a way to add an expiration date to user accounts through the run commands, they are below, but can’t seem to find any guidance on where to squeeze it in. Thanks for any help.

    $data = import-csv $args[0]
    $FQDN = $env:userdnsdomain

    foreach ($i in $data){

    $first = $i.First
    $last = $i.Last
    $rank = $i.Rank
    $edipi = $i.EDIPI
    $name = $last + ‘, ‘ + $first + ‘ ‘ + $XXXX + ‘ XXXX’
    $alias = $first + ‘.’ + $last
    $upn = $edipi + “@” + “XXX”
    $ou = $i.OU
    $encryptedpass = ConvertTo-SecureString -AsPlainText $i.Password -Force
    $resetpass = $true

    new-mailbox -Firstname $first -LastName $last -Name $name -Alias $alias -UserPrincipalName $upn -OrganizationalUnit $ou -Password $encryptedpass -ResetPasswordOnNextLogon $resetpass

    }

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Charles,

      To set an expiration date to user accounts, try following these steps:

      1. Save the below script to the .ps1 format (e.g. myscript.ps1):

      #Import the ActiveDirectory module so we are able to set the expiration date
      Import-Module ActiveDirectory

      $data = import-csv $args[0]
      $FQDN = $env:userdnsdomain

      #define the expiration date in the following format MM/DD/YYYY HH:MM AM/PM”
      $expirationDate = “11/1/2016 3:00AM”

      foreach ($i in $data){

      $first = $i.First
      $last = $i.Last
      $rank = $i.Rank
      $edipi = $i.EDIPI
      $name = $last + ‘, ‘ + $first + ‘ ‘ + $XXXX + ‘ XXXX’
      $alias = $first + ‘.’ + $last
      $upn = $edipi + “@” + “XXX”
      $ou = $i.OU
      $encryptedpass = ConvertTo-SecureString -AsPlainText $i.Password -Force
      $resetpass = $true

      new-mailbox -Firstname $first -LastName $last -Name $name -Alias $alias -UserPrincipalName $upn -OrganizationalUnit $ou -Password $encryptedpass -ResetPasswordOnNextLogon $resetpass

      #set the expiration using the previously provided date. The identity would be the $upn
      Set-ADAccountExpiration -Date $expirationDate -Identity $upn
      }

      The first line of the script is required to import AD module, which you need later to run the cmdlet with an expiration date. Next, define the expiration date ($expirationDate). The core action is Set-ADAccountExpiration – in the –Date provide your date ($expirationDate) and in the –Identity provide user’s UPN ($upn).

      2. Execute the .ps1 file containing the above script (myscript.ps1) via Exchange Management Shell.

      Hope this helps!
      Adam

  5. Hi Adam,

    Is it possible to put command “$Password=readhost…” in continue of “import-csv c:\newusers.csv | …”

    I want to have everything in one line if it’s possible.

    Thank you for quick response.

    Ence

  6. Hi all,

    I wanted to ask is it possible to put static password in the same line where is command for creating mailbox? Thanks in front.

    My commands are:

    $Password=Read-Host “Enter Default Password” -AsSecureString
    import-csv C:\NewUsers.csv | ForEach-Object {New-Mailbox -Name $_.Name -Alias $_.Alias -OrganizationalUnit $_.OrganizationalUnit -UserPrincipalName $_.UPN -Database $_.Database -Password $Password}

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Ence,

      I’m not sure if I understand. Do you mean a standard password for all users that they cannot change?

      Thank you!
      Adam

  7. Amazing. I woke up in the morning and had a mail from Developers that they need 500 accounts to do a load test. I was like whatt!!! and this came to the rescue. Super Job.. Works as expected. Thank you so much

  8. avatar
    Tyrone Dixon says:

    Thanks a lot for this walkthrough!

    I actually added a few other New-Mailbox parameters. Worked really well.

    Thanks
    Ty

  9. I want to create exchange 2010 mailboxes using exchange 2013 powershell, but I am getting error.

    The Mailbox database “dbname” isn’t on a server running Exchange 2013 or a later version. If you want to create or
    enable a Exchange 2010 mailbox, or want to enable the archive or remote archive for a Exchange 2010 Sp1 mailbox,

  10. I am trying to create about 100 mailboxes using the command:

    import-csv “C:\users\xyz\desktop\Bulk.csv” | ForEach-Object {New-Mailbox -Bulk -Name $_.Name -Alias $_.Alias -OrganizationalUnit $_.OrganizationalUnit -UserPrincipalName $_.UPN -Database $_.Database -Password $Password}

    But I was always getting error:Cannot bind argument to parameter ‘Name’ because it is an empty string.
    + CategoryInfo : InvalidData: (:) [New-Mailbox], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,New-Mailbox

    My CSV file looks like this:

    Name,Alias,OrganizationalUnit,Database,UserPrincipalName
    Testing Test,ttesting,deer.com/Users,DEER,[email protected]

    Kindy assist to check the problem

    Thanks.

    • avatar
      Adam the 32-bit Aardvark says:

      Hi Abu,

      Apologies for the late response.

      The error would suggest that your CSV file headers are missing the ‘Name’ field. My suggestions:
      – check if the ‘Name’ field is spelled correctly in the CSV file
      – remove the -Bulk parameter from the command (it’s unnecessary and might cause errors) and run it again.

      Let me know what was the result.

      Best regards,
      Adam

  11. avatar
    Adam the 32-bit Aardvark says:

    Hi Alexis!
    Thanks for your feedback.
    The problem lies in the way you named the user principal name column in your CSV. Its name is UserPrincipalName while in the PS command you use UPN as the data source anchor.
    You can fix this by changing the name of the column in CSV to UPN or by changing the part of the PS command from:
    -UserPrincipalName $_.UPN
    to
    -UserPrincipalName $_.UserPrincipalName.
    In other words – the string after the $_. part in the command must be the same as the name of the CSV column.

  12. avatar
    Alexis Crawford says:

    Hi,

    I have a list of 130 shared mailboxes that I must create. So I created a CSV file like this:

    Name,Alias,OrganizationalUnit,Database,UserPrincipalName

    John Smith,jsmith,domain.com/accounts/shared,mailbox database A,[email protected]

    Mark Flone,mflone,domain.com/accounts/shared,mailbox database A,[email protected]

    ETC…..

    The list is ready and it is saved.

    import-csv C:\path | New-mailbox -Shared

    the Error is the following:

    “Cannot bind parameter ‘Name’ to the target. Exception setting “Name”: “The property can’t be empty.”

    I went into my spreadsheet and Trimmed everything, then saved and still the same error result.

    Then I tried the following:

    import-csv C:\temp\sharedMailboxCreationTest.csv | ForEach-Object {New-Mailbox -shared -Name $_.Name -Alias $_.Alias -OrganizationalUnit $_.OrganizationalUnit -UserPrincipalName $_.UPN -Database $_.Database}

    The Error:

    “Cannot bind argument to parameter ‘UserPrincipalName’ because it is an empty string.”

    What am I missing here?

    Alexis

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

CodeTwo sp. z o.o. sp. k. is a controller of your personal data.
See our Privacy Policy to learn more.