-
Notifications
You must be signed in to change notification settings - Fork 95
/
Import-MailboxContacts.ps1
289 lines (261 loc) · 14.5 KB
/
Import-MailboxContacts.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# http://www.stevieg.org/2010/07/using-powershell-to-import-contacts-into-exchange-and-outlook-live/
# https://www.reddit.com/r/PowerShell/comments/tyfmuf/getmailboxcontacts_and_importmailboxcontacts
# Import-MailboxContacts -CSVFileName C:\temp\contacts.csv -EmailAddress [email protected] -Impersonate $true -Username [email protected] -Password <pass>
# NOTE: not tested with admin account that requires MFA
# your csv must have headers as defined in left column of $ContactMapping
function Import-MailboxContacts {
param (
[string]$CSVFileName,
[string]$EmailAddress,
[string]$Username,
[string]$Password,
[string]$Domain,
[bool]$Impersonate,
[string]$EwsUrl,
[string]$EWSManagedApiDLLFilePath,
[bool]$Exchange2007,
[switch]$Exchange2010
)
#
# Import-MailboxContacts.ps1
#
# By Steve Goodman, Use at your own risk.
#
# Parameters
# Mandatory:
# -CSVFileName : Filename of the CSV file to import contacts for this user from. Same format as Outlook Export.
# -EmailAddress : Account SMTP email address. Required, but only used when impersonating or with Autodiscover - otherwise uses the user you login as
# Optional:
# -Impersonate : Set to $true to use impersonation.
# -Username : The username to use. If this isn't specified (along with Password), attempts to use the logged on user.
# -Password : Used with above
# -Domain : Used with above - optional.
# -EwsUrl : The URL for EWS if you don't want to use Autodiscover. Typically https://casserver/EWS/Exchange.asmx
# -EWSManagedApiDLLFilePath : (Optional) Overwrite the filename and path to the DLL for EWS Managed API. By default, uses the default install location.
# -Exchange2007 : Set to $true to use the Exchange 2007 SP1+ version of the Managed API.
#
# Contact Mapping - this maps the attributes in the CSV file (left) to the attributes EWS uses.
# NB: If you change these, please note "First Name" is specified at line 102 as a required attribute and
# "First Name" and "Last Name" are hard coded at lines 187-197 when constructing NickName and FileAs.
$ContactMapping = @{
'First Name' = 'GivenName'
'Middle Name' = 'MiddleName'
'Last Name' = 'Surname'
'Company' = 'CompanyName'
'Department' = 'Department'
'Job Title' = 'JobTitle'
'Business Street' = 'Address:Business:Street'
'Business City' = 'Address:Business:City'
'Business State' = 'Address:Business:State'
'Business Postal Code' = 'Address:Business:PostalCode'
'Business Country/Region' = 'Address:Business:CountryOrRegion'
'Home Street' = 'Address:Home:Street'
'Home City' = 'Address:Home:City'
'Home State' = 'Address:Home:State'
'Home Postal Code' = 'Other:Home:PostalCode'
'Home Country/Region' = 'Address:Home:CountryOrRegion'
'Other Street' = 'Address:Other:Street'
'Other City' = 'Address:Other:City'
'Other State' = 'Address:Other:State'
'Other Postal Code' = 'Address:Other:PostalCode'
'Other Country/Region' = 'Address:Other:CountryOrRegion'
"Assistant's Phone" = 'Phone:AssistantPhone'
'Business Fax' = 'Phone:BusinessFax'
'Business Phone' = 'Phone:BusinessPhone'
'Business Phone 2' = 'Phone:BusinessPhone2'
'Callback' = 'Phone:CallBack'
'Car Phone' = 'Phone:CarPhone'
'Company Main Phone' = 'Phone:CompanyMainPhone'
'Home Fax' = 'Phone:HomeFax'
'Home Phone' = 'Phone:HomePhone'
'Home Phone 2' = 'Phone:HomePhone2'
'ISDN' = 'Phone:ISDN'
'Mobile Phone' = 'Phone:MobilePhone'
'Other Fax' = 'Phone:OtherFax'
'Other Phone' = 'Phone:OtherTelephone'
'Pager' = 'Phone:Pager'
'Primary Phone' = 'Phone:PrimaryPhone'
'Radio Phone' = 'Phone:RadioPhone'
'TTY/TDD Phone' = 'Phone:TtyTddPhone'
'Telex' = 'Phone:Telex'
'Anniversary' = 'WeddingAnniversary'
'Birthday' = 'Birthday'
'E-mail Address' = 'Email:EmailAddress1'
'E-mail 2 Address' = 'Email:EmailAddress2'
'E-mail 3 Address' = 'Email:EmailAddress3'
'Initials' = 'Initials'
'Office Location' = 'OfficeLocation'
"Manager's Name" = 'Manager'
'Mileage' = 'Mileage'
'Notes' = 'Body'
'Profession' = 'Profession'
'Spouse' = 'SpouseName'
'Web Page' = 'BusinessHomePage'
'Contact Picture File' = 'Method:SetContactPicture'
}
# CSV File Checks
# Check filename is specified
if (!$CSVFileName) {
THROW 'Parameter CSVFileName must be specified'
}
# Check file exists
if (!(Get-Item -Path $CSVFileName -ErrorAction SilentlyContinue)) {
THROW 'Please provide a valid filename for parameter CSVFileName'
}
# Check file has required fields and check if is a single row, or multiple rows
$SingleItem = $false
$CSVFile = Import-Csv -Path $CSVFileName
if ($CSVFile.'First Name') {
$SingleItem = $true
} else {
if (!$CSVFile[0].'First Name') {
Throw "File $($CSVFileName) must specify at least the field 'First Name'"
}
}
# Check email address
if (!$EmailAddress) {
Throw 'Parameter EmailAddress must be specified'
}
if (!$EmailAddress.Contains('@')) {
Throw 'Parameter EmailAddress does not appear valid'
}
# Check EWS Managed API available
if (!$EWSManagedApiDLLFilePath) {
#$EWSManagedApiDLLFilePath = 'C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll'
$EWSManagedApiDLLFilePath = 'C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll'
}
if (!(Get-Item -Path $EWSManagedApiDLLFilePath -ErrorAction SilentlyContinue)) {
Throw "EWS Managed API not found at $($EWSManagedApiDLLFilePath). Download from https://github.com/gangstanthony/PowerShell/raw/master/EWSManagedAPI2.2.msi"
}
# Load EWS Managed API
#[void][Reflection.Assembly]::LoadFile('C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll')
[void][Reflection.Assembly]::LoadFile($EWSManagedApiDLLFilePath)
# Create Service Object
if ($Exchange2007) {
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
} elseif ($Exchange2010) {
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010)
} else {
#$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
}
# Set credentials if specified, or use logged on user.
if ($Username -and $Password) {
if ($Domain) {
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($Username,$Password,$Domain)
} else {
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($Username,$Password)
}
} else {
$service.UseDefaultCredentials = $true
}
# Set EWS URL if specified, or use autodiscover if no URL specified.
if ($EwsUrl) {
$service.URL = New-Object Uri($EwsUrl)
} else {
$EwsUrl = 'https://outlook.office365.com/ews/exchange.asmx'
try {
#$service.AutodiscoverUrl($EmailAddress)
$service.URL = New-Object Uri($EwsUrl)
} catch {
Throw
}
}
# Perform a test - try and get the default, well known contacts folder.
if ($Impersonate) {
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress)
}
try {
$ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts)
} catch {
Throw
}
# Add contacts
foreach ($ContactItem in $CSVFile) {
# If impersonate is specified, do so.
if ($Impersonate) {
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $EmailAddress)
}
$ExchangeContact = New-Object Microsoft.Exchange.WebServices.Data.Contact($service)
if ($ContactItem.'First Name' -and $ContactItem.'Last Name') {
$ExchangeContact.NickName = $ContactItem.'First Name' + ' ' + $ContactItem.'Last Name'
} elseif ($ContactItem.'First Name' -and !$ContactItem.'Last Name') {
$ExchangeContact.NickName = $ContactItem.'First Name'
} elseif (!$ContactItem.'First Name' -and $ContactItem.'Last Name') {
$ExchangeContact.NickName = $ContactItem.'Last Name'
}
$ExchangeContact.DisplayName = $ExchangeContact.NickName
$ExchangeContact.FileAs = $ExchangeContact.NickName
$BusinessPhysicalAddressEntry = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
$HomePhysicalAddressEntry = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
$OtherPhysicalAddressEntry = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
# This uses the Contact Mapping above to save coding each and every field, one by one. Instead we look for a mapping and perform an action on
# what maps across. As some methods need more "code" a fake multi-dimensional array (seperated by :'s) is used where needed.
foreach ($Key IN $ContactMapping.Keys) {
# Only do something if the key exists
if ($ContactItem.$Key) {
# Will this call a more complicated mapping?
if ($ContactMapping[$Key] -like '*:*') {
# Make an array using the : to split items.
$MappingArray = $ContactMapping[$Key].Split(':')
# Do action
switch ($MappingArray[0]) {
'Email' {
$ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::($MappingArray[1])] = $ContactItem.$Key
}
'Phone' {
$ExchangeContact.PhoneNumbers[[Microsoft.Exchange.WebServices.Data.PhoneNumberKey]::($MappingArray[1])] = $ContactItem.$Key
}
'Address' {
switch ($MappingArray[1]) {
'Business' {
$BusinessPhysicalAddressEntry.($MappingArray[2]) = $ContactItem.$Key
$ExchangeContact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::($MappingArray[1])] = $BusinessPhysicalAddressEntry
}
'Home' {
$HomePhysicalAddressEntry.($MappingArray[2]) = $ContactItem.$Key
$ExchangeContact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::($MappingArray[1])] = $HomePhysicalAddressEntry
}
'Other' {
$OtherPhysicalAddressEntry.($MappingArray[2]) = $ContactItem.$Key
$ExchangeContact.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::($MappingArray[1])] = $OtherPhysicalAddressEntry
}
}
}
'Method' {
switch ($MappingArray[1]) {
'SetContactPicture' {
if (!$Exchange2007) {
if (!(Get-Item -Path $ContactItem.$Key -ErrorAction SilentlyContinue)) {
Throw "Contact Picture File not found at $($ContactItem.$Key)"
}
$ExchangeContact.SetContactPicture($ContactItem.$Key);
}
}
}
}
}
} else {
# It's a direct mapping - simple!
if ($ContactMapping[$Key] -eq 'Birthday' -or $ContactMapping[$Key] -eq 'WeddingAnniversary') {
if ($ContactItem.$Key -ne '0/0/00') {
[System.DateTime]$ContactItem.$Key = Get-Date($ContactItem.$Key)
}
}
if ($ContactItem.$Key -ne '0/0/00') {
$ExchangeContact.($ContactMapping[$Key]) = $ContactItem.$Key
}
}
}
}
# Save the contact
$ExchangeContact.Save()
# Provide output that can be used on the pipeline
$Output_Object = New-Object Object
$Output_Object | Add-Member NoteProperty FileAs $ExchangeContact.FileAs
$Output_Object | Add-Member NoteProperty GivenName $ExchangeContact.GivenName
$Output_Object | Add-Member NoteProperty Surname $ExchangeContact.Surname
$Output_Object | Add-Member NoteProperty EmailAddress1 $ExchangeContact.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1]
$Output_Object
}
}