How would I do this? Any ideas? I just want to make sure my script does not try to create a new mailContact if the ExternalEmailAddress already exists.
If (Test-Path $CSVFileName) {
#Import the CSV file
$csvfile = Import-CSV $CSVFileName
#Loop through CSV file
foreach ($line in $csvfile) {
try {
#Create the mail contact
New-MailContact -domaincontroller $dc -Name $line.Name -ExternalEmailAddress $line.ExternalEmailAddress -OrganizationalUnit $OU -ErrorAction STOP
Set-Contact -domaincontroller $dc -Identity $line.Name -Department $line.Department -Title "Sales Team" -StreetAddress $line.StreetAddress -City $line.City -StateOrProvince $line.StateOrProvince -PostalCode $line.PostalCode -Office $line.Office -CountryOrRegion $line.CountryOrRegion
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
}
I'm not seeing any fundamental issue with your approach. If you are worried about testing it, create a truncated version of the CSV file, to see how the script reacts with some tests accounts or whatnot. You could also make use of the -WhatIf
parameter on the New
& Set
commands to check which objects will be affected, but without making the change.
I have to assume the $OU
variable is defined elsewhere. The only other thing I'd suggest is to use splatting to make it more readable. That might look something like this:
$NewParams = @{
DomainController = $dc
OrganizationalUnit = $OU
ErrorAction = 'Stop'
}
$SetParams = @{
DomainController = $dc
Title = 'Sales Team'
}
If (Test-Path $CSVFileName) {
#Import the CSV file
$csvfile = Import-CSV $CSVFileName
# Adjust splatting hash tables per incoming line:
$NewParams['Name'] = $line.Name
$NewParams['ExternalEmailAddress'] = $line.ExternalEmailAddress
# Adjust splatting hash for the set command:
$SetParams['Identity'] = $line.Name
$SetParams['Department'] = $line.Department
$SetParams['StreetAddress'] = $line.StreetAddress
$SetParams['City'] = $line.City
$SetParams['StateOrProvince'] = $line.StateOrProvince
$SetParams['PostalCode'] = $line.PostalCode
$SetParams['Office'] = $line.Office
$SetParams['CountryOrRegion'] = $line.CountryOrRegion
#Loop through CSV file
foreach ($line in $csvfile) {
try {
#Create the mail contact
New-MailContact @NewParams
Set-Contact @SetParams
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
}
This example sets up 2 hash tables with constant values. Then inside the loop, it will add and/or change the variable parameters in the hashes, per line of input. They simply reference those hashes as the argument to the New-MailContact
& Set-Contact
commands.
The Exchange Management Shell will not let you duplicate an SMTP address. If you attempt to it will return an error like:
The proxy address "SMTP:Example@Example.com" is already being used by the proxy addresses or LegacyExchangeDN of "local.domian/Users/OtheMailEnabledObject". Please choose another proxy address.
However, if you want to prevent errors altogether and/or prevent writing these specific kinds of errors to the log there are a few things you can do.
From a code perspective, the easiest thing to do is to simply add an If block with a Get-Recipient
command.
#...
#Loop through CSV file
foreach ($line in $csvfile) {
If( !(Get-Recipient $line.ExternalEmailAddress) ) {
try {
#Create the mail contact
New-MailContact @NewParams
Set-Contact @SetParams
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
}
Note: Get-Recipient
is more thorough than Get-MailContact
.
Another approach might be to simply handle those specific errors differently.
#...
#Loop through CSV file
foreach ($line in $csvfile) {
try {
#Create the mail contact
New-MailContact @NewParams
Set-Contact @SetParams
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
If( $Error[0].CategoryInfo.Reason -ne 'ProxyAddressExistsException' ){
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
}
So in this case you are only logging when the error isn't a duplicate proxy address. You can of course create additional logic depending on what you want.
If you have a very large number of contacts to create both of these methods might be rather slow. This is because they'd be executing a lot of commands they don't need to. For the latter approach, the performance hit would be related to how many duplicate errors actually occur. For the former, you'd take a hit on each loop iteration because you're always checking regardless of whether the New-MailContact
command will be successful anyway.
So the last approach is to create a list of existing proxy addresses you can check against before trying to create a new contact.
To compile a list of all SMTP proxy addresses:
$ExistingAddresses =
Get-Recipient ResultSize Unlimited |
Select-Object -ExpandProperty EmailAddresses |
Where-Object{$_.PrefixString -eq 'SMTP'} |
Select-Object -ExpandProperty SmtpAddress
However, Get-Recipient
may have problems paging through large sets returned by a large query. Depends on your environment. If you do have a problem you can use an alternate approach using AD cmdlets, which will be much faster in any case.
$ExistingAddresses =
Get-ADObject -Filter "mailnickname -like '*'" -Properties 'ProxyAddresses' |
ForEach-Object{
ForEach($ProxyAddress in $_.ProxyAddresses)
{
If( $ProxyAddress -match "^smtp" ) {
$ProxyAddress.Split(':')[1]
}
}
}
Once you have $ExistingAddresses
populated you can change the loop to check the list first:
foreach ($line in $csvfile) {
If( $line.ExternalEmailAddress -notin $ExistingAddresses ) {
try {
#Create the mail contact
New-MailContact @NewParams
Set-Contact @SetParams
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
}
Again, you can build additional logic if desired. For example, an Else{...}
if you want to report finding a duplicate etc...
Based on additional comments. If you want to run a set command on those contacts that already existed. here's 1 example:
#Loop through CSV file
foreach ($line in $csvfile) {
If( !(Get-Recipient $line.ExternalEmailAddress) ) {
try {
#Create the mail contact
New-MailContact @NewParams
"$($line.Name) was created successfully." | Out-File $logfile -Append
}
catch {
$message = "A problem occured trying to create the $($line.Name) contact"
$message | Out-File $logfile -Append
Write-Warning $message
Write-Warning $_.Exception.Message
$_.Exception.Message | Out-File $logfile -Append
}
}
# The contact either already exists or was just created, so long as you
# Use the same domain controller go ahead and perform the Set...
Set-Contact @SetParams
}
Again, there are a thousand ways to arrange something like this. And, all of the above approaches can probably be modified to satisfy the new requirement. However, this will not tell you which properties get updated. If you want that kind of property level comparison, we'd have to write still more code.