Exchange Web Services & Powershell - Contact Update Issues

Hi All,

I am using EWS with Powershell for the first time, and although my code works, I have run across an issue I am not able to fix. I am trying to fix users' contacts that have been imported incorrectly from another mail system, which is working fine for most entries. However, when an email address field includes a colon (:) when I call the address using the following:

($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1].Address)

it does not read the address. I have identified this doesn't appear to be a code issue, as when I replace the address with another, still with invalid characters, such as < and spaces, this works fine. I presume this would be a conflict with the EWS syntax and use of : within the syntax itself.

I have tried finding a way to separate the "EmailAddress1" part so that the colon included within the address field doesn't affect the script but haven't found a successful way of doing this. I hope all the above makes sense. Is there anyone who is able to direct me to a solution so we can call the email addresses that contain the invalid colons? 

Many thanks,

Mike Parker

February 3rd, 2015 8:30am

Yes, I see this too. The server doesn't return the address because it's invalid. However, I noticed that it does return a Name for the EmailAddress entry, which contains the invalid address, so you might be able to do some string manipulation to extract the value.

In other words, this:

($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1].Name)

Gives this:

"Colon Man (colon:foo@bar.com)"

Free Windows Admin Tool Kit Click here and download it now
February 3rd, 2015 9:46am

Hi Jason,

Thanks for the response. This would possibly be an option, however, on my test users I am not getting the Name field either. I just created a new contact to test this. In OWA the contact looks like this: 



But if I run the following in Powershell:

foreach($contact in $contacts){($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1])}

I get 5 of the following (I have added colons to each of the contacts for testing purposes):

Name        :
Address     :
RoutingType :
MailboxType :
Id          :

Any more ideas? =)

Thanks,

Mike

February 3rd, 2015 9:56am

It would help to see more of your code. Did you call Contact.Bind to load all the properties?
Free Windows Admin Tool Kit Click here and download it now
February 3rd, 2015 10:00am

Please see the relevant portion of code below. If you need any more please let me know:

$ContactsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts)
$Contacts = $ContactsFolder.FindItems(100)
ForEach($contact in $contacts) {

	$error.clear()
	$iter1 = ($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1].Address)
	$iter2 = ($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress2].Address)
	$iter3 = ($contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress3].Address)
	$enumEmailAddress1 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress1;
	$enumEmailAddress2 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress2;
	$enumEmailAddress3 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress3;
	$enumDisplayName = [Microsoft.Exchange.WebServices.Data.ContactSchema]::DisplayName


	$DisplayName = $contact.DisplayName
	# write-host "$DisplayName"
	$iter = 1
	$LogOutput = $DisplayName 
	while ($iter -lt 4){
		$error.clear()
		Write-Host "Working on Email Address $iter of contact $DisplayName";
		if ($iter -eq 1){
			$contactEmail = $iter1
			$enumEmailAddress = $enumEmailAddress1
		}
		elseif($iter -eq 2){
			$contactEmail = $iter2
			$enumEmailAddress = $enumEmailAddress2
		}
		elseif($iter -eq 3){
			$contactEmail = $iter3
			$enumEmailAddress = $enumEmailAddress3
		}

		$LogOutput = $LogOutput + "," + $contactEmail
		if(($contactEmail -eq "mailto:toi.smdioa@beicn.com") -or ($contactEmail -like "*<*") -or ($contactEmail -like "*>*")){
			$contactEmail = $contactEmail.Split('<')[1]
			$contactEmail = $contactEmail.Split('>')[0]
			$contactEmail = $contactEmail -replace ("mailto:","")
			$contactEmail = $contactEmail -replace ("'","")

			$Contact.EmailAddresses[$enumEmailAddress] = $contactEmail
			$LogOutput = $LogOutput + "," + $contactEmail

		}
		$iter++
	} # End of While
	$Contact.Update($enumAlwaysOverWrite)

	#.ADD Output the $LogOutput to the log file here
	Out-File -FilePath $logCSV -InputObject $LogOutput -Encoding UTF8 -append

} # End of ForEach Contact

Thanks again for your help! 

Mike 


February 3rd, 2015 10:09am

Try calling Contact.Load before accessing the email properties to ensure that all of the relevant properties are loaded.

Free Windows Admin Tool Kit Click here and download it now
February 3rd, 2015 10:30am

Sorry to be a pain, would you be able to provide an example of how this would be used in this situation?

Not familiar with the Contact.Load() 

Thanks,

Mike

February 3rd, 2015 10:36am

Ok, so I actually tried this from Powershell, and I reproduced it when creating the ExchangeService object while specifying Exchange2007_SP1. When I changed it to Exchange2013_SP1 it worked. What version of Exchange are you on?
Free Windows Admin Tool Kit Click here and download it now
February 3rd, 2015 12:37pm

Hi Jason,

Thanks for coming back again. I believe I am setting the Exchange version to 2010, so I will set it to 2013 when I have the code to hand tomorrow and update you.

Thanks again,

Mike

February 3rd, 2015 3:05pm

Hi Jason,

I have just run again and checked the Exchange version. I am connecting to Office 365 to test, but in the live version I will be connecting to Exchange 2013 SP1. I have re-tested this morning, ensuring the Exchange version in my service is correct as below:

Url                          : https://outlook.office365.com/EWS/Exchange.asmx
ImpersonatedUserId           : Microsoft.Exchange.WebServices.Data.ImpersonatedUserId
ManagementRoles              :
PreferredCulture             :
DateTimePrecision            : Default
FileAttachmentContentHandler :
TimeZone                     : (UTC) Dublin, Edinburgh, Lisbon, London
UnifiedMessaging             : Microsoft.Exchange.WebServices.Data.UnifiedMessaging
EnableScpLookup              : True
TraceEnablePrettyPrinting    : True
CookieContainer              : System.Net.CookieContainer
SendClientLatencies          : True
TraceEnabled                 : False
TraceFlags                   : All
TraceListener                : Microsoft.Exchange.WebServices.Data.EwsTraceListener
Credentials                  : Microsoft.Exchange.WebServices.Data.WebCredentials
UseDefaultCredentials        : False
Timeout                      : 100000
PreAuthenticate              : False
AcceptGzipEncoding           : True
RequestedServerVersion       : Exchange2013_SP1
UserAgent                    : ExchangeServicesClient/15.00.0847.030
ServerInfo                   : 15.01.0065.017
WebProxy                     :
KeepAlive                    : True
ConnectionGroupName          :
ClientRequestId              :
ReturnClientRequestId        : False
HttpHeaders                  : {}
HttpResponseHeaders          : {[Transfer-Encoding, chunked], [Content-Encoding, gzip], [Vary, Accept-Encoding], [request-id,
                               4a70bed1-e965-4ac6-9cb7-b210b2a646ff,4a70bed1-e965-4ac6-9cb7-b210b2a646ff]...}


Still get the same response, I have 3 contacts, 2 in correct format and 1 containing the colon. When I run:

Foreach($contact in $contacts) {$contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1].Address;}

it will only return the 2 contacts without a colon! :-@

Jason, when you get the correct results, is this when using a Contact.Load because I still haven't been able to work that one out...

Thanks,
Mike

Free Windows Admin Tool Kit Click here and download it now
February 4th, 2015 4:56am

Here's my entire script:

$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
$uri = [system.URI] "https://outlook.office365.com/ews/exchange.asmx"
$service.Url = $uri

$service.Credentials = New-Object System.Net.NetworkCredential("user@contoso.com", "password")

$ContactsFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts)

$ivItemView =  New-Object Microsoft.Exchange.WebServices.Data.ItemView(100)      
$psPropset = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)   

$Contacts = $ContactsFolder.FindItems($ivItemView)

[void]$service.LoadPropertiesForItems($Contacts, $psPropset)

ForEach($Contact in $Contacts.Items) {
  Write-Host ($Contact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] | Format-List | Out-String)
}

I used LoadPropertiesForItems since it does it all in one shot. It should be the same as Contact.Load, so I wouldn't worry about that.

February 4th, 2015 10:31am

Hi Jason,

I tested this with EWS API version 2.1 and it was not working, upgraded to 2.2 as yours and this now loads the display name but still not the email address. This is workable though because at least we will have a log of the display name for items that are now blank.

Thanks for all your help, if I make any further progress I will update the thread! 

Thanks,

Mike

Free Windows Admin Tool Kit Click here and download it now
February 5th, 2015 4:04am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics