The second article in this series will continue the Lab Setup Script. This part of the script I wrote will cover these options: populating calendar entries, populating task entries, configuring impersonation, mailbox quotas, DLP policies, and adding a disclaimer. In the next article I will cover mobile devices, retention policies, enabling archives, OWA policies and configuring APPs.
Let’s dive right on in:
New, Extended Menu: (circled items are covered in this post)

Populating Calendar Entries
Populating calendar entries requires a bit of EWS programming and not being a programmer, or knowing the interface for EWS very well, I turned to the Internet looking for someone who has (See my article on methodology). After a bit of research I found a good article I’ve used with one customer with great success. I’ve included the code here and referenced the author in the description section of the full script (all sections are collapsed by default):
# Code section for the menu
7 {# Populate calendars
# Create sample calendar entries and exported it to a PST file
# Import these into random mailboxes
write-host "This function assumes you have the correct rights." -fore red
write-host " "
start-sleep 5
Create-CalendarEvents
}
# Import calendar events
function Create-CalendarEvents {
$events = import-csv c:\scripts\calendarevents.csv
$import = read-host "Do you want to import calendar events into all mailboxes or random mailboxes ['a' or 'r']"
if ($import -eq "a") {
$mailboxes = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).primarysmtpaddress
foreach ($line in $mailboxes) {
$primary = $line.local+"@"+$line.domain
foreach ($line in $events) {
# get-mailbox | new-calendarevent -subject $line.subject -date $line.date -impersonate
new-calendarevent -identity $primary -subject $line.subject -date $line.date -impersonate
}
write-host "Calendar entries for $line.displayname have been added." -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"}).primarysmtpaddress
while ($counter -lt $range) {
foreach ($line in $events) {
$address = $mailbox[$counter]
$primary = $address.local+"@"+$address.domain
get-mailbox $mailbox[$counter] | new-calendarevent -subject $line.subject -date $line.date -impersonate
}
$counter++
write-host "Calendar entries for $mailbox[$counter] have been added." -foregroundcolor green
}
}
} # End Create Calendar Items Function
# Create Calendar Entries
function new-calendarevent {
[CmdletBinding(DefaultParametersetName='Identity')]
param(
[Parameter(Position=0, ParameterSetName='Identity')]
$Identity,
[Parameter(Position=1, Mandatory=$true)]
$Subject,
[Parameter(Position=2, Mandatory=$true)]
$Date,
[Parameter(Position=3)]
[Switch]$Impersonate,
[Parameter(Position=4)]
$ExchangeVersion = 'Exchange2013_CU7',
[Parameter(Position=5, ParameterSetName='Pipeline', ValueFromPipelineByPropertyName=$true)]
$PrimarySmtpAddress,
[Parameter(Position=6)]
[System.Management.Automation.PSCredential]
$Credential,
[Parameter(Position=7)]
$EWSUrl
)
begin {
#Load the EWS Assembly
Add-Type -Path "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.WebServices.dll"
}
process {
#Is the identity coming from the pipeline?
if($PsCmdlet.ParameterSetName -eq 'Pipeline') {
$Identity = $PrimarySmtpAddress.ToString()
}
#Create the ExchangeService object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$ExchangeVersion)
#If Credential parameter used, set the credentials on the $service object
if($Credential) {
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
}
#If EWSUrl parameter not used, locate the end-point using autoD
if(!$EWSUrl) {
$service.AutodiscoverUrl($Identity, {$true})
}
else {
$service.Url = New-Object System.Uri -ArgumentList $EWSUrl
}
#If Impersonation parameter used, impersonate the user
if($Impersonate) {
$ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Identity
$service.ImpersonatedUserId = $ImpersonatedUserId
}
#Configure the start and end time for this all day event
$start = (get-date $date)
$end = $start.addhours(24)
#Create and save the appointment
$appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
$appointment.Subject = $Subject
$appointment.Start = $Start
$appointment.End = $End
$appointment.IsAllDayEvent = $true
$appointment.IsReminderSet = $false
$appointment.Categories.Add('Holiday')
$appointment.Location = 'United States'
$appointment.LegacyFreeBusyStatus = [Microsoft.Exchange.WebServices.Data.LegacyFreeBusyStatus]::Free
$appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone)
}
}
A sample run-through of Option 7:

This section of code pulls from a list of holidays/calendar entries stored in a CSV file:

For calendar entries you can add them to all mailboxes (option ‘a’) or to random mailboxes (option ‘r’). The list of mailboxes that have calendar entries are displayed as the script processes the mailbox. This option does require impersonation so make sure that the user account has the correct rights to perform this action.
Populating Task Entries
# Code section for the menu
8 {# Populate Tasks
# Create sample calendar entries and exported it to a PST file
# Import these into random mailboxes
write-host "This function assumes you have the correct rights." -fore red
write-host " "
start-sleep 5
Create-Tasks
}
# Code section - Initial Function (decision making)
# Import Tasks
function Create-Tasks {
$tasks = import-csv c:\scripts\tasks.csv
$import = read-host "Do you want to import calendar events into all mailboxes or random mailboxes ['a' or 'r']"
if ($import -eq "a") {
$mailboxes = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).primarysmtpaddress
foreach ($line in $mailboxes) {
$primary = $line.local+"@"+$line.domain
foreach ($line2 in $tasks) {
# get-mailbox | new-task -subject $line.subject -date $line.date -impersonate
new-task -identity $primary -subject $line2.subject -startdate $line2.startdate -enddate $line2.enddate -impersonate
}
write-host "Task entries for $line.displayname have been added." -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"}).primarysmtpaddress
while ($counter -lt $range) {
foreach ($line in $tasks) {
$address = $mailbox[$counter]
$primary = $address.local+"@"+$address.domain
get-mailbox $primary | new-task -subject $line.subject -startdate $line.startdate -enddate $line.enddate -impersonate
}
write-host "Task entries for $primary have been added." -foregroundcolor green
$counter++
}
}
} # End Create Tasks Function
# Code section - Initial Function (decision making)
# Create Task Entries
function new-task {
[CmdletBinding(DefaultParametersetName='Identity')]
param(
[Parameter(Position=0, ParameterSetName='Identity')]
$Identity,
[Parameter(Position=1, Mandatory=$true)]
$subject,
[Parameter(Position=2, Mandatory=$true)]
$StartDate,
[Parameter(Position=3, Mandatory=$true)]
$EndDate,
[Switch]$Impersonate,
[Parameter(Position=4)]
# UPDATED to Exchange 2013
$ExchangeVersion = 'Exchange2013_SP1',
[Parameter(Position=5, ParameterSetName='Pipeline', ValueFromPipelineByPropertyName=$true)]
$PrimarySmtpAddress,
[Parameter(Position=6)]
[System.Management.Automation.PSCredential]
$Credential,
[Parameter(Position=7)]
$EWSUrl
)
begin {
#Load the EWS Assembly - UPDATED to Exchange 2013
Add-Type -Path "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.WebServices.dll"
}
process {
#Is the identity coming from the pipeline?
if($PsCmdlet.ParameterSetName -eq 'Pipeline') {
$Identity = $PrimarySmtpAddress.ToString()
}
#Create the ExchangeService object
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$ExchangeVersion)
#If Credential parameter used, set the credentials on the $service object
if($Credential) {
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
}
#If EWSUrl parameter not used, locate the end-point using autoD
if(!$EWSUrl) {
$service.AutodiscoverUrl($Identity, {$true})
}
else {
$service.Url = New-Object System.Uri -ArgumentList $EWSUrl
}
#If Impersonation parameter used, impersonate the user
if($Impersonate) {
$ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Identity
$service.ImpersonatedUserId = $ImpersonatedUserId
}
#Create and save the task
$task = New-Object Microsoft.Exchange.WebServices.Data.Task -ArgumentList $service
$task.Subject = $subject
$task.StartDate = $startdate
$task.DueDate = $enddate
$task.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Tasks)
# ([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Notes)
}
}
A sample run-through of Option 8:

This section of code pulls from a list of task entries stored in a CSV file:

For task entries you can add them to all mailboxes (option ‘a’) or to random mailboxes (option ‘r’). The list of mailboxes that have task entries are displayed as the script processes the mailbox. This option does require impersonation so make sure that the user account has the correct rights to perform this action.
Configure Impersonation
Impersonation can be used for many functions in Exchange, in the case of this script I use impersonation to handle certain tasks that if the right is missing, will fail. This step will either enable your current account or a different account. The script also checks to see if there is an existing impersonation role configured before creating one.
# Code section for the menu
20 {# Assign impersonation rights to the current user account
add-impersonation
}
# Impersonation Function
function add-impersonation {
$answer = read-host "Does your user account need the impersonation right before proceeding [y or n]"
if ($answer -eq "y") {
$user = [Environment]::UserName
# Create Management Scope for impersonation
if ((get-managementscope "impersonation") -eq $null) {
New-ManagementScope –Name:Impersonation –RecipientRestrictionFilter {RecipientType -eq "UserMailbox"}
}
#Assign impersonation to a user
New-ManagementRoleAssignment –Role:ApplicationImpersonation –User:$user –CustomRecipientWriteScope:Impersonation
} else {
$answer2 = read-host "Does another user account need the impersonation right before proceeding [y or n]"
if ($answer2 -eq "y") {
$user = read-host "Enter the name of the account that needs impersonation rights"
# Create Management Scope for impersonation
if ((get-managementscope "impersonation") -eq $null) {
New-ManagementScope –Name:Impersonation –RecipientRestrictionFilter {RecipientType -eq "UserMailbox"}
}
#Assign impersonation to a user
New-ManagementRoleAssignment –Role:ApplicationImpersonation –User:$user –CustomRecipientWriteScope:Impersonation
}
}
} # End of add-impersonation

Adding DLP Policies
This section is based on my three part series where I call my XML script from the main lab setup script:
# Code section for the menu
9 {# DLP Policy Creation -ForegroundColor Red
# This location is where ever you downloaded the script to
invoke-expression "c:\scripts\XMLScript-Lab-1.3.ps1"
}
A sample run through of the script looks just like my article on this script that I’ve done before:

At the very end I can import the XML file as a new Rule Classification for DLP:

Then the script will create a DLP rule based on this criteria:
![]()
Configure Mailbox Quotas
Script for the option is as follows:
# Code section for the menu
11 {# Configure quotas
configure-quotas
}
# Quotas Function
function configure-quotas {
write-host "Enter your Quota values:"
$iwq = read-host "Issue Warning Quota [in MB, unlimited]"
if ([string]$iwq -ne "unlimited") {
[string]$iwq = [string]$iwq+" MB"
}
[string]$psq = read-host "Prohibit Send Quota [in MB]"
if ($psq -ne "unlimited") {
[string]$psq = [string]$psq+" MB"
}
[string]$psrq = read-host "Prohibit Send/Receive Quota [in MB]"
if ([string]$psrq -ne "unlimited") {
[string]$psrq = [string]$psrq+" MB"
}
$answer = read-host "Do you want to apply the policies to all users or random users [a or r]"
if ($answer -eq "a") {
$mailboxes = (get-mailbox | where {$_.RecipientTypeDetails -ne "DiscoveryMailbox"}).primarysmtpaddress
foreach ($line in $mailboxes) {
$primary = $line.local+"@"+$line.domain
set-mailbox $primary -ProhibitSendQuota $psq -ProhibitSendReceiveQuota $psrq -IssueWarningQuota $iwq -UseDatabaseQuotaDefaults $false
write-host "The mailbox for $primary has had their quotas modified as requested:" -foregroundcolor green
get-mailbox $primary | ft ProhibitSendQuota, ProhibitSendReceiveQuota, IssueWarningQuota, UseDatabaseQuotaDefaults
}
write-host "Quotas configured for all mailboxes as requested."
} 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"}).primarysmtpaddress
while ($counter -lt $range) {
$address = $mailbox[$counter]
$primary = $address.local+"@"+$address.domain
set-mailbox $primary -ProhibitSendQuota $psq -ProhibitSendReceiveQuota $psrq -IssueWarningQuota $iwq -UseDatabaseQuotaDefaults $false
write-host "The mailbox for $primary has had their quotas modified as requested:" -foregroundcolor green
get-mailbox $primary | ft ProhibitSendQuota, ProhibitSendReceiveQuota, IssueWarningQuota, UseDatabaseQuotaDefaults
}
write-host "Quotas configured for $range mailboxes as requested."
}
start-sleep 5
} # End of Quotas function
In this script, the Quotas option is rather simplified with either setting the three Quota values for all mailboxes or random mailboxes. Enter the number of MB needed for each value or use Unlimited. There is no check to validate the values at this time, but may be added in a future version of the script.
Here is a sample run through of the option:

The script will report the changes made as they are made:

Now you have quotas to test against in a lab environment.
Configure Disclaimer Text
# Code from the menu
12 {# Configure disclaimers
Check-OldDisclaimers
Configure-NewDisclaimers
}
# Check for Old Disclaimers
function Check-OldDisclaimers {
$rulecheck = (Get-TransportRule).ApplyHtmlDisclaimerText
$rulecheck2 = get-transportrule | where {$_.ApplyHtmlDisclaimerText -ne $null}
if ($rulecheck -eq $null) {
write-host " "
write-host "There are no disclaimers in place now." -foregroundcolor green
write-host " "
} else {
foreach ($line in $rulecheck2) {
write-host " "
write-host "There is a transport rule in place called $line that is a disclaimer rule." -ForegroundColor Yellow
write-host " "
}
}
}
# Add New Disclaimers
function Configure-NewDisclaimers {
$name = read-host "Name of the disclaimer rule"
$DisclaimerNameCheck = get-transportrule | where {$_.name -eq $name}
if ($DisclaimerNameCheck -eq $null) {
$text = read-host "Disclaimer text or HTML"
New-TransportRule -FromScope 'NotInOrganization' -ApplyHtmlDisclaimerLocation 'Append' -ApplyHtmlDisclaimerText $text -ApplyHtmlDisclaimerFallbackAction 'Wrap' -Name $name -StopRuleProcessing:$false -Mode 'Enforce' -Comments '
' -RuleErrorAction 'Ignore' -SenderAddressLocation 'Header'
} else {
write-host "There is a rule with the same name." -nonewline
write-host " Please try the option again." -ForegroundColor Red
write-host " "
Configure-NewDisclaimers
}
}
The disclaimer part of this script is pretty simplistic right now. There are a couple of configurable options – The name of the rule and the text of the disclaimer. Other options are hardcoded, like the location (Append), fall back action (wrap), mode (enforce), etc.
Here is a sample run of the script:

At the end you can see the rule is created. I also have a duplicate name check in the script to prevent those error messages from cropping up.
Scripts
Test Lab Script Version 1.2
XML Creation Script
**rename files with a .ps1 extension.
