Managing Office 365 Groups With Remote PowerShell

Posted on 2 CommentsPosted in Azure, cloud, exchange, exchange online, groups, IAmMEC, mcm, mcsm, MVP, Office 365, owa, powershell

Announced during Microsoft Ignite 2015, there are now PowerShell administration cmdlets available for the administration of the Groups feature in Office 365.

The cmdlets are all based around “UnifedGroups”, for example Get-UnifiedGroups.

Create a Group

Use New-UnifiedGroup to do this. An example would be New-UnifiedGroup -DisplayName “Sales” -Alias sales –EmailAddress

The use of the EmailAddress parameter is useful as it allows you to set a group that is not given an email address based on your default domain, but from one of the other domains in your Office 365 tenant.

Modify a Groups Settings

Use Set-UnifiedGroup to change settings such as the ability to receive emails from outside the tenant (RequireSenderAuthenticationEnabled would be $false), limit email from a whitelist (AcceptMessagesOnlyFromSendersOrMembers) and other Exchange distribution list settings such as hidden from address lists, mail tips and the like. AutoSubscribeNewMembers can be used to tell the group to email all new messages to all new members, PrimarySmtpAddress to change the email address that the group sends from.

Remove a Group

This is the new Remove-UnifiedGroup cmdlet.

Add Members to a Group

This cmdlet is Add-UnifiedGroupLinks. For example Add-UnifiedGroupLinks sales -LinkType members -Links brian,nicolas will add the two names members to the group. The LinkType value can be members as shown, but also “owners” and “subscribers” to add group administrators (owners) or just those who receive email sent to the group but not access to the groups content. To change members to owners you do not need to remove the members, just run something like Add-UnifiedGroupLinks sales –LinkType owners -Links brian,nicolas

You can also pipe in a user list from, for example a CSV file, to populate a group. This would read: Add-UnifiedGroupLinks sales -LinkType members -Links $users where $users = Get-Content username.csv would be run before it to populate the $users variable. The source of the variable can be anything done in PowerShell.

Remove Members from a Group

For this use Remove-UnifiedGroupLinks and mention the group name, the LinkType (member, owner or subscriber) and the user or users to remove.

To Disable Group Creation in OWA

Set-OWAMailboxPolicy is used to create a policy that is not allowed to create Groups and then users have that policy applied to them. For example Set-OWAMailboxPolicy “Students” –GroupCreationEnabled $false followed by Set-CASMailbox mary –OWAMailboxPolicy Students to stop the user “mary” creating groups. After the policy is assigned and propagates around the Office 365 service, the user can join and leave groups, but not create them.

Control Group Naming

This feature allows you to control the group name or block words from being used. This is easier to set in the Distribution Groups settings in Exchange Control Panel rather than via PowerShell. To do this EAC use Recipients > Groups and click the ellipses icon (…) and select Configure Group Naming Policy. This is the same policy for distribution groups. You can add static text to the start or end of name, as well as dynamic text such as region.

Admins creating groups are not subject to this policy, but unlike DL’s if they create groups in PowerShell the policy is also not applied and so the -IgnoreNamingPolicy switch is not required.

Speaking at TechEd Europe 2014

Posted on 4 CommentsPosted in certificates, cloud, EOP, exchange, exchange online, Exchange Online Protection, GeoDNS, hybrid, IAmMEC, journaling, mcm, mcsm, MVP, Office 365, smarthost, smtp, starttls, TechEd, TLS, transport

I’m please to announce that Microsoft have asked me to speak on “Everything You Need To Know About SMTP Transport for Office 365” at TechEd Europe 2014 in Barcelona. Its going to be a busy few weeks as I go from there to the MVP Summit in Redmond, WA straight from that event.


My session is going to see how you can ensure your migration to Office 365 will be successful with regards to keeping mail flow working and not seeing any non-deliverable messages. We will cover real world scenarios for hybrid and staged migrations so that we can consider the impact of mail flow at all stages of the project. We will look at testing mail flow, SMTP to multiple endpoints, solving firewalling issues, and how email addressing and distribution group delivery is done in Office 365 so that we always know where a user is and what is going to happen when they are migrated.

Compliance and hygiene issues will be covered with regards to potentially journaling from multiple places and the impact of having anti-spam filtering in Office 365 that might not be your mail flow entry point.

We will consider the best practices for changing SMTP endpoints and when is a good time to change over from on-premise first to cloud first delivery, and if you need to maintain on-premises delivery how should you go about that process.

And finally we will cover troubleshooting the process should it go wrong or how to see what is actually happening during your test phase when you are trying out different options to see which works for your company and your requirements.

Full details of the session, once it goes live, are at (Microsoft ID login needed to see this). Room and time to be announced.

Getting Exchange Message Sizing Raw Data

Posted on 2 CommentsPosted in exchange, exchange online, IAmMEC, mcm, mcsm, Office 365

On the internet there are a number of resources for collecting the raw data needed to size Exchange Server deployments. These include:

This blog outlines my process for collecting the data needed for the average message size. What is missing from the above two posts is the ability to collect this data in one go for the last seven (or so days) and then get the message tracking log average over the busiest five or so days. Different countries have different working patterns and public holidays, and the scripts above only do the previous day (though Neil’s says the script uses averages across many days – it does not).

The Script

Download the script from the source and save to Notepad. Edit the top of the script by deleting the first five lines of the code (not the comments or the blank lines) and then replace them with the alternative lines shown below:

Remove These Lines

$today = get-date
$rundate = $($today.adddays(-1)).toshortdatestring()

$outfile_date = ([datetime]$rundate).tostring("yyyy_MM_dd")
$outfile = "email_stats_" + $outfile_date + ".csv"

Replace With These Lines

$today = get-date
$whichDay = $args[0]
if (! $whichDay) { $whichDay = 1 }
$rundate = $($today.adddays(-$whichDay))

$outfile_date = ([datetime]$rundate).tostring("yyyy_MM_dd")
$outfile = "email_stats_" + $outfile_date + ".csv"

Before running this script you need to do two things. First if you have different Exchange Server locations around the world you need to alter the script to only include the servers in those geographies that you want to search. Do this by changing the two lines that read as follows and add in the server name or a unique differentiator that will pick up just the mailbox and hub transport servers in these regions. Edge servers do not need to be considered:

  • $mbx_servers = Get-ExchangeServer |? {$_.serverrole -match “Mailbox”}|% {$_.fqdn}
  • $hts = get-exchangeserver |? {$_.serverrole -match “hubtransport”} |% {$}

These two lines are near the top and need to be changed to something like the following:

  • $mbx_servers = Get-ExchangeServer UK* |? {$_.serverrole -match “Mailbox”}|% {$_.fqdn}
  • $hts = get-exchangeserver UK* |? {$_.serverrole -match “hubtransport”} |% {$}

In the above I altered the script to find just the Exchange Servers starting with the letters UK. Adjust as needed. If you have one location/timezone worldwide then these changes are not needed.

If you are collecting data from an Exchange 2013 server(s) then change “hubtransport” in the $hts line to read “mailbox”.

Save the file as a PowerShell script (Get-MessageTrackingLogStats.ps1) and copy it to your Exchange Server.

Before you can run the script you need to check that you have enough tracking logs to process, or you will get invalid and skewed data. Run Get-TransportServer | FL name,*trackinglog* and make sure that you have a large enough quota for each day of logs and then check each of these folders and make sure they do not exceed this value. If they do, then you need to run the below script frequently before the log files are removed from the server rather than at the end of 7 or 14 days.

Now you can run the script with a number after it for how many days back you want to look at the logs. This will process the message tracking logs for that day, that number of days back. For example is you run the script Get-MessageTrackingLogStats.ps1 5 then it will look back for one day of data, five days ago. Repeat the running of the script until you have run it seven times. You will have one CSV file of tracking log reports for each of the last seven days:

  • Get-MessageTrackingLogStats.ps1 1
  • Get-MessageTrackingLogStats.ps1 2
  • Get-MessageTrackingLogStats.ps1 3
  • Get-MessageTrackingLogStats.ps1 4
  • Get-MessageTrackingLogStats.ps1 5
  • Get-MessageTrackingLogStats.ps1 6
  • Get-MessageTrackingLogStats.ps1 7

Zip up these files and take them to a computer running Microsoft Excel.

One the oldest file and process each of them as follows:

Hide columns C through E and H through to O and R through to U:


You now have a spreadsheet with Date/User/Received Total/Received MB Total/Sent Unique Total/Sent Unique MB Total:

Format as a table by selecting a cell in the table and clicking the Table button in the Insert tab:

The Table Tools / Design tab appears. Select Total Row check box from here. This will scroll you to the bottom of the table.

Select the third cell in the total row and drop-down the options and choose Average:

Drag this Average cell formula across all the four columns of numbers:

Modify the fourth column (Received MB Total) to read as follows =SUBTOTAL(101,[Received MB Total])/Table1[[#Totals],[Received Total]]*1024. This is the fourth column divided by the third column (the count of received messages) and multiplied by 1024 to convert it from MB to KB. The Exchange Bandwidth Calculator and Storage Calculator work on values in KB and not MB.

Repeat for the fourth column of figures. This time take the formula to be =SUBTOTAL(101,[Sent Unique MB Total])/Table1[[#Totals],[Sent Unique Total]]*1024 which is the last column divided by the previous and converted to KB. This total row now shows you the average messages sent and received and the average size of these messages in KB.

At the bottom of the spreadsheet add the following:

  • Sent/Mailbox/Day
  • Received/Mailbox/Day
  • Average/MessageSize/Day (KB)

Then copy the relevant data into the cells as shown The Average is the sum of the two averages divided by 2 (=Table1[[#Totals],[Received MB Total]]+Table1[[#Totals],[Sent Unique MB Total]]/2):

Then take all your numbers and reduce the number of decimal points shown:

Now that you have the raw data calculated, save this file as an Excel Workbook (and not a CSV).

Repeat for each of the CSV files you have available

Process The Daily Data

Create a new spreadsheet that contains the following three tables:

  • Messages Sent Per Day, with a row for each day and a column for each unique geographical region
  • Messages Received Per Day, with a row for each day and a column for each unique geographical region
  • Average Message Size (KB), with a row for each day and a column for each unique geographical region

This will look like the following, once all the data is copied from the source spreadsheets:


Now you can create a chart for each region for each table. The following shows Sent / Received and Average (KB). Each region is overlapping as a different line colour:

Note its possible here that HK (blue) is missing some data as it is unexpectedly low



Note the HK (blue) Sunday Average message size. This is probably becuase one or a few users sent a disproportionate number of larger emails on the quiet day of the week. For my analysis I am going to ignore it.

Now I have my peak Messages Sent Per Day for each region – and I take the highest value for the week and not the value for yesterday which is what I would get if I just ran the above script once.

This data can now go into the Bandwidth Calculator and generate accurate figures for the business in question.

Configuring Exchange On-Premises to Use Azure Rights Management

Posted on 7 CommentsPosted in 2010, 2013, 64 bit, aadrm, ADFS, ADFS 2.0, DLP, DNS, exchange, exchange online, https, hybrid, IAmMEC, load balancer, loadbalancer, mcm, mcsm, MVP, Office 365, powershell, rms, sharepoint, warm

This article is the fifth in a series of posts looking at Microsoft’s new Rights Management product set. In an earlier previous post we looked at turning on the feature in Office 365 and in this post we will look at enabling on-premises Exchange Servers to use this cloud based RMS server. This means your cloud users and your on-premises users can shared encrypted content and as it is cloud based, you can send encrypted content to anyone even if you are not using an Office 365 mailbox.

In this series of articles we will look at the following:

The items above will get lit up as the articles are released – so check back or leave a comment to the first post in the series and I will let you know when new content is added.

Exchange Server integrates very nicely with on-premises RMS servers. To integrate Exchange on-premises with Windows Azure Rights Management you need to install a small service online that can connect Exchange on-premises to the cloud RMS service. On-premises file servers (classification) and SharePoint can also use this service to integrate themselves with cloud RMS.

You install this small service on-premises on servers that run Windows Server 2012 R2, Windows Server 2012, or Windows Server 2008 R2. After you install and configure the connector, it acts as a communications interface between the on-premises IRM-enabled servers and the cloud service. The service can be downloaded from

From this download link there are three files to get onto the server you are going to use for the connector.

  • RMSConnectorSetup.exe (the connector server software)
  • GenConnectorConfig.ps1 (this automates the configuration of registry settings on your Exchange and SharePoint servers)
  • RMSConnectorAdminToolSetup_x86.exe (needed if you want to configure the connector from a 32bit client)

Once you have all this software (or that which you need) and you install it then IT and users can easily protect documents and pictures both inside your organization and outside, without having to install additional infrastructure or establish trust relationships with other organizations.

The overview of the structure of the link between on-premises and Windows Azure Rights Management is as follows:


Notice therefore that there are some prerequisites needed. You need to have an Office 365 tenant and turn on Windows Azure Rights Management. Once you have this done you need the following:

  • Get your Office 365 tenant up and running
  • Configure Directory Synchronization between on-premises Active Directory and Windows Azure Active Directory (the Office 365 DirSync tool)
  • It is also recommended (but not required) to enable ADFS for Office 365 to avoid having to login to Windows Azure Rights Management when creating or opening protected content.
  • Install the connector
  • Prepare credentials for configuring the software.
  • Authorising the server for connecting to the service
  • Configuring load balancing to make this a highly available service
  • Configuring Exchange Server on-premises to use the connector

Installing the Connector Service

  1. You need to set up an RMS administrator. This administrator is either the a specific user object in Office 365 or all the members of a security group in Office 365.
    1. To do this start PowerShell and connect to the cloud RMS service by typing Import-Module aadrm and then Connect-AadrmService.
    2. Enter your Office 365 global administrator username and password
    3. Run Add-AadrmRoleBasedAdministrator -EmailAddress <email address> -Role “GlobalAdministrator” or Add-AadrmRoleBasedAdministrator -SecurityGroupDisplayName <group Name> -Role “ConnectorAdministrator”. If the administrator object does not have an email address then you can lookup the ObjectID in Get-MSOLUser and use that instead of the email address.
  2. Create a namespace for the connector on any DNS namespace that you own. This namespace needs to be reachable from your on-premises servers, so it could be your .local etc. AD domain namespace. For example rmsconnector.contoso.local and an IP address of the connector server or load balancer VIP that you will use for the connector.
  3. Run RMSConnectorSetup.exe on the server you wish to have as the service endpoint on premises. If you are going to make a highly available solutions, then this software needs installing on multiple machines and can be installed in parallel. Install a single RMS connector (potentially consisting of multiple servers for high availability) per Windows Azure RMS tenant. Unlike Active Directory RMS, you do not have to install an RMS connector in each forest. Select to install the software on this computer:
  4. Read and accept the licence agreement!
  5. Enter your RMS administrator credentials as configured in the first step.
  6. Click Next to prepare the cloud for the installation of the connector.
  7. Once the cloud is ready, click Install. During the RMS installation process, all prerequisite software is validated and installed, Internet Information Services (IIS) is installed if not already present, and the connector software is installed and configured
  8. If this is the last server that you are installing the connector service on (or the first if you are not building a highly available solution) then select Launch connector administrator console to authorize servers. If you are planning on installing more servers, do them now rather than authorising servers:
  9. To validate the connector quickly, connect to http://<connectoraddress>/_wmcs/certification/servercertification.asmx, replacing <connectoraddress> with the server address or name that has the RMS connector installed. A successful connection displays a ServerCertificationWebService page.
  10. For and Exchange Server organization or SharePoint farm it is recommended to create a security group (one for each) that contains the security objects that Exchange or SharePoint is. This way the servers all get the rights needed for RMS with the minimal of administration interaction. Adding servers individually rather than to the group results in the same outcome, it just requires you to do more work. It is important that you authorize the correct object. For a server to use the connector, the account that runs the on-premises service (for example, Exchange or SharePoint) must be selected for authorization. For example, if the service is running as a configured service account, add the name of that service account to the list. If the service is running as Local System, add the name of the computer object (for example, SERVERNAME$).
    1. For servers that run Exchange: You must specify a security group and you can use the default group (DOMAIN\Exchange Servers) that Exchange automatically creates and maintains of all Exchange servers in the forest.
    2. For SharePoint you can use the SERVERNAME$ object, but the recommendation configuration is to run SharePoint by using a manually configured service account. For the steps for this see
    3. For file servers that use File Classification Infrastructure, the associated services run as the Local System account, so you must authorize the computer account for the file servers (for example, SERVERNAME$) or a group that contains those computer accounts.
  11. Add all the required groups (or servers) to the authorization dialog and then click close. For Exchange Servers, they will get SuperUser rights to RMS (to decrypt content):
  12. If you are using a load balancer, then add all the IP addresses of the connector servers to the load balancer under a new virtual IP and publish it for TCP port 80 (and 443 if you want to configure it to use certificates) and equally distribute the data across all the servers. No affinity is required. Add a health check for the success of a HTTP or HTTPS connection to http://<connectoraddress>/_wmcs/certification/servercertification.asmx so that the load balancer fails over correctly in the event of connector server failure.
  13. To use SSL (HTTPS) to connect to the connector server, on each server that runs the RMS connector, install a server authentication certificate that contains the name that you will use for the connector. For example, if your RMS connector name that you defined in DNS is, deploy a server authentication certificate that contains in the certificate subject as the common name. Or, specify in the certificate alternative name as the DNS value. The certificate does not have to include the name of the server. Then in IIS, bind this certificate to the Default Web Site.
  14. Note that any certificate chains or CRL’s for the certificates in use must be reachable.
  15. If you use proxy servers to reach the internet then see for steps on configuring the connector servers to reach the Windows Azure Rights Management cloud via a proxy server.
  16. Finally you need to configure the Exchange or SharePoint servers on premises to use Windows Azure Active Directory via the newly installed connector.
    • To do this you can either download and run GenConnectorConfig.ps1 on the server you want to configure or use the same tool to generate Group Policy script or a registry key script that can be used to deploy across multiple servers.
    • Just run the tool and at the prompt enter the URL that you have configured in DNS for the connector followed by the parameter to make the local registry settings or the registry files or the GPO import file. Enter either http:// or https:// in front of the URL depending upon whether or not SSL is in use of the connectors IIS website.
    • For example .\GenConnectorConfig.ps1 –ConnectorUri -SetExchange2013 will configure a local Exchange 2013 server
  17. If you have lots of servers to configure then run the script with –CreateRegEditFiles or –CreateGPOScript along with –ConnectorUri. This will make five reg files (for Exchange 2010 or 2013, SharePoint 2010 or 2013 and the File Classification service). For the GPO option it will make one GPO import script.
  18. Note that the connector can only be used by Exchange Server 2010 SP3 RU2 or later or Exchange 2013 CU3 or later. The OS on the server also needs to be include a version of the RMS client that supports RMS Cryptographic Mode 2. This is Windows Server 2008 + KB2627272 or Windows Server 2008 R2 + KB2627273 or Windows Server 2012 or Windows Server 2012 R2.
  19. For Exchange Server you need to manually enable IRM as you would do if you had an on-premises RMS server. This is covered in but in brief you run Set-IRMConfiguration -InternalLicensingEnabled $true. The rest, such as transport rules and OWA and search configuration is covered in the mentioned TechNet article.
  20. Finally you can test if RMS is working with Test-IRMConfiguration –Sender You should get a message at the end of the test saying Pass.
  21. If you have downloaded GenConnectorConfig.ps1 before May 1st 2014 then download it again, as the version before this date writes the registry keys incorrectly and you get errors such as “FAIL: Failed to verify RMS version. IRM features require AD RMS on Windows Server 2008 SP2 with the hotfixes specified in Knowledge Base article 973247” and “Microsoft.Exchange.Security.RightsManagement.RightsManagementException: Failed to get Server Info from —> System.Net.WebException: The request failed with HTTP status 401: Unauthorized.”. If you get these then turn of IRM, delete the “C:\ProgramData\Microsoft\DRM\Server” folder to remove old licences, delete the registry keys and run the latest version of GetConnectorConfig.ps1, refresh the RMS keys with Set-IRMConfiguration –RefreshServerCertificates and reset IIS with IISRESET.

Now you can encrypt messages on-premises using your AADRM licence and so not require RMS Server deployed locally.

Updating Exchange 2013 Anti-Malware Agent From A Non-Internet Connected Server

Posted on Leave a commentPosted in 2013, 64 bit, antivirus, exchange, Exchange Online Protection, IAmMEC, malware, mcm, mcsm, powershell, x64

In Forefront Protection for Exchange (now discontinued) for Exchange 2010 it was possible to run the script at to download the signatures and scan engines when the server did not have a direct connection to the download site at

To achieve the same with Exchange 2013 and the built-in anti-malware transport agent you can repurpose the 2010 script to download the engine updates to a folder on a machine with internet access and then use a script from Exchange Server 2013 to download from a share on the first machine that you downloaded the files to, and that the Exchange Servers can reach.

So start by downloading the script at and saving it as Update-Engines.ps1.

Create a folder called C:\Engines (for example) and share it with Authenticated Users / Read access and full control to the account that will run Update-Engines.ps1

Run Update-Engines.ps1 with the following

Update-Engines.ps1 -EngineDirPath C:\engines -UpdatePathUrl  -Engines “Microsoft” -Platforms amd64

The above cmdlet/script downloads just the 64 bit Microsoft engine as that is all you need and places them in the local folder (which is the shared folder you created) on that machine. You can schedule this script using standard published techniques for scheduling PowerShell.

On your Exchange Server that has no internet connectivity, start Exchange Management Shell and run the following:

Set-MalwareFilteringServer ServerName –PrimaryUpdatePath \\dlserver\enginesShare

Then start a PowerShell window that is running as an administrator – you can use Exchange Management Shell, but it too needs to be started as an administrator to do this last step. In this shell run the following:





Then compare the first results from Get-EngineUpdateInformation with the second results. If you have waited 30 or so seconds, the second set of results should be updated to the current time for the LastChecked value. UpdateVersion and UpdateStatus might also have changed. If your Exchange Server has internet connectivity it will already have updated automatically every hour and so not need this script running.

Exchange DLP Rules in Exchange Management Shell

Posted on Leave a commentPosted in 2013, cloud, DLP, EOP, exchange, exchange online, Exchange Online Protection, IAmMEC, IFilter, mcm, mcsm, Office 365

This one took a while to work out, so noting it down here!

If you want to create a transport rule for a DLP policy that has one data classification (i.e. data type to look for such as ‘Credit Card Number’) then that is easy in PowerShell and an example would be as below.

New-TransportRule -name “Contoso Pharma Restricted DLP Rule (Blocked)” -DlpPolicy ContosoPharma” -SentToScope NotInOrganization -MessageContainsDataClassifications @{Name=”Contoso Pharmaceutical Restricted Content”} -SetAuditSeverity High -RejectMessageEnhancedStatusCode 5.7.1 -RejectMessageReasonText “This email contains restricted content and you are not allowed to send it outside the organization”

As you can see, and highlighted in red, the data classification is a hashtable and the single classification is mentioned.

To add more than one classification is much more involved:

$DataClassificationA = @{Name=”Contoso Pharmaceutical Private Content”}
$DataClassificationB = @{Name=”Contoso Pharmaceutical Restricted Content”}
$AllDataClassifications = @{}
New-TransportRule -name “Notify if email contains ContosoPharma documents 1” -DlpPolicy “ContosoPharma” -SentToScope NotInOrganization -MessageContainsDataClassifications $AllDataClassifications.Values -SetAuditSeverity High -GenerateIncidentReport administrator -IncidentReportContent “Sender”,”Recipients”,”Subject” -NotifySender NotifyOnly

And as you can see, shown in red above, you need to make a hashtable of hashtables and then use the value of the final hashtable in the New-TransportRule

Enabling and Configuring AADRM in Exchange Online

Posted on Leave a commentPosted in 2010, 2013, aadrm, exchange, exchange online, IAmMEC, mcm, mcsm, Office 365, rms

This article is the fourth in a series of posts looking at Microsoft’s new Rights Management product set. In the previous post we looked at turning on the feature in Office 365 and in this post we will look at how to manage the service in the cloud.

In this series of articles we will look at the following:

The items above will get lit up as the articles are released – so check back or leave a comment to the first post in the series and I will let you know when new content is added.

Once you have turned on Azure Active Directory rights management you need to enable it in a variety of locations based on your needs. This series of blog posts will look at doing that in both Exchange and SharePoint, both online in Office 365 and on-premises as well as for desktop users and mobile and tablet users. First we will start with Exchange Online.

Exchange Online configuration for AADRM is probably the most complex one to do, and its not that complex really! To enable AADRM for Exchange Online at the time of writing you need to import the RMS Key from AADRM. If you had installed AD RMS on premises then you might have already done this for Exchange Online to integrate it with your on-premises RMS infrastructure – if this is the case, don’t change the key online or it will break. These steps are for Exchange Online users who have never used or integrated AD RMS with Exchange on-premises.

Enabling AADRM in Exchange Online

  1. Enable AADRM in your Office 365 tenant as mentioned previously
  2. Set the RMS Key Sharing URL to the correct value as listed in
  3. For example, to set this if your Office 365 tenant is based in the EU you would use the following PowerShell cmdlet in a remote session connected to Exchange Online:
  4. Then import the keys and templates for your tenant from the AADRM servers online. The keys and templates are known as the Trusted Publishing Domain. This is done in a remote PowerShell session connected to Exchange Online using the following cmdlet:
    • Import-RMSTrustedPublishingDomain -RMSOnline -name “RMS Online”
  5. In the PowerShell response to the previous command you should see the AddedTemplates value read “Company Name – Confidential” and “Company Name – Confidential View Only” which are the default two templates. If customised templates have been created and published, they will appear here as well.
  6. To check that the key/template import has worked run Test-IRMConfiguration -RMSOnline from the Exchange Online remote PowerShell command prompt. You should see PASS listed at the end of the output.
  7. Finally, to turn on IRM protection in Exchange Online run Set-IRMConfiguration –InternalLicensingEnabled $true from an Exchange Online remote PowerShell session.

Configuring AADRM in Exchange Online

  1. Once IRM is enabled with Set-IRMConfiguration –InternalLicensingEnabled $true you can run Get-IRMConfiguration and you will see the following options are enabled. You can turn any of these off (and on again) as your require:
    • JournalReportDecryptionEnabled: Ensures the IRM protected messages stored in an Exchange Journal report are also stored in the same report in clear text.
    • ClientAccessServerEnabled: Enables OWA to offer IRM protection during email composing (click the ellipsis (…) in the new email compose screen and select set permissions menu). OWA will also prelicence IRM protected content so that OWA users can open content they are licenced to view etc. without needing to have access to the RMS infrastructure directly. Note that during testing I found it could take up to 24 hours for Exchange Online to show the RMS templates in OWA. [RMS011]
    • SearchEnabled: When you search your mailbox for content, anything that is IRM protected will appear in your search results if it matches the search keyword. This setting allows Exchange Search to open and index your content even if it is not listed as a valid user of the content.
    • TransportDecryptionSetting: This allows the transport pipeline in Exchange to decrypt content so that it is available for transport agents to view it. For example anti-malware agents and transport rules. The content is reprotected at the end of the transport pipeline before it leaves the server.
    • EDiscoverySuperUserEnabled: Allows discovery search administrators to query for keywords in your protected content even if they would not be able to directly open the content if they had access to your mailbox or if they found the email saved to a file share of other sharing location.

What the RMS Settings in Exchange Actually Do


Enabling journal report decryption allows the Journaling agent to attach a decrypted copy of a rights-protected message to the journal report. Before you enable journal report decryption, you must add the Federated Delivery mailbox to the super users group configured on your Active Directory Rights Management Services (AD RMS) server or AADRM settings.

Note: This is currently not working in Exchange Online and the above instructions are for Exchange On-Premises deployments.


When IRM is enabled on Client Access servers, Outlook Web App users can IRM-protect messages by applying an Active Directory Rights Management Services (AD RMS) template created on your AD RMS cluster or AADRM service. Outlook Web App users can also view IRM-protected messages and supported attachments. Before you enable IRM on Client Access servers, you must add the Federation mailbox to the super users group on the AD RMS cluster or AADRM service as this allows the server to decrypt all content for you on the server so that the user does not need to have to have access to the RMS or AADRM service.

With CAS being able to licence and get licences on your behalf from the RMS service, you have the ability to do RMS inside OWA, and even if you are offline in OWA then any protected content already comes with its licence and so can be read without a connection to the RMS service.


The SearchEnabled parameter specifies whether to enable searching of IRM-encrypted messages in Outlook Web App.


The TransportDecryptionSettingparameter specifies the transport decryption configuration. Valid values include one of the following:

  • Disabled   Transport decryption is disabled for internal and external messages.
  • Mandatory   Messages that can’t be decrypted are rejected, and a non-delivery report (NDR) is returned.
  • Optional   A best effort approach to decryption is provided. Messages are decrypted if possible, but delivered even if decryption fails.

Transport decryption allows RMS protected messages to be decrypted as they are processed on the Exchange Server and then encrypted again before they leave the server. This means transport agents such as anti virus or transport rules can process the message (i.e. scan for viruses or add signatures or do DLP processing) the message as they see it in its unencrypted form.


The EDiscoverySuperUserEnabledparameter specifies whether members of the Discovery Management role group can access IRM-protected messages that were returned by a discovery search and are residing in a discovery mailbox. To enable IRM-protected message access to the Discovery Management role group, set the value to $true.

Managing Azure Active Directory Rights Management

Posted on Leave a commentPosted in 2013, aadrm, dirsync, encryption, IAmMEC, journal, journaling, licence, mcm, mcsm, MVP, Office 365, rms, transport agent

This article is the third in a series of posts looking at Microsoft’s new Rights Management product set. In the previous post we looked at turning on the feature in Office 365 and in this post we will look at how to manage the service in the cloud.

In this series of articles we will look at the following:

The items above will get lit up as the articles are released – so check back or leave a comment to the first post in the series and I will let you know when new content is added.

Once you have signed up for the Azure Active Directory Rights Management (AADRM) Service there are a few things that you need to manage. These are:

  • The service itself
  • Users who are allowed to create RMS protected content
  • Enable and configure Super User rights if required.

Managing AADRM

There is not a lot to do in the Office 365 admin web pages with regard to the management of the service apart from enabling it, which we covered in the previous post and disabling it. Disabling the service involves the same steps as enabling it – you just click the big deactivate button!

AADRM can be further managed with PowerShell though. There are lots of blog posts on connecting to Office 365 using PowerShell, and some of those include the cmdlets to connect to Exchange Online etc. as well. The code below adds to this, and loads the AADRM module and connects to AADRM service in the cloud.

$cred = Get-Credential

write-host "Username: " $cred.username

Connect-MsolService -Credential $cred

Write-Host "...connected to Office 365 Windows Azure Active Directory"

$s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $cred -Authentication Basic -AllowRedirection

$importresults = Import-PSSession $s -Verbose

Write-Host "...connected to Exchange Online"

Import-Module AADRM

Connect-AadrmService -Verbose -Credential $cred

If you save the above PowerShell code as a text file with a .ps1 extension then you can run the script and easily connect to Office 365 with the credentials you enter. Then connect to Exchange Online with the same set of credentials and finally to AADRM with, of course, the same credentials. This allows you to manages users, email and security from a single session.

To get the AADRM PowerShell module on your computer (so that Import-Module AADRM works) you need to download the Rights Management PowerShell administration module from and then install it.

To install you need to have already installed the Microsoft Online Services Sign-In Assistant 7.0 and PowerShell 2.0. The PowerShell config file needs some settings adding to it, though I found on my Windows 8 PC that these had already been done. See the instructions at for this change to the config file.

  1. Run a PowerShell session and load the module with
    1. Import-Module AADRM
    2. Connect-AadrmService -Verbose
  2. Login when prompted with a user with Global Admin rights in Office 365.
  3. Or, use the script above to do Office 365, Exchange Online and AADRM in a single console.
  4. Run Get-Aadrm to check that the service is enabled

Enabling Super User Rights

Super Users in RMS are accounts that have the ability to decrypt any content protected with that RMS system. You do not need Super User rights to use RMS, nor do you need anyone who has Super User rights to use the product. But there are times when it might be required. One example would be during a discovery or compliance process. At this time it might be required that someone is able to open any RMS protected document to look for hits on the compliance issue in question. Super User gives that right, but would be needed just for the duration of the task that requires these rights. Rights to be Super User would be granted as needed and very importantly removed as needed.

Another example for the use of Super User is when a process needs to see content in its unprotected form. The common use case for this is Exchange Server and its transport decryption process. In Exchange Server you have agents that run against each message looking for something and then acting if that something is found. For example you would not want an virus to bypass the built in AV features of Exchange Server 2013 by protecting it with RMS! Or if you had a disclaimer transport rule or agent, you would not want the disclaimer or DLP feature to not see the content and act upon it because the content was encrypted. The same goes for journaling and the ability to journal a clear text copy of the message as well as the encrypted one if you wish.

To do all this in Exchange Server, the RMS Super User feature needs to be enabled and we will come back in a later post on the specifics of doing that for Exchange, but first we need to enable it in AARMS and set the users who will be Super Users and then, when we are finished with whatever required Super User, we need to turn it off again.

The Rights Management super users group is a special group that has full control over all rights-protected content managed by the Rights Management service. Its members are granted full owner rights in all use licenses that are issued by the subscriber organization for which the super users group is configured. This means that members of this group can decrypt any rights-protected content file and remove rights-protection from it for content previously protected within that organization.

By default, the super users feature is not enabled and no groups or users are assigned membership to it. To turn on the feature run Enable-AadrmSuperUserFeature from the AADRM PowerShell console. The opposite cmdlets exists to turn the feature off again – Disable-AadrmSuperUserFeature!

Once it is enabled you can set Office 365 users as Super Users. To do this run Add-AadrmSuperUser –EmailAddress where the user is either a cloud only Office 365 account or one that you have pushed to Office 365 using DirSync from your on-premises Active Directory. You can add more than one user, each user is added as a separate running of the cmdlets.

To see your list of Super Users, run Get-AadrmSuperUser. To remove users either take them out one by one (Remove-AadrmSuperUser –EmailAddress or just turn off the Super User feature with Disable-AadrmSuperUserFeature.

Adding AADRM Licences to Users

Once you have AADRM activated you can give your users the rights to create protected content. This is done in the licencing page of the Office 365 web admin portal or via PowerShell. The steps for adding user licences in the shell are discussed at That article was written some time ago, so the following are the changes for AADRM:

  • The Service Plan for the AADRM SKU is RMS_S_ADHOC

The New Rights Management Service

Posted on 3 CommentsPosted in aadrm, active directory, certificates, cloud, compliance, dirsync, exchange, exchange online, https, hybrid, journal, journaling, mcm, mcsm, microsoft, Office 365, Outlook, pki, policy, rms, smarthost, transport, unified messaging, voicemail

This blog is the start of a series of articles I will write over the next few months on how to ensure that your data is encrypted and secured to only the people you want to access it, and only for the level of rights you want to give them.

The technology that we will look at to do this is Microsoft’s recently released Windows Azure Active Directory Rights Management product, also known as AADRM or Microsoft Rights Management, or “the new RMS”.

In this series of articles we will look at the following:

The items above will get lit up as the article is released – so check back or leave a comment to this post and I will let you know when new content is added to this series.

What is “rights management”

Simply this is the ability to ensure that your content is only used by whom you want it to be used by and only for what you grant. Its known in various guises, and the most common guise is Digital Rights Management (DRM) as applied to the music and films you have been downloading for years.

With the increase in sharing music and other mp3 content in the last ten plus years, the recording companies and music sellers started to protect music. It did not go down well, and I would say this is mainly because the content was bought and so the owner wanted to do with it as they liked – even if what they liked was legal they were limited from doing so. I have music I bought that I cannot use because the music retailer is out of business or I tried to transfer it too many times. I now buy all my music DRM free.

But if the content is something I created and sold, rather than something I bought I see it very differently. When the program was running I was one of the instructors for the Microsoft Certified Master program. I wrote and delivered part of the Exchange Server training. And following the reuse of my and other peoples content outside of the classroom, the content was rights protected – it could be read only by those who I had taught. Those I taught think differently about this, but usually because the management of getting a new copy of the content when it expires!

But this is what rights management is, and this series of articles will look at enabling Azure Active Directory Rights Management, a piece of Office 365 that if you are an E3 or E4 subscriber then you already have, and if you have a lower level of subscription or none at all you can buy for £2/user/month and this will allow you to protect the content that you create, that it can be used by only those you want to read it (regardless of where you or they put it) and if you want it can expire after a given time.

In this series we will look at enabling the service and connecting various technologies to it, from our smartphones to PC’s to servers and then distributing our protected content to whom needs to see it. Those who receive it will be able to use the content for free. You only pay to create protected content. We will also look at protecting content automatically, for example content that is classified in a given way by Windows Server or emails that match certain conditions (for example they contain credit cards or other personally identifiable information (PII) information such as passport or tax IDs) and though I am not a SharePoint guru, we will look at protecting content downloaded from SharePoint document libraries.

Finally we will look at users protecting their own content – either the photographs they take on their phones of information they need to share (documents, aka using the phones camera as a scanner) or taking photos of whiteboards in meetings where the contents on the board should not be shared too widely.

Stick around – its a new technology and its going to have a big impact on the way we share data, regardless of whether we share it with Dropbox or the like or email or whatever comes next.

Moving Exchange Online Protection Junk Mail to the Junk Email Folder

Posted on Leave a commentPosted in 2007, 2010, 2013, active directory, cloud, Edge, EOP, exchange, exchange online, FOPE, mcm, mcsm, spam, transport

If you use Exchange Online Protection (EOP) to filter your email in the cloud and to remove spam and malware before onward delivery to you, and if you use Exchange 2007 or later on-premises, then you need to configure Exchange to move detected spam to the Junk Email folder in Outlook.

By default EOP detects two levels of spam (malware is automatically removed) and tags them. In Exchange, you need to use Transport Rules to move these emails to the users Junk Email folder. If you wish for EOP throw away junk emails of either detection level (i.e. high junk is discarded) then you still need to configure these transport rules to move the remaining detected junk email into the Junk Email folder in Outlook. If you place all EOP detected spam in the quarantine or throw it away, you should still create these transport rules as it means they are in place for any future changes you make at EOP.

If you use Exchange Online (part of Office 365) then you do not need to create these rules as they already exist (though you cannot see them in any admin tools you have).

The Transport Rules To Create

The following four transport rules need to be created on your Exchange organization. These four rules get created with the highest priority, moving all existing rules below them. They set the Spam Confidence Level of the message to 6 in these examples, though this should be set to a value that exceeds the SCLJunkThreshold organization wide setting for your Exchange Organization, as any email that exceeds this value is placed into the Junk Email folder upon delivery to the users mailbox.

New-TransportRule "Move EOP Detected Spam (SFV:SPM) to Junk Email Folder" -HeaderContainsMessageHeader "X-Forefront-Antispam-Report" -HeaderContainsWords "SFV:SPM" -SetSCL 6 -Priority 0

New-TransportRule "Move EOP Detected Spam (SFV:SKS) to Junk Email Folder" -HeaderContainsMessageHeader "X-Forefront-Antispam-Report" -HeaderContainsWords "SFV:SKS" -SetSCL 6 -Priority 1

New-TransportRule "Move Personal Block List Spam (SFV:SKB) to Junk Email Folder" -HeaderContainsMessageHeader "X-Forefront-Antispam-Report" -HeaderContainsWords "SFV:SKB" -SetSCL 6 -Priority 2

New-TransportRule "Move Bulk Email (SFV:SKB) to Junk Email Folder" -HeaderContainsMessageHeader "X-Forefront-Antispam-Report" -HeaderContainsWords "SRV:BULK" -SetSCL 6 -Priority 3

Once these four rules are run, AD replication will need to be allowed to happen and then all Exchange Servers will action this rule for any email that EOP thinks is spam. The default value for SCLJunkThreshold is 4, so as long as the rules set the SCL value to greater than this value it should work. Use Get-OrganizationConfig | FL SCLJunkThreshold to get this value for your organization.

What the EOP Message Tags Mean

The X-Forefront-Antispam-Report header in the email contains many values. See for what EOP thinks about the spam rating of the message.

  • SFV – means Spam Filtering Verdict
  • SFV:SFE – Originated from a Safe Sender (EOP learns Outlook safe senders due to Windows Azure Directory Sync)
  • SFV:BLK – Originated from a Blocked Sender
  • SFV:SPM – Spam
  • SFV:SKB – Emails where the sender is on the users personal block list as configured in OWA or Outlook Junk Email settings
  • SFV:SKS – (SKIP) The message was marked as spam prior to being processed by the spam filter. This includes messages where the message matched a Transport rule to automatically mark it as spam and bypass all additional filtering
  • SFV:NSPM – Not Spam

Article updated in June 2016 to include new headers and go from two rules to four

Removing Edge Subscription When Exchange 2013 Installed

Posted on 6 CommentsPosted in 2007, 2010, 2013, Edge, exchange, federation, IAmMEC, mcm, mcsm, smarthost, transport

Exchange 2013 does not have an Edge role (at the time of writing – Aug 2013). It is possible to use Exchange 2010 SP3 and install the Edge role should you need one.

There is a problem though when it comes to removing the Edge Subscription between an organization that contains Exchange 2013 servers and the Exchange 2010 Edge Server. To remove the subscription on the Edge server role you run Remove-EdgeSubscription servername and this removes both the subscription and any subscribed objects from the local AD LDS database on that Edge Server. But if any of these subscribed objects where created on Exchange 2013 after it was installed, then they will have an ExchangeVersion equal to 0.20 ( The Exchange 2010 SP3 Remove-EdgeSubscription cannot process this object and so fails with:

Remove-EdgeSubscription : Can’t make this change because the object’s ExchangeVersion property is 0.20 (, which is not supported by the current version 0.1 (8.0.535.0). You will need a newer version of Exchange to make this change. Property Name: ExchangeVersion
At line:1 char:24
+ Remove-EdgeSubscription <<<<  edge2 -Verbose
+ CategoryInfo          : NotSpecified: (0:Int32) [Remove-EdgeSubscription], DataValidationException
+ FullyQualifiedErrorId : D8A49A14,Microsoft.Exchange.Management.SystemConfigurationTasks.RemoveEdgeSubscription

The way to fix this is to find and manually remove the object with an ExchangeVersion of 0.20 ( from the AD LDS database and then repeat the Remove-EdgeSubscription cmdlet – as that should now work (unless you have two or more objects with the higher version number to locate and delete).

  1. To find objects with an ExchangeVersion greater than “0.1 (8.0.535.0)”, which is the version Exchange 2010 will process, open ADSIEdit on the Edge server.
  2. Right-click the ADSI Edit node at the top of the window and choose Connect to…
  3. In the Connection Settings dialog (shown above), change the Select a well known Naming Context to Configuration and type the local server name and the AD LDS port in the Select or type a domain or server field. The server:port value should be EDGESERVERNAME:50389
  4. Expand the tree view until you reach CN=First Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration,CN={AD258B4D-CCB4-4125-80C1-7B73CE066341}
  5. You now need to look at each object, starting with those you remember having created since 2013 was installed, for an object who’s msExchVersion value is not 4535486012416. For example, in the below screenshot I have an accepted domain made due to Federation in Exchange 2013. This object (under CN=Accepted Domains,CN=Transport Settings,…) has a value of 88218628259840.
  6. To validate that this is the correct object to manually delete, from the Exchange Management Shell on the Edge server, enter Get-Object | FT name,ExchangeVersion where Object is the cmdlet that you are looking to query – in my case it would be Get-AcceptedDomain.
  7. As you can see, this object has a newer ExchangeVersion and so it is (at least) this object that is stopping Exchange EdgeSync from being removed.
  8. Manually delete this object in ADSI Edit (it is safe to do this as it will resync from the Exchange organization if you recreate Edge Subscription later). Do not delete it from the Active Directory with ADSI Edit – just from AD LDS. Take care to only delete this object and not the parent object.
  9. Once this object is gone, try Remove-EdgeSubscription servername again. If this is the only object, then the Edge Subscription will be removed in the Edge Server

You can now carry on with whatever it was that you were doing that required a removal of the Edge Subscription.

Journal Alternative Mailbox and No Inbox Rules

Posted on 1 CommentPosted in 2013, compliance, exchange, exchange online, journal, journaling, mcm, mcsm, ndr, Office 365, rules, transport, transport agent

In the event of your journal mailbox going offline, any journal reports destined for these mailboxes will queue. After two days (though this time is the expiry time for messages in your Exchange organization, so may be different) the message will expire and an NDR sent to the sender of the journal report. The problem is that the journal report was not sent by anyone – the From address is <>. So no NDR is generated and the journal report is lost.

There is the JournalReportNdrTo property of TransportConfig that allows you to set who will receive these NDR’s.

Set-TransportConfig -JournalingReportNdrTo

Once this value is set this mailbox should be monitored occasionally and any NDR’s opened and the containing message (the journal report) resent so that it goes back to the (now working) journal mailbox.

In Exchange 2013 this NDR mailbox is never the subject of journaling nor do any inbox rules run against this mailbox – even if this mailbox is mentioned in a journal rule of if the mailbox has inbox rules associated with it. When you set this value in your Exchange 2013 organization you get the following warning:

WARNING: Any mail to JournalingReportNdrTo mailbox will not be journaled and it will not honor transport and mailbox rules settings. It is recommended to create a dedicated mailbox for JournalingReportNdrTo setting or set it to an external address.

Or if you set it in Exchange Control Panel then the following popup appears:


The warning also mentions that Transport Rules do not fire for this mailbox, but that is not what I have seen – though it might be that specific transport rules do not get actioned, but others do. Inbox rules and Journal Rules are not processed.

Therefore it is very important that you do not use a standard mailbox as the target for JournalReportNdrTo, as this mailbox will have all its outbound emails missing from any journal it should be stored it (and this would be a compliance issue) and the user will get bothered that their email rules in Outlook are not working.

The problem is that this is not the case in Exchange 2010, so if you have set the JournalReportNdrTo property in the past on a mailbox, and then migrated that mailbox to 2013 you will not be warned, but you will find that upon migration to 2013 your inbox rules stop working and if you look in the journal mailbox you will not find messages send from this mailbox. Therefore create a mailbox specifically for journal NDR’s before you migrate to Exchange 2013.

Removing Old Exchange 2013/2016 Log Files

Posted on 22 CommentsPosted in 2013, exchange, mcm, mcsm

Update: 18th Sept 2014. An updated version of this script has been written by Thomas Stensitzki and can be downloaded from This updated version works on systems that have not used the default installation paths and it reads them automatically from the server. The below still works for users with default installation paths.

Exchange 2013 creates log files for everything, and this is way more than in 2010. Everything is logged, and even when the server is doing nothing, it is recording the health of the server and writing that down to the logs.
The following PowerShell script removes log files (those named *.log) over 30 days old in the IIS logs folder and the same from the Exchange 2013 logging folder. Neither of these folders are cleaned up automatically in Exchange 2013 RTM or SP1. The transport logs in a different folder are cleaned up automatically after 30 days, so this script uses the same duration.

Set-Executionpolicy RemoteSigned -Force
$days=30 #You can change the number of days here

$ExchangeLoggingPath="C:\Program Files\Microsoft\Exchange Server\V15\Logging\"

Write-Host "Removing IIS, TMP_ and Exchange logs; keeping last" $days "days"
Function CleanTmpFiles($TargetFolder)
    Write-Host "Deleting tmp_* files and folders in $TargetFolder" 
    Get-ChildItem $TargetFolder -Include tmp_* -Recurse -ErrorAction SilentlyContinue | foreach ($_) {Remove-Item $_.FullName -Recurse -ErrorAction SilentlyContinue}
Function CleanLogfiles($TargetFolder)
    if (Test-Path $TargetFolder) {
        $Now = Get-Date
        $LastWrite = $Now.AddDays(-$days)
        $Files = Get-ChildItem $TargetFolder -Include *.log -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
        foreach ($File in $Files)
            {Write-Host "Deleting file $File" -ForegroundColor "Red"; Remove-Item $File -ErrorAction SilentlyContinue | out-null}
Else {
    Write-Host "The folder $TargetFolder doesn't exist! Check the folder path!" -ForegroundColor "red"


The above script runs in PowerShell and will delete logs on the server that you are running the script on.

The following version of the same script will get all the Exchange 2013 or later servers in the organization (excluding Edge Role servers) and then deletes the logs (older than 30 days) across all the servers for you from one machine. You run this second script from Exchange Management Shell (run as administrator) and need remote file access to C$ (or whichever folder you set in the script) to all the servers Exchange 2013 servers.

Set-Executionpolicy RemoteSigned -Force
$days=30 #You can change the number of days here

$ExchangeInstallRoot = "C"
$ExchangeLoggingPath="Program Files\Microsoft\Exchange Server\V15\Logging\"

Write-Host "Removing IIS and Exchange logs; keeping last" $days "days"
Function CleanTmpFiles($TargetFolder)
    $TargetServerFolder = "\\$E15Server\$ExchangeInstallRoot$\$TargetFolder"
    Write-Host "Deleting tmp_* files and folders in $TargetServerFolder"
    Get-ChildItem $TargetServerFolder -Include tmp_* -Recurse -ErrorAction SilentlyContinue | foreach ($_) {Remove-Item $_.FullName -Recurse -ErrorAction SilentlyContinue}
Function CleanLogfiles($TargetFolder)
    $TargetServerFolder = "\\$E15Server\$ExchangeInstallRoot$\$TargetFolder"
    Write-Host $TargetServerFolder
    if (Test-Path $TargetServerFolder) {
        $Now = Get-Date
        $LastWrite = $Now.AddDays(-$days)
        $Files = Get-ChildItem $TargetServerFolder -Include *.log -Recurse | Where {$_.LastWriteTime -le "$LastWrite"}
        foreach ($File in $Files)
               # Write-Host "Deleting file $File" -ForegroundColor "Red"
                Remove-Item $File -ErrorAction SilentlyContinue | out-null}
Else {
    Write-Host "The folder $TargetServerFolder doesn't exist! Check the folder path!" -ForegroundColor "red"

$Ex2013 = Get-ExchangeServer | Where {($_.IsE15OrLater -eq $true) -and ($_.ServerRole -ne "Edge")}

foreach ($E15Server In $Ex2013) {

IPv6 Routed LAN with Windows

Posted on 2 CommentsPosted in DNS, draytek, exchange, iis, ip, ipv4, ipv6, mcm, mcsm, rras, windows

This blog is written to note down the steps needed to configure IPv6 on the whole of your LAN using Windows Server 2008 R2 as the router, but without installing RRAS.

It also uses Hurricane Electric’s IPv6 tunnel broker service to provide the IPv6 connectivity via an IPv4 tunnel as my internet provider (Virgin Media in the UK) does not provide direct IPv6 connectivity at the time of writing (Dec 2012).

Originally the plan was to do all this with the Draytek 2920 router on my network, but after days of trying I gave up as it was unable to connect to SixXS over AICCU or Freenet6/gogo via TSPC even though I had made accounts and entered the information as shown on various websites and forum. Draytek do not provide a 6in4 tunnel mode, so I needed to move to using Windows or Linux, as I have both on my LAN – though I am way more familiar with Windows!

Configuring Your Internet Router

You will need control over your internet connection as you will need to enable inbound PING responses before you can create an IPv6 tunnel. On a Draytek router this is System Maintenance > Management > untick Disable PING from the internet.

Also to allow a tunnel to traverse a NATed router, you need to allow Protocol 41 to pass the firewall. On a Draytek router this involves creating a new rule in the Default Call Filter rule set and the same under the Default Data Filter set. The settings are Direction: WAN –> LAN/RT/VPN; Source IP: Any; Destination IP: Any; Service Type: Protocol: 41; Filter: Pass Immediately.

Getting a Hurricane Electric Tunnel

Visit and create an account and request a tunnel. Once you have requested a tunnel you will get the following information on the IPv6 Tunnel tab (of which only the important information is shown, and where I have changed the values to be generic):

  • IPv6 Tunnel Endpoints
    • Server IPv4 Address: a.b.c.d (the endpoint of the tunnel at Hurricane Electric)
    • Server IPv6 Address: 2001:xxxx:wwww:65b::1/64 (this has wwww shown in bold and is the Hurricane Electric end of the tunnel they have created for you, and it will end in a 1.)
    • Client IPv4 Address: w.x.y.z (this is your external IP address of your internet connection)
    • Client IPv6 Address: 2001:xxxx:wwww:65b::2/64 (this has wwww shown in bold and is your end of the tunnel they have created for you, and it will end in a 2.)
  • Routed IPv6 Prefixes
    • Routed /64: 2001:xxxx:yyyy:65b::/64 (this has yyyy in bold and yyyy is one number higher than wwww in the IPv6 tunnel endpoints above).

On the Example Configurations tab you will get the choice of operating system to use, and you need to select Windows Vista/2008/7 from the dropdown list. This will present you with some netsh commands as shown (where the values will be your specific values rather than the generic values I show here):

netsh interface teredo set state disabled
netsh interface ipv6 add v6v4tunnel IP6Tunnel w.x.y.z a.b.c.d
netsh interface ipv6 add address IP6Tunnel 2001:xxxx:wwww:65b::2
netsh interface ipv6 add route ::/0 IP6Tunnel 2001:xxxx:wwww:65b::1

If you are behind a NATed router then you need to change the w.x.y.z value which will show your public IP address for the private IP address of the Windows Server you are going to run this set of commands on.

Run these commands from an elevated command prompt. Once complete you should be able to reach the IPv6 internet from that machine. Try ping and you should get back the IPv6 address for Facebook (showing your DNS server is IPv6 aware – Windows DNS will return AAAA, the IPv6 version of the A record, responses if your client has a valid global IPv6 address). Another destination you can attempt to ping is

You now have working IPv6 from a single server on your LAN.

Configuring The Windows Router

The next step is to enable this single server as a router. This will allow the forwarding of packets between the LAN and the IPv6 Tunnel that exists on this server.

NOTE: This series of steps does not use RRAS, and therefore there is no firewall on this router. Therefore these steps should be for lab environments only, as you need to ensure that Windows Firewall on all your endpoints is secure (remote admin [DCOM], RPC Endpoing and 445 have default rules for open to anyone) – these will need securing to a suitably valid range, or implment IPSec on the servers so connections cannot be made from non domain members. A good IPv6 port scanner is available at

Continuing in your elevated command prompt on the tunnel Windows machine enter the following command:

netsh interface ipv6 set route ::/0 IP6Tunnel publish=yes

This adds a route for the entire IPv6 address space to go via this machine, and publishes it so that it can be see by other machines on the LAN. The publish=yes command is the only bit of this that is different from the commands provided by Hurricane Electric.

The next command to enter is:

netsh interface ipv6 add address interface=”Local Area Connection” address=2001:xxxx:yyyy:65b::1

This command adds an IP address from the Routed /64 range to the network card on the machine (called “Local Area Connection” here. If your network card has a different name then change the name, and use the correct address that you want to use rather than the generic one I show here). I have chosen to end my routers IPv6 address with ::1. This means that the full address in my example is 2001:xxxx:yyyy:065b:0000:0000:0000:0001 and therefore I could choose anything for the 0000:0000:0000:0001 bit, remembering that one long list of zero’s can be collapsed to :: and leading zero’s can be removed.

Continue with:

netsh interface ipv6 set interface “Local Area Connection” forwarding=enabled advertise=enabled routerdiscovery=enabled advertisedefaultroute=enabled privacy=disabled

The command (which is long and probably wrapped on your web browser) enables forwarding on the Local Area Connection interface (forwards packets arriving on this interface to others, i.e. makes this box a router) and it will also advertise it’s routes and that it is a router. Router advertisement (both advertise=enabled routerdiscovery=enabled) allow clients on your network to find the router and generate their own IPv6 address. In this example this will therefore turn on IPv6 for your entire LAN. If you wish to do this test on just a few servers then add a valid IPv6 address using DHCPv6 with reservations or add the addresses manually on the machines you want to test IPv6 from (valid addresses are 2001:xxxx:yyyy:065b:z:z:z:z, where z:z:z:z is up to four blocks of four hex digits each). Privacy (see later) is disabled for this NIC as well.

NOTE: For any website that is IPv6 enabled, any computer that gets an IPv6 address will now use the tunnel to get to the internet. If the tunnel is down or slow then internet connectivity on all your machines will suffer. Your tunnel will be slower than your WAN speed and latency is likely to be higher. Consider carefully the advertise and routerdiscovery settings. You can always change them to disabled later if you wish (and reset your client network card to pick up the changes with netsh int ipv6 reset). I managed two days with IPv6 for every client before I changed back to IPv4. There are steps on line to change the prefix policy (netsh int ipv6 show prefix) to put IPv4 above IPv6 as an alternative to turning advertising and router discovery off.

The next command to enter is:

netsh interface ipv6 set route 2001:xxxx:yyyy:65b::/64 “Local Area Connection” publish=yes

This command publishes the route to your LAN so that the IP6Tunnel network that you created earlier can route packets to the correct interface. This is the opposite command the the first publish command you ran previously, as that one published the outbound route, this publishes the inbound route.

Finally you need to run this last command:

netsh int ipv6 set interface “IP6Tunnel” forwarding=enabled

This allows packets arriving on the IP6Tunnel from the internet to be forwarded to other networks on the machine. Again, this is the opposite of the earlier forwarding=enabled command and allows forwarding of packets arriving on the IP6Tunnel adapter to be forwarded into the LAN.

Connecting to the IPv6 Internet

Finally you are ready to go. If you open a command prompt on a Windows Vista or later client on the LAN and run ipconfig you should see an IPv6 address (and maybe a temporary IPv6 address) as well as a default gateway listing your newly configured router (reached via the Link Local address rather than the global IP address of the router if routerdiscovery is enabled on the router).

The IPv6 address you have is calculated from your Routed /64 subnet (the network portion of the address) and your MAC address. This local portion will therefore always be the same for you. This means that you are therefore trackable on the internet, as your local portion does not change. Therefore Windows 7 generates a temporary address which changes every 7 days (netsh int ipv6 show addresses and the Pref. Life column for Preferred Lifetime). After seven days the temporary address is recreated.

Open your web browser and visit to see if you have IPv6 connectivity.

You should now be able to ping or ping and get a response back from the IPv6 internet.

Note that if you reboot your router or your client they will take a short while to pick up a valid IPv6 configuration from the Router Advertisements (RADV) that are running on the router (advertising the Routed /64 range you have – no requirement for DHCPv6 in this example).

Having the IPv6 Internet Connect To You (i.e. Publishing IPv6 Services)

On any machine with a valid global IPv6 address you should be able to enable the File and Printer Sharing (Echo Request – ICMPv6-In) rule in Windows Firewall and then visit (or another IPv6 online ping test tool) and be able to ping your server or client.

Disable the ping firewall rule if needed and enable or create a firewall rule to allow a port of your choice to be published over IPv6. Configure the server to support listening on IPv6 if needed and then attempt to browse that service from another IPv6 enabled client.

Got this far – have a go at the IPv6 certification at Hurricane Electric

IPv6 Certification Badge for brainier

Creating a Simple Exchange Server Transport Agent

Posted on 5 CommentsPosted in 2007, 2010, 2013, agent, exchange, mcm, sdk, smtp, transport agent, visual studio

This blog post follows a session that I delivered at the MEC 2012 conference in Orlando. If you attended the conference the slides are available on for the rest of 2012.

Part of the transport agents session was writing a new transport agent, and the example agent was to do add a form of catch-all functionality. The example code below (which purposefully needs editing to work, as its designed to be a learning tool) takes an email in the form of where the final recipient is and the subject line is changed to read [tag] Original Subject. Therefore email addresses can be given out that are an adjusted form of your real address, and on receipt of the email the correct recipient address is determined in code (the value before the _ appended to the domain name) so that you do not need to add lots of aliases to your user account in Active Directory. The subject is then changed to indicate the email came from this alternative original address. For example, an email to would go to and have [linkedin] added to the start of the subject.

As this partial catch all transport agent needs access to the recipient information and the subject, the agent needs to be bound to OnEndOfHeaders or OnEndOfData in the SMTP stack. It could also be bound to OnSubmittedMessage as a routing agent (rather than an SMTP agent) but could not be bound to OnResolvedMessage as recipient resolution has already happened by this point.

Writing the Transport Agent

To create the transport agent you need Visual Studio – the basic version of Visual Studio are sufficient and you need to copy the two DLL’s from Program Files\Microsoft\Exchange Server\V14\Public (or the V15 folder for Exchange 2013) to a folder on your development machine. You need a copy of these DLL’s for every version/service pack/update rollup of Exchange that you will run your agent on, as the DLL’s might change between these versions, and if you have the wrong version you will not be able to install your agent on a new server or if the server is updated, the transport service will fail as it will not be able to load the agent.

In Visual Studio, create a .NET 2 or 3.5 Class Library (for Visual Basic if using the below code) for Exchange 2010 or .NET 4.0 Class Library for Exchange 2013. For the project name enter something descriptive for what you are going to create (rather then ClassLibrary1). For example MECDemoPartialCatchAll.


Copy and paste the following code into the class.vb file, replacing the template text.

   1: Imports System

   2: Imports System.Collections.Generic

   3: Imports System.Text

   4: Imports Microsoft.Exchange.Data.Transport

   5: Imports Microsoft.Exchange.Data.Transport.Smtp


   7: Namespace XXXXX REM Change This


   9:     NotInheritable Class YYYYYY REM Change This

  10:         Inherits SmtpReceiveAgentFactory


  12:         Public Overrides Function CreateAgent(ByVal server As SmtpServer) As SmtpReceiveAgent

  13:             Return New ZZZZZ REM Change This

  14:         End Function


  16:     End Class


  18:     Public Class ZZZZZ REM Change This

  19:         Inherits SmtpReceiveAgent


  21:         Private Sub MyEndOfDataHandler(ByVal source As ReceiveMessageEventSource, ByVal e As EndOfDataEventArgs) Handles Me REM Change This

  22:             ' Get and change the recipient from alias_tag to alias (only doing for 1 recipient for simplicity)

  23:             If e.MailItem.Recipients.Count = 1 And InStr(e.MailItem.Recipients.Item(0).Address, "_") > 1 Then

  24:                 Dim Recipient() As String = Split(e.MailItem.Recipients.Item(0).Address, "@", 2)

  25:                 Dim EmailAlias() As String = Split(Recipient(0), "_", 2)

  26:                 'EmailAlias(0) = alias to send email to

  27:                 'EmailAlias(1) = tag for subject line

  28:                 'Recipient(1) = domain


  30:                 ' The following line prepends [tag] to the subject of the message.

  31: REM Change This                 "[" + EmailAlias(1).ToString + "] " + e.MailItem.Message.Subject


  33:                 'the following drops the current recipient

  34:                 e.MailItem.Recipients.Remove(e.MailItem.Recipients.Item(0).Address)


  36:                 'the following adds the recipient back again, this time using the alias without the tag

  37:                 e.MailItem.Recipients.Add(New RoutingAddress(EmailAlias(0).ToString + "@" + Recipient(1).ToString))

  38:             End If

  39:         End Sub


  41:     End Class


  43: End Namespace

Download this code

The remaining steps on creating the agent will be to modify the lines above that are marked with REM statements and then to add the reference DLL’s you copied from your Exchange Server and finally build your DLL.

Visual Studio can tell you when your code contains errors before you build your code, but to do so you need to reference the DLL’s that you obtained from your Exchange Server earlier in this blog. To do this you need to have copied the two DLL’s to a unique folder on your computer. I use c:\temp\Agent Authoring\Dll\E14-SP2-RU4 to store the DLL’s from Exchange 2010, SP2, RU4. Then when RU5 is released, if the DLL’s have changed I will place them in an E14-SP2-RU5 folder and update the references in my project. If I keep using the same folder then Visual Studio does not refresh the DLL but uses an existing cached copy.

To add the DLL’s right-click the project name to the right of the Visual Studio window and choose Properties (or press Alt+Enter):


Change to the Reference’s tab and click Add > Browse to find and add these two DLL’s.


You should see the two DLL’s listed as well as the default references for DLL’s included in the class library template that you used in Visual Studio.

Back on the code, its time to make the changes. Each of the changes and why it is needed are detailed based on the line numbers above

Line 7 – Namespace

This value of the namespace for the transport agent. Standard conventions indicate that this should be your company name. Therefore in your code change XXXXX to C7Solutions

Line 9 – NotInheritable Class

This value, YYYYYY, is the class that you are creating. This class inherits all the functionality of the Microsoft.Exchange.Data.Transport.Smtp.SmtpReceiveAgentFactory class. For this partial catch-all agent, a good name would be PartialCatchAllFactory.

Line 13 and 18 – Public Class

The Public Class contains the code to execute when the agent is called. This class has a name (ZZZZZ in the sample code above) and should be given a name that represents what the code does. This name in this example can be PartialCatchAll and it needs to be used in Line 13 (inside the PartialCatchAllFactory code to indicate the code to call instead of SmtpReceiveAgentFactory. And of course it is needed on line 18 to name the actual block of code. The name to use for this example will be PartialCatchAll

Line 21 – Handler

This line is missing the end of the code. Its a line that says run the code in this subroutine if the OnEndOfData event is called. Change the end of the line to read Me.OnEndOfData. This value should be one of the suggestions in the drop down list if you have done everything correct so far:


This subroutine also returns e as a pointer to the email message (i.e. you can modify e.MailItem.DeliveryPriority and many other properties) and source as a reference to the SMTP connection (i.e. with source.Disconnect you would close the SMTP session).

In this code lines 34 and 37 change the recipient. Line 34 removes the first recipient and then line 37 adds a new recipient that matches the alias + the domain.

Line 31 – Modify Subject

Finally, this code is missing the start of line 31. You need to enter e.MailItem.Message.Subject =  at the start of the line so that they subject becomes [tag] + original subject.

Building the Transport Agent DLL

The Errors List at the bottom of the Visual Studio screen should be empty by now. So time to build the project. If you have not saved this project in Visual Studio, the DLL will be created in the %temp% directory, so best recommendation is to save the project before building the DLL.

To save the project click File >  Save All and enter a suitable name for the project.


The project name becomes the solution name by default and then click Save.

The final thing to check before you build the DLL is the Root namespace value. This should be set to the name of the class library and can be set during creation of the library. If you have written your library in VB.Net then you will need this value to register the DLL. If you used C# then you will not need this value. As we have used VB.Net above, we need to check the root namespace value. This can be found on the project properties page.


If your DLL is ready to release (i.e. you have build and tested it already) then choose Build > Configuration Manager menu. Change the Active solution configuration to Release and click Close. If you do not make this change then the DLL will be created in the project_name\bin\debug folder and its possible that Visual Studio does not compile all the optimizations to the code that it can. For production items that perform at as good a speed as you can write optimal code, you should change this to Release for the Configuration value. The DLL will be created in project_folder\bin\release.

To build your DLL (debug or release) select the Build > Build RootNamespaceValue menu. This will create a DLL in project_name\bin\debug or project_name\bin\release.  A working version for Exchange 2010 SP2, RU4 can be downloaded from here.

Installing the Transport Agent

Copy the DLL to all your Exchange Servers that have the hub transport role installed on them (or if this should only apply to emails inbound from the internet, then just the servers that are listed on your MX records or the first servers connected to for inbound emails). Place the file in a directory (say C:\C7Agents) and run the following five lines from Exchange Management Shell:

Install-TransportAgent -Name “C7PartialCatchAll” -AssemblyPath “C:\C7Agents\MECDemoPartialCatchAll.dll”
-TransportAgentFactory “MECDemoPartialCatchAll.C7Solutions.PartialCatchAllFactory”

Enable-TransportAgent “C7CatchAll”

Restart-Service MSExchangeTransport


# Recommend closing EMS window now

Note that this restarts the transport service (required) and IIS (which will effect OWA and other CAS roles on the same machine). Remote Powershell (an IIS resource) will lock the DLL open, and so if you need to delete the DLL after uninstalling it, you need to have reset IIS and closed the Powershell window.

Finally, send an email to where name is the part of your email address before the @ in Exchange and is your domain. The value in “value” will be added to the subject as [value]. You get get an email in this form you know your agent has worked.

Transport Agents and Exchange 2013

I’ve also written an additional blog post on the changes for Exchange Server 2013 and transport agents. This covers the things to consider that are different with regards to Exchange 2007/2010 and the new Exchange.