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.