Lab Setup Script – Part 4 – Advanced Features 1

If you’ve followed my previous posts on this topic you have seen the growing list of automated PowerShell setups that are included for some of the basic functions in Exchange. For this article I am going to start delving into the more complicated, more advanced features of Exchange including the option to handle more complex situations with previous configurations.

Configure Delegation

“You can use the EAC or the Shell to assign permissions to users or groups (called delegates) that allow them to open or send messages from other mailboxes. Permissions can be assigned to user mailboxes, linked mailboxes, resource mailboxes, and shared mailboxes. You can also assign permissions to distribution groups, dynamic distribution groups, and mail-enabled security groups to allow delegates to send messages on behalf of the group. You can assign delegates the following permissions to access mailboxes or send messages on behalf of mailboxes or groups.”


# Code for menu
20 { # Configure Delegation

# Configure Delegation
function Configure-delegation {
    $userA = read-host "What user needs delegation rights? [enter the user's alias]"
    $userB = read-host "What user mailbox will have access granted to it? [enter the user's alias]"  
    $accessrights = read-host "What access rights will be granted? [use commas if more than one]"
    $folder = read-host "All folders or specific folder [a or s]"
    if ($folder -eq "a") {
        $folder2 = "*"
        $combo = $usera+":\"+$folder2
        add-MailboxFolderPermission -Identity $userB -User $UserA -AccessRights $accessrights
    if ($folder -eq "s") {
        $folder2 = read-host "Which folder will the rights apply to"
        $combo = $usera+":\"+$folder2
        # Add the folder tothe user's mailbox being modified"
        $name = $userB+":\"+$folder2
        add-MailboxFolderPermission -Identity $name -User $UserA -AccessRights $accessrights
} # End the Configure Delegation function

Sample run through of the Delegation part of the script:

Calendar Access


All Folder Access


As you can see from the script, you need to specify the folder, the user, who is assigned the right, etc. Make sure you have the right correctly typed, or the command will fail.

Room Lists

Room lists are like a little gem hidden in Exchange 2013. I am hoping to shed more light in this feature with my blog article earlier this month, to this advanced functionality included in the lab setup script. More information can be found at this TechNet page.

# Menu Choices
5 { # Create Rooms
	$choice = read-host "Do you want to [1] create rooms or [2] rooms and roomlists?[1 or 2]"			 
	if($choice -eq 1) {
	} else { # Added an move advanced option (1.3)

# Create new Room Lists
Function New-RoomList {
    write-host " "
	Write-host "This function will help you create rooms and room lists for your test environment, assuming" -ForegroundColor green
    write-host "the OU's and rooms are not created so far." -ForegroundColor green
    write-host " "
	$answer1 = read-host "Create room lists from scratch? [y or n]"
	If ($answer1 -eq "y") {
		$csvmanual = read-host "Do you want to [1] use a CSV file or [2] enter the rooms manually ? [1 or 2]"
		If ($csvmanual -eq 1) {
			# import rooms and room lists from CSV file
			# CSV format:
			# roomlist,room,ou
            $csvfile = read-host "Specify a CSV file to read from"
			$csv = Import-csv $csvfile
            write-host "No column validation here - use this at your own risk."

            # pausing
            Write-Host "Press any key to continue ..."
            $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
			Foreach ($line in $csv) {
                # Check for the existence of the Room list, create if it does not exist
                if ((get-distributiongroup $line.roomlist) -eq $null) {
				    New-DistributionGroup -Name $line.roomlist -OrganizationalUnit $line.ou -RoomList
                $track = 0
                $database = (get-mailboxdatabase).name
                write-host "For the new Room Mailboxe:"
                $mbx = $
                $password = read-host "Enter password for the $mbx mailbox" -AsSecureString
                $dbcount = (get-mailboxdatabase).count
                $domain = read-host "Enter a domain to be used for the rooms SMTP address"
#               $source2 = import-csv c:\temp\roommailboxes.csv
                $name = $
                $name = $name -replace '\s',''
                $upn = $name+"@"+$domain
                new-mailbox -userprincipalname $upn -alias $name -database $database[$track] -displayname $ -name $name -password $password -room
                if ($track -ge $dbcount) {
                    $track = 0

            # Add members according to the CSV file provided
            Add-DistributionGroupMember -Identity $line.roomlist -Member $
		If ($csvmanual -eq 2) {
			$norooms = read-host "How many rooms do you want to create?"
			$noroomlists = read-host "How many room lists do you want to create?"
            $counter = 0
            while ($counter -lt $norooms) {
                $roomname = read-host "Enter a name for the room"
                $capacity = read-host "Enter a room capacity"
                $ou = read-host "Enter an OU to search for [i.e. rooms]"
                Get-OrganizationalUnit -SearchText $ou |ft *canonicalname*
                $ou = read-host "Copy one of the OUs above to use for placing the room mailboxes or enter a new one"
                New-mailbox -Name $roomname -OrganizationalUnit $ou -room -ResourceCapacity $capacity
            $counter = 0
            while ($counter -lt $noroomlists) {
                $roomlist = read-host "Enter a name for the room list"
                $ou2 = read-host "Enter an OU for the room list"
                New-DistributionGroup -Name $roomlist -OrganizationalUnit $ou2 -RoomList
                $NoRoomMembers = read-host "How many rooms do you want to add to the $roomlist roomlist?"
                $counter2 = 0
                while ($counter -lt $NoRoomMembers) {
                    $RoomListMember = read-host "What room do you want to add to the $roomlist room list?"
                    Add-DistributionGroupMember -Identity $roomlist -Member $RoomListMember

    If ($answer1 -eq "n") {
        write-host " "
        write-host "Exiting room list function...." -foregroundcolor red
        write-host " "
        start-sleep 5
} # End of the New-RoomList function

Sample run through of working through Room List options:

Enter Rooms and Room Lists Manually


Using a CSV File for the Process


The Room Lists script section provides options for creating lists via CSV files or entering the details manually.

Configure Journaling

“Journaling can help your organization respond to legal, regulatory, and organizational compliance requirements by recording inbound and outbound email communications. When planning for messaging retention and compliance, it’s important to understand journaling, how it fits in your organization’s compliance policies, and how Microsoft Exchange Server 2013 helps you secure journaled messages.”


# Menu Code
19 { # Configure Journaling

# Configure Journaling for Exchange
function configure-journaling {
    $journaloption = read-host "Do you want to configure [1] Per User Journaling or [2] Journaling for all messages? [1 or 2]"
    # Scope options - Internal | External | Global
    $mailbox = read-host "Do you need to create a journal mailbox? [y or n]"
    $database = read-host "Do you need to create a journal database? [y or n]"
    $name = read-host "Provide a name for the journal rule"
    if ($database -eq "y") {
        write-host "The next part of the script will ask for how many databases to create.  Choose 1." -foregroundcolor Green
    } else {
        $dbname = read-host "What database would you like to use for journaling?"
    if ($mailbox -eq "y") {
        $journalmailbox = read-host "What will you call the journaling mailbox?"
        $password = read-host "Enter a password" -AsSecureString
        $prefix = read-host "Enter a prefix for the User Principal Name [i.e. @domain.local]"
        $mailbox = $journalmailbox+$prefix
        write-host "The $journalmailbox will be created in the Users OU"
        new-mailbox -userprincipalname $mailbox -alias $journalmailbox -database $tbd -displayname $journalmailbox -name $journalmailbox -password $password
    } else {
        $journalmailbox = read-host "What is the name of the journaling mailbox?"
    if ($journaloption -eq "1") {
        $nousers = read-host "How many users do you want to configure journaling for?"
        $counter = 0
        $list = @()
        while ($counter -lt $nousers) {
            $user = read-host "What user do you want to configure for journaling? [user alias]"
            $email = (get-mailbox $user).primarysmtpaddress
            $smtp = $email.local+"@"+$email.domain
            $list += ,($smtp)
        # Configure journaling for the user
        New-JournalRule -Name $name -JournalEmailAddress $smtp -Scope Global -recipient $smtp -Enabled $true
    } else {
        # Configure journaling for the organization
        $email = (get-mailbox $journalmailbox).primarysmtpaddress
        $smtp = $email.local+"@"+$email.domain
        New-JournalRule -Name $name -JournalEmailAddress $smtp -Scope Global -Enabled $true
} # End the Configure Journaling function

In the below sample run-through, I am attempting to simulate Journaling for all mailboxes, while creating a database (calls another function in the script), as well as creating a Journal mailbox to go with it.


Per User
The next sample is a run-through of adding journaling on a per user basis, without creating a database or journal mailbox.


Retention Policies

“In Microsoft Exchange Server 2013 and Exchange Online, Messaging records management (MRM) helps organizations to manage email lifecycle and reduce legal risks associated with e-mail and other communications. MRM makes it easier to keep messages needed to comply with company policy, government regulations, or legal needs, and to remove content that has no legal or business value. “


# Menu Code
10 {#	Create retention Policies

# Create Retention Policies
function create-retentionpolices {
    $createorapply = read-host "[1] Create or [2] Apply retention policies [1 or 2]"
    if ($createorapply -eq 1) {

    $polno = read-host "How many Retention Policies do you want to create"
    $polcounter = 0
    while ($polcounter -lt $polno) {
        $currentpol = $polcounter +1
        $polname = read-host "Specify a name for Rentention Policy number $currentpol"
        $tagno = read-host "How many Retention Tags do you want to create"
        $counter = 0
        $alltags = @()
        $allpolicies = @()
        while ($counter -lt $tagno) {
            $current = $counter + 1
            $name = read-host "Specify a name for Retention Tag number $current"
            $allpolicies += ,($name)
            $time = read-host "Specify a time frame to apply the tag (i.e. 60, 90, 120)"
            $RetentionAction = read-host "Specify a retention action (DeleteAndAllowRecovery, PermanentlyDelete, MoveToArchive)"
            if ($retentionaction -eq "MoveToArchive") {
                $type = "all"
            } else {
                $type = read-host "Specify which folders will be affect (All, Inbox, etc.  )"
            $comment = read-host "Specify a comment for the Retention Tag (optional)"
            $alltags += ,($name)
            if ($retentionaction -eq "permanentlyDelete") {
                $archive = $false
            } else {
                $archive = $true
            New-RetentionPolicyTag -Name $name -Type $type -RetentionAction $retentionaction -RetentionEnabled:$archive -AgeLimitForRetention $time -Comment $comment
        new-retentionpolicy -name $polname -RetentionPolicyTagLinks $alltags
    $action = read-host "Do you want to apply these policies to your users now? [y or n]"

    # After creating polcies - create them?
    if ($action -eq "y") {$createorapply = 2}

    if ($createorapply -eq 2) {
        $allpolicies = (get-retentionpolicy).name
        foreach ($line in $allpolicies) {
           $action2 = read-host "For the retention policy $line, do you want to apply this policy to any users? [y or n]"
           if ($action2 -eq "y") {
                $applyto = read-host "Do you want to apply the policies to [a] all users, [r] random users or [c] use a csv file? [a, r or c]"
                if ($applyto -eq "a") {
                    get-mailbox | set-mailbox -retentionpolicy $line
                if ($applyto -eq "r") {
                    $mbxcount = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).count
                    $range =  get-random -minimum 0 -maximum $mbxcount
                    $mailbox = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).alias
                    $counter = 0
                    $userlist = @()
                    while ($counter -lt $range) {
                        $alias = $mailbox[$counter]
                        get-mailbox $alias | set-mailbox -retentionpolicy $line
                if ($applyto -eq "c") {
                    # CSV format is just the mailbox alias, with a header of 'alias'
                    $csv = read-host "Specify a CSV file to read from"
                    foreach ($line in $csv) {
                        get-mailbox $line.alias | set-mailbox -retentionpolicy $line

} # End of the create-retentionpolices function.

Applying Retention Policies
In the below example, the script will ask if you want to apply the listed retention policy to users in the environment.


Dynamic Distribution Groups
For distribution groups, the script initially created very generic groups with the “DistributionGroup” name and places a random 1 to 10 users into each distribution group. For this version, there will be a small menu to drive your choices for group creations and validations.

# Code for Menu
22 { #Configure dynamic DLs

# Create Distribution Groups
function create-dynamicdistributiongroups {
    $random = read-host "Create random [1] Dynamic Distribution Groups or [2] create with a CSV file? [1 or 2]"
    if ($random -eq 1) {
        $dlcount = read-host "How many distribution groups would you like to create"
        $alias1 = "DistributionGroup"
        $displayname1 = "Distribution Group "
        $dlcounter = 1
        while ($dlcounter -lt $dlcount) {
            $displayname = $displayname1+$dlcounter
            $alias = $alias1+$dlcounter
            $orgunit = read-host "Enter the OU for the Dynamic Distribution Group"
            new-dynamicdistributiongroup -name $displayname -displayname $displayname -alias $alias -RecipientFilter {RecipientType -eq 'UserMailbox'} -OrganizationalUnit $orgunit
    if ($random -eq 2) {
        $csvfile = read-host "Specify CSV file for creating Dynamic Distribution Groups"
        $csv = import-csv $csvfile
        foreach ($line in $csv) {
            new-dynamicdistributiongroup -name $line.displayname -displayname $line.displayname -alias $line.alias -RecipientFilter {RecipientType -eq 'UserMailbox'} -OrganizationalUnit $line.orgunit
	write-host "Dynamic Distribution Groups step complete." -foregroundcolor green
	write-host " "
    start-sleep 5
} # End of the create-dynamicdistributiongroups function

Sample Dynamic List Creation
Notice in the below example, a CSV file is specified. The CSV file contained pre-populated information to make the process go easier.


Archive Quotas

# Code for menu
21 { # Configure Archive Quotas

# Enable Archives for all or some users
function enable-archives {
    $selection = read-host "Do you want to enable archives for all mailboxes or random mailboxes [a or r]"
    $location = read-host "Would you like to create a new mailbox database for the archive mailboxes [y or n]"
    if ($location -eq "n") {
        $database = read-host "Which database will the archive mailboxes be placed in"
    if ($location -eq "y") {
        $srv = ($server[0]).name
        write-host "The new archive database will bew placed on $srv."
        $directory1 = read-host "Please enter a valid directory to place the database files"
        $directory2 = read-host "Please enter a valid directory to place the log files"
        $archivename = "ArchiveDatabase"
        $edb = $directory1+"\"+$archivename+".edb"
        $log = $directory2+"\"+$archivename
        $server = get-mailboxserver
        new-mailboxdatabase -name $archivename -edbfilepath $edb -logfolderpath $log -server $srv -erroraction silentlycontinue

    # Enable the mailboxes to have archive mailboxes
    if ($selection -eq "a") {
        $mailboxes = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).alias
        foreach ($line in $mailboxes) {
            enable-mailbox $line -Archive -ArchiveDatabase $database -erroraction silentlycontinue
            $name = (get-mailbox $alias).displayname
            write-host "An archive mailbox for $name has been created." -foregroundcolor green    
    } else {
        $mbxcount = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).count
        $range =  get-random -minimum 0 -maximum $mbxcount
        $counter = 0
        $mailbox = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).alias
        while ($counter -lt $range) {
                $alias = $mailbox[$counter]
                enable-mailbox $alias -Archive -ArchiveDatabase $database -erroraction silentlycontinue
        $name = (get-mailbox $alias).displayname
        write-host "All archive mailboxes have been created." -foregroundcolor green    
} # End function for archive mailboxes

Using a CSV File
This example uses a CSV file to apply quotas to the Archive Mailboxes for users.


Random Users
This option allows a policy to applied randomly, which is usually only done for lab environments.


All Users
In the last example, the archive quota policies can be applied to all users as seen below:


Script Download
Now that the script has reach the more advance level, I am posting it to the web at a TechNet Wiki download. Once the script has been finalized or at least has 80% of the features I want, it will be placed in the GitHub universe to allow people to modify it.

Here is the Lab-Setup-1.3 script for download now. Remember to rename it as a .ps1 file.

Next Steps
In the next article or two I will finish up the Advanced parts of the script. Following that and possibly my last post in the series I will cover using DSC and xExchange with a lab setup as well as production uses. Look for those articles in the coming weeks.

Previous Articles in this Series
Part 1
Part 2
Part 3


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s