Querying msExchDelegateListLink in Exchange Online with PowerShell

9 Mar 2023 Update:

I updated the script to support Modern Auth (OAuth) which is now required for most things in Exchange Online. Details are in the comments of the new script itself:

https://github.com/Mike-Crowley/Public-Scripts/blob/main/Get-AlternateMailboxes.ps1

If you still want the old one, it will be here for a while

https://github.com/Mike-Crowley/Public-Scripts/blob/main/Get-AlternateMailboxes_BasicAuth.ps1

12 Aug 2020 Update:

A few readers contacted me to report this script no longer works. I got around to investigating it today and see the cause, revealed in a Fiddler trace:

X-AnchorMailbox

(larger)

It would seem Microsoft now needs an anchor mailbox, likely to determine what tenant this request is for. I was able to modify my script to accommodate. Sadly, Microsoft is decomissioning the TechNet Gallery, so I may not update that site, just to have them delete it anyway. Please consider including the following in the script yourself:

... 

#Other attributes available here: https://msdn.microsoft.com/en-us/library/microsoft.exchange.webservices.autodiscover.usersettingname(v=exchg.80).aspx
 
$Headers = @{
'X-AnchorMailbox' = $Credential.UserName
} 

$WebResponse = Invoke-WebRequest https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc -Credential $Credential -Method Post -Body $AutoDiscoverRequest -ContentType 'text/xml; charset=utf-8' -Headers $Headers
[System.Xml.XmlDocument]$XMLResponse = $WebResponse.Content 

... 

$Credential= Get-Credential
Get-AlternateMailboxes -SMTPAddress bob.smith2@contoso.com -Credential $Credential

...

Original Post:

 

There are a number of articles that describe the relationship between the FullAccess permission of an Exchange mailbox and the msExchDelegateListLink attribute. Here are two good ones:

In short, this attribute lists all the other mailboxes your mailbox has FullAccess to, unless AutoMapping was set to $false when assigning the permission. It can be a handy attribute to query when trying to learn what mailboxes might appear in an end-user’s Outlook profile.

This attribute is synced to Office 365 via Azure AD Connect, however, for whatever reason, it is not synced back on-premises for new or migrated mailboxes. It is also not exposed in Get-User, Get-Mailbox, Get-MailboxStatistics, Microsoft Graph or Azure AD Graph.

The information is however included in the user’s AutoDiscover XML response. This is how Outlook knows what mailboxes to mount. If you want to look at this data manually, use the ctrl+right-click tool from the Outlook icon on the system tray. This article describes how to do that, if somehow you’re reading this but don’t already know about this tool:

You can also look at the AutoDiscover XML file via the venerable TestConnectivity.Microsoft.com web site. Look at the bottom of of the file, and you’ll see “AlternativeMailbox” entries.

<AlternativeMailbox>  
<Type>Delegate</Type>
<DisplayName>crowley test 1</DisplayName>
<SmtpAddress>crowleytest1@mikecrowley.us</SmtpAddress>
<OwnerSmtpAddress>crowleytest1@mikecrowley.us</OwnerSmtpAddress>
</AlternativeMailbox>
<AlternativeMailbox>
<Type>Delegate</Type>
<DisplayName>crowley test 2</DisplayName>
<SmtpAddress>crowleytest2@mikecrowley.us</SmtpAddress>
<OwnerSmtpAddress>crowleytest2@mikecrowley.us</OwnerSmtpAddress>
</AlternativeMailbox>

While not exactly the msExchDelegateListLink attribute, its the same difference.

This is neat, but to be useful at scale, we need to query this in PowerShell. Fortunately, there are two methods to fetch the AutoDiscover XML.

You can query these endpoints directly or through the the Exchange Web Services (EWS) API. If you don’t have a preference, Microsoft’s documentation recommends SOAP, which is the approach I’ll discuss here.

Using Invoke-WebRequest and SOAP, we can request specific attributes, such as AlternateMailboxes. Other useful attributes are listed in this article:

While I’m not a developer (developers, please keep your laughter to yourself!), I did manage to cobble together the following SOAP request, which will be the string we “post” to the AutoDiscover service. You’ll notice I’ve marked the user we’re querying and any attributes I might want in bold (modify this list to suit your needs):

<soap:Envelope xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<a:RequestedServerVersion>Exchange2013</a:RequestedServerVersion>
<wsa:Action>http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetUserSettings</wsa:Action>
<wsa:To>https://autodiscover.exchange.microsoft.com/autodiscover/autodiscover.svc</wsa:To>
</soap:Header>
<soap:Body>
<a:GetUserSettingsRequestMessage xmlns:a="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<a:Request>
<a:Users>
<a:User>
<a:Mailbox>bob@contoso.com</a:Mailbox>
</a:User>
</a:Users>
<a:RequestedSettings>
<a:Setting>UserDisplayName</a:Setting>
<a:Setting>UserDN</a:Setting>
<a:Setting>UserDeploymentId</a:Setting>
<a:Setting>MailboxDN</a:Setting>
<a:Setting>AlternateMailboxes</a:Setting>
</a:RequestedSettings>
</a:Request>
</a:GetUserSettingsRequestMessage>
</soap:Body>
</soap:Envelope>

(For this post, I only care about AlternateMailboxes.)

AutoDiscover requires authentication, so we’ll also need to use the Get-Credential cmdlet. Interestingly, any mailbox can query the AutoDiscover response for any other user in the Office 365 tenant. This means, through PowerShell, I can look up the msExchDelegateListLink / AlternativeMailbox values for other users (even without administrative privileges).

I’ve written a function to return the results in a PowerShell array like this:

Get-AlternateMailboxes-Example

I should also point out:

  • It has the Exchange Online URL hard-coded within, though you could adapt this for other URLs if you’d like.
  • Both SMTPAddress and Credential parameters require valid Exchange Online mailboxes (though, as previously mentioned they do not need to be the same mailbox).

Usage Example:

Get-AlternateMailboxes -SMTPAddress bob@contoso.com -Credential (Get-Credential)

Finally, here is the script itself:

Guest Appearance on the Exchange Server Pro Podcast

A few days back, I had an opportunity to chat with Paul Cunningham on his Exchange Server Pro Podcast. Paul is a world-renowned Exchange Server expert and Microsoft MVP, based out of Australia. We discussed ways to protect Exchange from attack, along with other security concepts while responding to the recent news around “OWA Vulnerabilities”.false-true

If you’ve got 30 minutes , check it out!

Podcast Episode 4: Securing Outlook Web App (OWA) and Exchange Server with Mike Crowley

A New and an Updated PowerShell Script

NOTE: Updated November 2016 to include -ServersToQuery and -StartTime and parameters.

e.g.

.\RDPConnectionParser.ps1 -ServersToQuery Server1, Server2 -StartTime "November 1"

————————–

Hey everyone, yes I’m still alive!

Connection Report for Remote Desktop 

I wrote a script that connects to one or multiple servers and captures Remote Desktop logons, disconnects, reconnects and logoffs along with the connecting IP:

Feb 2021 Edit:
Microsoft finally took down the TechNet Gallery. This script is now available on GitHub: https://github.com/Mike-Crowley/Public-Scripts/blob/main/RDPConnectionParser.ps1

Download RDPConnectionParser.ps1 here

Recipient Address Report (Formally ProxyAddressCount)

I also updated the “Exchange Proxy Address (alias) Report” script.  It now includes a few environment metrics, as well as the regular CSV-style output:

Download the updated script here

Feb 2021 Edit:
Microsoft finally took down the TechNet Gallery. This script is now available on GitHub: https://github.com/Mike-Crowley/Public-Scripts/blob/main/RecipientReportv5.ps1

Converting SMTP Proxy Addresses to Lowercase

Update: Be aware, this script has not been tested with SIP, X400 or other address types. I am working on an update to validate these scenarios, but in the meantime, proceed at your own risk with these address types.

I recently encountered a question in an online forum where someone asked for a script to convert all of their user’s email addresses to lower case values.  While this doesn’t affect the message delivery, it can have an impact on aesthetics when the address is displayed in an external recipient’s email client.  An Exchange Email Address Policy can do this to some degree, but I wanted to see how it could be done with PowerShell.

The challenge with a script like this is twofold:

  1. Email addresses (proxy addresses) are a multi-valued attribute, which can be tricky to work with.
  2. PowerShell is generally not case-sensitive, and therefore when we try to rename Mr. Gallalee’s email address in the screenshot below, we can see that it does not work:

WARNING: The command completed successfully but no settings of 'demolab.local/Users/Rob Gallalee' have been modified.

After a little bit of inspiration from a script written by Michael B Smith, I came up with the below:


$MailboxList = Get-Mailbox  -ResultSize unlimited

$MailboxList | % {

$LoweredList = @()
$RenamedList = @()

foreach ($Address in $_.EmailAddresses){
if ($Address.prefixstring -eq "SMTP"){
$RenamedList += $Address.smtpaddress + "TempRename"
$LoweredList += $Address.smtpaddress.ToLower()
}
}
Set-mailbox $_ -emailaddresses $RenamedList -EmailAddressPolicyEnabled $false
Set-mailbox $_ -emailaddresses $LoweredList

#Without this line the "Reply To" Address could be lost on recipients with more than one proxy address:
Set-mailbox $_ -PrimarySmtpAddress $_.PrimarySmtpAddress
}

This script works as follows:

  1. Puts all mailboxes into the $MailboxList variable.  If you don’t want all mailboxes,  edit the Get-Mailbox cmdlet as you see fit.
  2. Filters out X400 and other non-SMTP addresses.
  3. Creates an array called $RenamedList which stores each proxy address with “TempRename” appended to it (e.g. Rgallalee@demolab.localTempRename).
  4. Creates another array ($LoweredList) and use the “ToLower” method on each proxy address.
  5. Sets the proxy address for the user to the value of $RenamedList and then to $LoweredList.
    1. This is how we get around the case case insensitivity – name it to something else and then name it back.
  6. Step 4 and 5 don’t preserve the “Primary” / “Reply-To” address, so we set it back manually with the last line.

Note: This script turns off the email address policy for each user.

As always, feedback is welcome.

EDIT Dec 2018:
This is a similar approach, but for mailboxes migrated to Office 365. In this case, only the Primary SMTP addresses are targeted.

It may also be faster than the above, due to the fact we’re only operating against mailboxes that have uppercase (vs all of them).

Set-ADServerSettings -ViewEntireForest:$true

$TargetObjects = Get-RemoteMailbox -ResultSize Unlimited | Where {$_.PrimarySmtpAddress.ToLower() -cne $_.PrimarySmtpAddress}

Write-Host $TargetObjects.count "Remote mailboxes have one or more uppercase characters." -ForegroundColor Cyan

#Backup First
Function Get-FileFriendlyDate {Get-Date -format ddMMMyyyy_HHmm.s}
$DesktopPath = ([Environment]::GetFolderPath("Desktop") + '\')
$LogPath = ($DesktopPath + (Get-FileFriendlyDate) + "-UppercaseBackup.xml")

$TargetObjects | select DistinguishedName, PrimarySMTPAddress, EmailAddresses | Export-Clixml $LogPath
Write-Host "A backup XML has been placed here:" $LogPath -ForegroundColor Cyan
Write-Host

$Counter = $TargetObjects.Count

foreach ($RemoteMailbox in $TargetObjects) {

    Write-Host "Setting: " -ForegroundColor DarkCyan -NoNewline
    Write-Host $RemoteMailbox.PrimarySmtpAddress -ForegroundColor Cyan
    Write-Host "Remaining: " -ForegroundColor DarkCyan -NoNewline
    Write-Host $Counter -ForegroundColor Cyan

    Set-RemoteMailbox $RemoteMailbox.Identity -PrimarySmtpAddress ("TMP-Rename-" + $RemoteMailbox.PrimarySmtpAddress) -EmailAddressPolicyEnabled $false
    Set-RemoteMailbox $RemoteMailbox.Identity -EmailAddresses @{remove = $RemoteMailbox.PrimarySmtpAddress}

    Set-RemoteMailbox $RemoteMailbox.Identity -PrimarySmtpAddress $RemoteMailbox.PrimarySmtpAddress.ToLower()
    Set-RemoteMailbox $RemoteMailbox.Identity -EmailAddresses @{remove = ("TMP-Rename-" + $RemoteMailbox.PrimarySmtpAddress)}

    $Counter --
}

Write-Host
Write-Host "Done." -ForegroundColor DarkCyan

#End

 

Combining PowerShell Cmdlet Results

In my last post I used used New-Object to create an desirable output when the “Get-Mailbox” cmdlet didn’t meet my needs.  If your eyes glazed over trying to read the script, let me make it a bit simpler by focusing on a straight forward example.

Say you need to create a list of user’s mailbox size with their email address.  This sounds like a simple request, but what you’d soon find is that mailbox sizes are returned with the Get-MailboxStatistics cmdlet and the email address is not.  For that, you need to use another cmdlet, such as Get-Mailbox.

With the New-Object cmdlet, we are able to make a custom output that contains data from essentially wherever we want.

See this example:

$MyObject = New-Object PSObject -Property @{
EmailAddress = $null
MailboxSize = $null
}

In this example, I have created a new object with 2 fields, and saved it as the $MyObject variable.

For now, we’ve set the data to null, as shown below:

$MyObject

The next step is to populate each of those fields.  We can write to them one at a time with lines like this:

$MyObject.EmailAddress = (Get-Mailbox mcrowley).PrimarySmtpAddress
$MyObject.MailboxSize = (Get-MailboxStatistics mcrowley).TotalItemSize

Note: The variable we want to populate is on the left, with what we want to put in it on the right.

To confirm our results, we can simply type the variable name at the prompt:

$MyObject with data

Pretty cool, huh?

Ok, so now about that list.  My example only shows the data for mcrowley, and you probably need more than just 1 item in your report, right?

For this, you need to use the foreach loop.  You can read more about foreach here, but the actual code for our list is as follows:

(I am actually going to skip the $null attribute step here)

$UserList = Get-mailbox -Resultsize unlimited
$MasterList = @()
foreach ($User in $UserList) {
$MyObject = New-Object PSObject -Property @{
EmailAddress = (Get-Mailbox $User).PrimarySmtpAddress
MailboxSize = (Get-MailboxStatistics $User).TotalItemSize
}
$MasterList += $MyObject
}
$MasterList

$MasterList with data

Finally, if you wanted to make this run faster, we really don’t need to run “get-mailbox” twice.  For better results, replace the line:

EmailAddress = (Get-Mailbox $User).PrimarySmtpAddress

With this one:

EmailAddress = $User.PrimarySmtpAddress

Exchange Proxy Address (alias) Report

Feb 2021 Edit:
Microsoft finally took down the TechNet Gallery. This script is now available on GitHub: https://github.com/Mike-Crowley/Public-Scripts/blob/main/RecipientReportv5.ps1

————–

Exchange Server stores user’s alternate email addresses as a multi-valued attribute within Active Directory.  For example, if my colleague Jorge has jdiaz@demolab.local as well as diazj@demolab.local, his proxyAddresses attribute would look like this:

ADUC - ProxyAddresses

Notice, the capital SMTP vs. the lowercase smtp.  There can be only one uppercase SMTP, and this represents the primary, or “reply to” address.

While, it’s very easy to view someone’s proxy addresses (often called aliases, but don’t confuse it with the “alias” attribute) within the Exchange Management Console, it can be tough to work with in the Exchange Management Shell (PowerShell) due to the data being stored as a  “Multi-Valued” attribute.  The usual “Get-Mailbox” output not only shows all addresses as a single item, but in the case “mcrowley” below, we can see the shell truncates:

get-mailbox mcrowley | select emailaddresses

While there are ways (example1, example2) to manipulate this output on the screen, I recently needed to create a complete list of all users possessing one or more secondary email address, and document what those addresses were.

On the surface, this sounds simple.  We want a list of users who have more than 1 proxy address.  At first, I thought of something like this:

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

Get-Mailbox -Filter {emailaddresses -gt 1} | Select EmailAddresses

But we can see this doesn’t actually capture the correct users.  In the above example, LiveUser1 only has a single proxy address, but it was returned anyway.  This is because the result is actually converted to a number, and the “-gt” or “greater than” operation is done on this number; not what we want.

I have written a script to help!

Features:

  1. This script creates a CSV output of everyone’s SMTP proxy addresses.
  2. Reports to the screen the total number of users found.
  3. Reports to the screen the user(s) with the most proxy addresses.
  4. You can configure the threshold of users reported. For example, if you only wanted users with 2 or more proxy addresses included, you should change the line: “$Threshold = 0” to “$Threshold = 2”

Misc:

  1. Does not currently work with Exchange Online (planned enhancement).
  2. This uses “get-recipient” with no filters by default.  You may want to  replace this with something more restrictive, like “get-mailbox”, or use the -filter parameter.
  3. Requires PS 2.0 (for Exchange 2007, see here)

Here is a sample output, shown in excel:

Sample output to screen:

The guts of this script might help with this exact scenario, or really, anywhere you want to break out and evaluate multi-valued attributes.  Feel free to use it and adjust as you see fit!

Download the script here, or copy from the text below:

&amp;lt;#

Features:
1) This script Creates a TXT and CSV file with the following information:
a) TXT file: Recipient Address Statistics
b) CSV file: Output of everyone's SMTP proxy addresses.

Instructions:
1) Run this from &amp;quot;regular&amp;quot; PowerShell.  Exchange Management Shell may cause problems, especially in Exchange 2010, due to PSv2.
2) Usage: RecipientReportv5.ps1 server5.domain.local

Requirements:
1) Exchange 2010 or 2013
2) PowerShell 4.0

April 4 2015
Mike Crowley

http://BaselineTechnologies.com

#&amp;gt;

param(
[parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage='Type the name of a Client Access Server')][string]$ExchangeFQDN
)

if ($host.version.major -le 2) {
Write-Host &amp;quot;&amp;quot;
Write-Host &amp;quot;This script requires PowerShell 3.0 or later.&amp;quot; -ForegroundColor Red
Write-Host &amp;quot;Note: Exchange 2010's EMC always runs as version 2.  Perhaps try launching PowerShell normally.&amp;quot; -ForegroundColor Red
Write-Host &amp;quot;&amp;quot;
Write-Host &amp;quot;Exiting...&amp;quot; -ForegroundColor Red
Sleep 3
Exit
}

if ((Test-Connection $ExchangeFQDN -Count 1 -Quiet) -ne $true) {
Write-Host &amp;quot;&amp;quot;
Write-Host (&amp;quot;Cannot connect to: &amp;quot; + $ExchangeFQDN) -ForegroundColor Red
Write-Host &amp;quot;&amp;quot;
Write-Host &amp;quot;Exiting...&amp;quot; -ForegroundColor Red
Sleep 3
Exit
}

cls

#Misc variables
#$ExchangeFQDN = &amp;quot;exchserv1.domain1.local&amp;quot;
$ReportTimeStamp = (Get-Date -Format s) -replace &amp;quot;:&amp;quot;, &amp;quot;.&amp;quot;
$TxtFile = &amp;quot;$env:USERPROFILE\Desktop\&amp;quot; + $ReportTimeStamp + &amp;quot;_RecipientAddressReport_Part_1of2.txt&amp;quot;
$CsvFile = &amp;quot;$env:USERPROFILE\Desktop\&amp;quot; + $ReportTimeStamp + &amp;quot;_RecipientAddressReport_Part_2of2.csv&amp;quot;

#Connect to Exchange
Write-Host (&amp;quot;Connecting to &amp;quot; + $ExchangeFQDN + &amp;quot;...&amp;quot;) -ForegroundColor Cyan
Get-PSSession | Where-Object {$_.ConfigurationName -eq 'Microsoft.Exchange'} | Remove-PSSession
$Session = @{
ConfigurationName = 'Microsoft.Exchange'
ConnectionUri = 'http://' + $ExchangeFQDN + '/PowerShell/?SerializationLevel=Full'
Authentication = 'Kerberos'
}
Import-PSSession (New-PSSession @Session)

#Get Data
Write-Host &amp;quot;Getting data from Exchange...&amp;quot; -ForegroundColor Cyan
$AcceptedDomains = Get-AcceptedDomain
$InScopeRecipients = @(
'DynamicDistributionGroup'
'UserMailbox'
'MailUniversalDistributionGroup'
'MailUniversalSecurityGroup'
'MailNonUniversalGroup'
'PublicFolder'
)
$AllRecipients = Get-Recipient -recipienttype $InScopeRecipients -ResultSize unlimited | select name, emailaddresses, RecipientType
$UniqueRecipientDomains = ($AllRecipients.emailaddresses | Where {$_ -like 'smtp*'}) -split '@' | where {$_ -NotLike 'smtp:*'} | select -Unique

Write-Host &amp;quot;Preparing Output 1 of 2...&amp;quot; -ForegroundColor Cyan
#Output address stats
$TextBlock = @(
&amp;quot;Total Number of Recipients: &amp;quot; + $AllRecipients.Count
&amp;quot;Number of Dynamic Distribution Groups: &amp;quot; +         ($AllRecipients | Where {$_.RecipientType -eq 'DynamicDistributionGroup'}).Count
&amp;quot;Number of User Mailboxes: &amp;quot; + 	                    ($AllRecipients | Where {$_.RecipientType -eq 'UserMailbox'}).Count
&amp;quot;Number of Mail-Universal Distribution Groups: &amp;quot; + 	($AllRecipients | Where {$_.RecipientType -eq 'MailUniversalDistributionGroup'}).Count
&amp;quot;Number of Mail-UniversalSecurity Groups: &amp;quot; + 	    ($AllRecipients | Where {$_.RecipientType -eq 'MailUniversalSecurityGroup'}).Count
&amp;quot;Number of Mail-NonUniversal Groups: &amp;quot; + 	        ($AllRecipients | Where {$_.RecipientType -eq 'MailNonUniversalGroup'}).Count
&amp;quot;Number of Public Folders: &amp;quot; + 	                    ($AllRecipients | Where {$_.RecipientType -eq 'PublicFolder'}).Count
&amp;quot;&amp;quot;
&amp;quot;Number of Accepted Domains: &amp;quot; + $AcceptedDomains.count
&amp;quot;&amp;quot;
&amp;quot;Number of domains found on recipients: &amp;quot; + $UniqueRecipientDomains.count
&amp;quot;&amp;quot;
$DomainComparrison = Compare-Object $AcceptedDomains.DomainName $UniqueRecipientDomains
&amp;quot;These domains have been assigned to recipients, but are not Accepted Domains in the Exchange Organization:&amp;quot;
($DomainComparrison | Where {$_.SideIndicator -eq '=&amp;gt;'}).InputObject
&amp;quot;&amp;quot;
&amp;quot;These Accepted Domains are not assigned to any recipients:&amp;quot;
($DomainComparrison | Where {$_.SideIndicator -eq '&amp;lt;='}).InputObject
&amp;quot;&amp;quot;
&amp;quot;See this CSV for a complete listing of all addresses: &amp;quot; + $CsvFile
)

Write-Host &amp;quot;Preparing Output 2 of 2...&amp;quot; -ForegroundColor Cyan

$RecipientsAndSMTPProxies = @()
$CounterWatermark = 1

$AllRecipients | ForEach-Object {

#Create a new placeholder object
$RecipientOutputObject = New-Object PSObject -Property @{
Name = $_.Name
RecipientType = $_.RecipientType
SMTPAddress0 =  ($_.emailaddresses | Where {$_ -clike 'SMTP:*'} ) -replace &amp;quot;SMTP:&amp;quot;
}

#If applicable, get a list of other addresses for the recipient
if (($_.emailaddresses).count -gt '1') {
$OtherAddresses = @()
$OtherAddresses = ($_.emailaddresses | Where {$_ -clike 'smtp:*'} ) -replace &amp;quot;smtp:&amp;quot;

$Counter = $OtherAddresses.count
if ($Counter -gt $CounterWatermark) {$CounterWatermark = $Counter}
$OtherAddresses | ForEach-Object {
$RecipientOutputObject | Add-Member -MemberType NoteProperty -Name (“SmtpAddress” + $Counter) -Value ($_ -replace &amp;quot;smtp:&amp;quot;)
$Counter--
}
}
$RecipientsAndSMTPProxies += $RecipientOutputObject
}

$AttributeList = @(
'Name'
'RecipientType'
)
$AttributeList += 0..$CounterWatermark | ForEach-Object {&amp;quot;SMTPAddress&amp;quot; + $_}

Write-Host &amp;quot;Saving report files to your desktop:&amp;quot; -ForegroundColor Green
Write-Host &amp;quot;&amp;quot;
Write-Host $TxtFile -ForegroundColor Green
Write-Host $CsvFile -ForegroundColor Green

$TextBlock | Out-File $TxtFile
$RecipientsAndSMTPProxies | Select $AttributeList | sort RecipientType, Name | Export-CSV $CsvFile -NoTypeInformation

Write-Host &amp;quot;&amp;quot;
Write-Host &amp;quot;&amp;quot;
Write-Host &amp;quot;Report Complete!&amp;quot; -ForegroundColor Green

Dealing with PST Files

Chances are, if you read my site, you also read the Exchange team blog.  This means you’ve seen the PST Capture Tool!  I’ve had a chance to work with this tool for a little while now and have found it to be a delight!PST File

“PSTs are bad M’kay?“

This is a line we’ve all recited a time or two (ok maybe not exactly that line), but do we even know why?  Are we just parrots, or do we actually have a reason for condemning this hugely prolific file format?

Let’s start by acknowledging that PST files aren’t all bad.  M’kay?  If you run Outlook at home, or if you use IMAP/POP-based accounts (Gmail, Hotmail, etc) at work, using a PST file can actually be a good idea.  While it is possible to direct internet mail to the Exchange mailbox, this would create several problems:

    • Wasting expensive Exchange disk space
    • Potential violation of company policies
    • Internet mail is now subject to corporate retention (and discovery!) policies
    • Makes moving to a job more painful
    • etc.

AutoArchive Group Policy Settings

I’d even go so far as to say you might want to use PST files for archiving corporate email!  If you run a small shop – or a big one that isn’t subject to any retention policies.  A group policy configuring AutoArchive (and a note to your users) might be a good way to implement spring cleaning in your Exchange data stores.

See, PST files actually can serve a purpose!

Then there is the other side of the coin:

In most situations, PST files represent unmanaged storage of email.  For someone who is charged with administering an email environment, this means we aren’t able to do our job.  If users begin to rely on something that we aren’t taking care of; what happens when it breaks?  We’ve all had the uncomfortable task of telling someone we can’t get their data back at least once in our careers.  It doesn’t make for fun times.

More important than our comfort; many organizations are subject to regulations which require them to turn email data over to the courts upon request.  A judge wont want to hear your sob story about how PST files aren’t searchable, and how you’re going to have to look across the whole network by hand to find that email thread.

I recently completed an Exchange 2010 deployment for a government organization that was subject to such legislation.  Once we activated the Personal Archive for their users, they decided to put the kibosh on PST files.  To enforce this, we laid out a three phased approach:

  1. Prevent the users from making new PST files
  2. Prevent the users from adding content to existing PST files
  3. Use the abovementioned PST Capture Tool to import PSTs as necessary

The first two steps were quite simple to accomplish.  Outlook reads a registry value called PSTDisableGrow (REG_DWORD).  We deployed a GPO to implement this as follows:

Outlook 2003 HKCU\Software\Microsoft\Office\11.0\Outlook\PST\
Outlook 2007 HKCU\Software\Microsoft\Office\12.0\Outlook\PST\
Outlook 2010 HKCU\Software\Microsoft\Office\14.0\Outlook\PST\

Set PSTDisableGrow to “1” (without the quotes).  This will allow users to mount PST files in Outlook, but it will not allow any new content to be placed within.  Don’t worry about overkill here.  I used a single GPO for all 3 settings.  Outlook version X doesn’t care about extra registry settings in Outlook Y’s key.

PSTDisableGrow has some siblings; read more about DisablePST, DisableCrossAccountCopy and DisableCopyToFileSystem here.

That’s all for now, have a great week!

EDIT: Be sure to also check out this relevant blog post by the Microsoft Exchange product group: Deep Sixing PST Files

Exchange 2010 Service Pack 2

Today, Microsoft released SP2 for Exchange 2010.  Version 14.2 (Build 247.5)

You can download SP2 here.

As previously announced, the major features for this update focus on the following areas:

  • A “Hybrid Configuration Wizard” (HCW) – which is used to guide administrators through the Office 365 Rich Coexistence setup.  BTW, you’ll notice Microsoft actually no longer uses the phrase “Rich Coexistence”, but instead prefers “hybrid” configuration.
  • Address Book Policies (ABP) – which allow an Exchange organization to segment the address list so that separate user populations can be hidden from each other (such as in a multi-tenant environment).  Here is an article that describes how this works, as well as another discussing some of the limitations.
  • Cross-Site Silent Redirection for OWA – which allows more seamless OWA redirection in a multi-site topology.
  • OWA Mini – which provides a text-only OWA experience so that you can use OWA from phones that do not support ActiveSync.

Here are some other fun facts:

  • Exchange 2010 SP2 extends the schema.  One interesting change is the new msExchExtensionAttribute attributes.  We’ve had 15 custom attributes for a while now, but this adds 30 more, all of which are multi-valued.  For your reference, Microsoft tracks Exchange schema extensions on this page.
  • Administrators can now disable the auto-mapping of user mailboxes in Outlook 2007/2010.  This may be helpful if a user has the “Full Access” permission to many other mailboxes.  By default, Outlook will try to mount all of them which could cause performance issues.
  • The "IIS 6 WMI Compatibility" component is requiredYou’ll need to add the “IIS 6 WMI Compatibility” component if you are upgrading from RTM or SP1.  A fresh install would offer to add this for you, but if you’re upgrading, you’ll need add it yourself.  You can easily add the IIS role service with the following two PowerShell commands:
         Import-Module servermanager
        Add-WindowsFeature Web-WMI
  • On some new hardware, I clocked the upgrade at ~22 minutes.  Ironically, Exchange Update Rollups often take longer than this!

Exchange Connections Slide Decks

Thanks to all who attended my sessions at Exchange Connections in Las Vegas this week!

As promised, I have uploaded the slides. You can download them here:

 

If you’re looking for slides from other presenters, you can find them here:

 

Hosting Exchange 2010 without the /hosting switch

The EHLO blog posted an important announcement today regarding Exchange 2010 in hosted environments.  Previously, for Microsoft to support your multi-tenant deployment of Exchange 2010, you had to build a whole new forest and use a special setup.com /hosting installation process.  There were other significant limitations as well.

The strict support statement, combined with Microsoft’s release of Office 365 really came as a one-two punch to some of the smaller companies who wished to host Exchange but could not afford to employ developers and/or take the risk of forfeiting support from Microsoft.  It seemed like Microsoft may have lost some love for their hosting partners.

With the Exchange 2010 SP2 update (scheduled to launch later this year), you will be able to host a multi-tenant environment with a regular deployment of Exchange.  This is made possible by the new Address Book Policies and specific configurations to be documented with the SP2 release.

Personally, I’d look at this very carefully before deploying any new /hosting environments.  This (SP2) seems like a much simpler deployment to maintain.

Speaking at Exchange Connections: November 2nd & 3rd in Las Vegas, Nevada

DevConnectionsWould you like an excuse to get out of the office for a few days?  When is the last time you learned something new?  Or how would you like an opportunity to share fresh ideas on the technology you’re passionate for?

Or heck, maybe it’s just been a while since you’ve been to Vegas?  Winking smile

Join me and other Microsoft enthusiasts at the DEVCONNECTIONS conference this fall!  This semiannual event covers many tracks from Visual Studio to Exchange Server to Microsoft’s hot new cloud products: Azure and Office 365.

In addition to attending some great sessions, I will also be presenting on two topics:

Exchange Online: Administration
Be careful not to fool yourself; Exchange Online (part of Office 365) offloads infrastructure management, but as an administrator, you are still responsible for the administration of your user mailboxes, Internet mail flow, message tracking and more! This session introduces you to the various administrative interfaces of Exchange Online, Forefront, RBAC, provisioning and other operational topics.
Exchange Online: Understanding Archiving and Compliance
Thinking of moving to Office 365? Whether you are aiming for a period of coexistence or a complete migration, your archival and compliance requirements are not going away! In this session we examine the features and functionality that Microsoft provides around retention, archiving, and search.

 

Sign up here, and use the SPKR discount code to save $50.

And if that’s not incentive enough, I’ll close by reminding you that Halloween in Las Vegas should prove to be very interesting…

Microsoft Office 365: A “Tales From The Trenches” Roundtable Webcast

Register for the 7/27/11 Webcast!

The long awaited release of Microsoft Office 365 has arrived. Now what? As nice as it would be to flip a switch and perform your migration, we all know the process is a bit more involved. So, how do you get there from here?

Join Planet and Microsoft experts who’ve been in the trenches participating in thousands of migrations to O365 to date. In this one hour interactive roundtable, they’ll share insights into:

  • Lessons learned from the early Beta adopters regarding the biggest challenges and hurdles to deployment
  • The critical need to address the underlying health of your Active Directory PRIOR to migration, and specific steps for cleaning up your environment
  • Security issues and features
  • Realistic migration timeline expectations
  • A head-to-head analysis of O365 and the competition

There is no cost to participate but space is limited so register today!

REGISTER NOW

 

About Planet Technologies

Planet Technologies is recognized world-wide as a leading expert in the integration and customization of Microsoft technologies, architecture, security and management consulting.  We offer Microsoft based solutions around business intelligence, CRM, collaboration and messaging, cloud services, desktop deployment, SharePoint solutions, unified communications, virtualization and more. Visit us a www.go-planet.com

ExRCA Now Supports Office 365

imageThe Exchange Microsoft Remote Connectivity Analyzer has been an essential tool for Exchange administrators since it’s initial release.  This site will attempt to connect to your environment through a variety of methods to help you ensure all is well, or troubleshoot issues related to client connectivity. 

If you haven’t seen this tool, you should definitely check it out:

http://www.TestExchangeConnectivity.com (or the short link: http://exrca.com)

Last week, Microsoft updated this tool to include support for Office 365.  While you wouldn’t actually be troubleshooting Microsoft’s Exchange environment, this new tab allows you to validate your URLs and configurations related to the “Rich-Coexistence” scenario.

Another interesting fact: Microsoft announced plans to incorporate other products into this tool, beyond Exchange Server. 

For a complete list of changes in this version, see the release notes.

 

Exchange Remote Connectivity Analyzer