Capturing ProxyAddresses Before-and-After

5/5 - (1 vote)

This past weekend, while working with a customer on a new proof-of-concept deployment of Exchange Hybrid and Microsoft Teams, we had a need to validate that no user accounts would be inadvertently updated during the upgrading of Exchange 2003 Recipient Policies to modern Exchange email address policies.

Background

Despite the customer having only Exchange 2016 servers in their environment, none of the policies had been upgraded from the legacy Ldap-filter syntax circa Exchange 2003.

It’s a long, long story.  We can talk about it over beers sometime.

After using Bill Long’s trusted ConvertFrom-LdapFilter script to determine the correct syntax, it was time to go.  However, the customer was unsure about the ramifications of running this to update policies (as their legacy EAPs hadn’t been touched in nearly 20 years).

The primary concerns?

  • Would this trigger a re-evaluation of EAPs?
  • Would this trigger an address book rebuild?
  • If users had been modified outside the Exchange management interface, would email addresses get updated or removed for those users if the EmailAddressPolicyEnabled property is set to True?

While the answer to all of those is upgrading an EAP should not trigger an address book rebuild, it’s always better to have a backup than to not.

So, here’s a quick way to compare a before and after for email addresses.

Before Script

First, you need to capture the current state of things.  While you could dump it to a CSV for easy reading, I prefer to have this type of data in XML (because it means fewer PSCustomObject types).

The customer built their EAPs based on unique values in Department, but you can use any attribute:

<#
.SYNOPSIS 
Export core values before policy changes.

.PARAMETER FilterableProperty
Select any filterable property name.

.PARAMETER FilterablePropertyValue
Enter a string value to match.

.PARAMETER Output
Output file name.

#>
param (
[string]$FilterableProperty,
[string]$FilterablePropertyValue,
[string]$Output = "Recipients.xml"
)
If ($FilterableProperty -and $FilterablePropertyValue ) { Get-Recipient -Filter "$FilterableProperty -eq '$FilterablePropertyValue'" -ResultSize Unlimited | Select Identity, DisplayName, Alias, SamAccountName, PrimarySmtpAddress, EmailAddresses, $FilterableProperty | Export-Clixml $Output -Force }
Else { Get-Recipient -Resultsize Unlimited | Select Identity, DisplayName, Alias, SamAccountName, PrimarySmtpAddress, EmailAddresses | Export-Clixml $Output -Force }

The content will be saved in the file name specified in $Output (or the -Output parameter).

After Script

Once you’ve made changes that could potentially impact users, you can re-run an export and compare the differences.

<#
.SYNOPSIS 
Export core values after policy changes.

.PARAMETER FilterableProperty
Select any filterable property name.

.PARAMETER FilterablePropertyValue
Enter a string value to match.

.PARAMETER Output
Output file name for differences.

.PARAMETER Source
Input file name of source XML (generated from BEFORE script).

#>

param(
[string]$FilterableProperty,
[string]$FilterablePropertyValue,
[string]$Output = "Differences.csv",
[string]$Source = "Recipients.xml"
)

If ($FilterableProperty -and $FilterablePropertyValue) { $PostChange = Get-Recipient -Filter "$FilterableProperty -eq '$FilterablePropertyValue'" -Resultsize Unlimited | Select Identity, Alias, SamAccountName, PrimarySmtpAddress, EmailAddresses, EmailAddressPolicyEnabled }
Else { $PostChange = Get-Recipient -Resultsize Unlimited | Select Identity, Alias, SamAccountName, PrimarySmtpAddress, EmailAddresses, EmailAddressPolicyEnabled }

$Original = Import-Clixml $Source

Foreach ($Recipient in $Original)
{
Foreach ($Address in $Recipient.EmailAddresses)
{
If ($Address.ProxyAddressString -ilike "smtp:*") {
If ($PostChange.EmailAddresses.ProxyAddressString -match $Address.ProxyAddressString )
{
#do nothing, object found 
}
Else
{
"$($Address.ProxyAddressString) for $($Recipient.DisplayName) ($($Recipient.Alias)) not found"
Add-Content -Path "$Output" "$($Address.ProxyAddressString),$($Recipient.Alias),$($Recipient.EmailAddressPolicyEnabled)"
}
}
}
}

Again, just like the before script, you can use the FilterableProperty and FilterablePropertyValue to scope your selection.

Ta-da!

The output file (specified in the -Output parameter) will have a comma-separated list identifying any missing proxy address, alias, and the current value of the object’s EmailAddressPolicyEnabled property.

Updates away!

 

author avatar
Aaron Guilmette
Helping companies conquer inferior technology since 1997. I spend my time developing and implementing technology solutions so people can spend less time with technology. Specialties: Active Directory and Exchange consulting and deployment, Virtualization, Disaster Recovery, Office 365, datacenter migration/consolidation, cheese.