Solved

Sync Exchange 2007 GAL to Exchange Public Folder

Posted on 2013-01-21
49
1,124 Views
Last Modified: 2013-03-01
Hello,

I have an Exchange 2007 Server with a Global Address List (GAL) and a Public Folder called "Public Global Address List".  I need to find a solution (preferably via scripting that I can automate via Tast Scheduler) that will allow me to sync the GAL to the Public Folder I mentioned.

There are many reasons for doing this.  Here are two reasons:

1) The GAL is very limited in the views that can be shown.  For example, we want to have the list grouped by Department.
2) We have custom fields we want to view that we can see when it's in a Public Folder.

The sync need only go one way (from the GAL to the Public Folder), and should be able to update/add/delete the entries in the Public Folder from the GAL.  Another way to accomplish this would be to delete all the entries in the Public Folder and then simply export out all of the GAL entries each time it is synched.

Thank you for your time and attention to this.

Best regards,

--Roger
0
Comment
Question by:RavenRB
  • 25
  • 24
49 Comments
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38805417
I don't know if this will work with PFs, but it might be worth a try. Not really syncing, though. More like copying, so you'd have to go with the 'delete all entries' method.

http://support.microsoft.com/kb/238773
0
 

Author Comment

by:RavenRB
ID: 38806081
Thank you, LeeDerbyshire.  I have already viewed this solution, and it doesn't meet the criteria of my request.  I need a way to automatically export the GAL in to a Public Folder that resides on the Exchange 2007 Server.

I've also found several commercial programs that will do this, but I'm wondering if there is a script that I can use to export the GAL in to a target that is a Public Folder (of contacts).  If I can find an example of this, or even someone to point me in the right direction on how to build my own, I will be very grateful.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38806201
No, I only included after reading your last sentence 'Another way to accomplish this would be to delete all the entries in the Public Folder and then simply export out all of the GAL entries each time it is synched.' I thought the procedure described in the link might fit that description. I haven't seen a script that will do it, because what you see in the GAL are AD user records, and that's quite different to a Contact item in a Public Folder. It might be possible to script it, but it might just be easier to buy something if you've already seen something. How much does what you've already seen cost?
0
 

Author Comment

by:RavenRB
ID: 38806470
Thank you, LeeDerbyshire.  The cost of the products I've seen start at $1000 and go up from there.  Rather pricey for a copy/paste/sync (albeit automated) solution.  I'm willing to pay it if necessary, but it seems like something a glorified batch file/script (I'm old school) should be able to do.  I'm holding out hope that someone here has a solution, that while not wrapped in an elegant installer with GUI packaging, will solve the problem just as effectively.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38806721
Sounds like a product opportunity :) I'll see if I can come up with something, but I'll be a few days, at least.
0
 

Author Comment

by:RavenRB
ID: 38820552
I was pinged by the site to update this request, so I'm shamelessly bumping.  :)
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38826618
No prob, but the more I think about it, the more difficulties I imagine. It should be easy enough to copy GAL entries into a PF. Once. But then there will be a problem of making sure that things don't get duplicated, and also to make sure that entries that get removed in the GAL will be removed from the PF. Not impossible, but it does mean that you have to also read the public folder, fairly regularly, to make sure that it no longer contains something that's not in the GAL. I'm just trying to think of the best way of doing all this.
0
 
LVL 31

Accepted Solution

by:
LeeDerbyshire earned 500 total points
ID: 38827318
Okay, here's the first attempt. It works here, but I have E2010, so you may end up needing to change a few things. You'll need to install the Exchange Web Services managed API (it only adds a small DLL to the server, but it would be very hard to do this without it). Note that you'll need to change the \Folder1\Folder2 bit to reflect the name of your own folder, which will need to be a Contact folder. Right now, it will only copy GAL to PF, and does not check for existing entries (so if you do it twice, you will get duplicates). Save it as a .ps1 file (say, GalSync.ps1) in the root of the Exchange server's c drive. Open powershell, and do

cd\
.\GalSync.ps1

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue
Add-Type -Path "C:\EWSManagedAPI\Microsoft.Exchange.WebServices.dll"
$folderPath = "\Folder1\Folder2"
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService("Exchange2007_SP1")
$ews.Url = "https://localhost/EWS/Exchange.asmx"
$rootFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::PublicFoldersRoot)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ews, $rootFolderId)
$arrPath = $folderPath.Split("\")
for ($i = 1; $i -lt $arrPath.length; $i++)
{
  $folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
  $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, $arrPath[$i])
  $findFolderResults = $ews.FindFolders($folder.Id, $searchFilter, $folderView)
  if ($findFolderResults.TotalCount -gt 0)
  {
    $folder = $findFolderResults.Folders[0]
  }
  else
  {
    "$folderPath Not Found"
    exit
  }
}

Get-Recipient | foreach {
  $_.DisplayName
  $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
  $item.DisplayName = $_.DisplayName
  $item.FileAs = $_.DisplayName
  $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
  $item.Save($folder.Id)
}

Open in new window

0
 

Author Comment

by:RavenRB
ID: 38833592
Thank you!  I'll try this tomorrow at work.  :)
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38834843
Okay. BTW, it also assumes that the Managed API gets installed in C:\EWSManagedAPI\ . I can't remember if that's a default location, or one that I chose. But you may need to change that bit of the script.
0
 

Author Comment

by:RavenRB
ID: 38853193
Thank you.  I'm trying to modify this script to allow for the automatic deletion of all contents of the Public Folder prior to the import.  Do you know of an easy way to modify this script to allow for this?
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38854784
Sure, there is the EWS Folder.Empty method. I'll add it to the script when I get a few minutes, or you can try adding it yourself, if you know how.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38855078
Oops, you have E2007, so Folder.Empty isn't available for you. I'll have to do it 'the hard way'.
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38855718
Okay, insert this before the line that begins with Get-Recipient. It assumes that there aren't more than 10000 contacts in the folder.

$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$findItemResults = $ews.FindItems($folder.Id, $itemView)
$findItemResults | foreach {
  $_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
0
 

Author Comment

by:RavenRB
ID: 38857293
Thank you, LeeDerbyshire.  I'll try this and report back.
0
 

Author Comment

by:RavenRB
ID: 38866623
Hello LeeDerbyshire.  Here's what I have found, thus far:

We've been able to copy the contacts from the GAL to the Public Folder.  However, we'd like more information to copy than what is currently copying.  We'd really like to have Department, Phone #, etc. also copy over.

We've modified the script such that it ignores SSL validation errors because we are using a self-signed certificate.

Here's a copy of the script as it currently stands:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly

## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll


$folderPath = "\HFG Global Contact List Test"
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService("Exchange2007_SP1")
$ews.Url = "https://localhost/EWS/Exchange.asmx"
$rootFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::PublicFoldersRoot)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ews, $rootFolderId)
$arrPath = $folderPath.Split("\")
for ($i = 1; $i -lt $arrPath.length; $i++)
{
  $folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
  $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, $arrPath[$i])
  $findFolderResults = $ews.FindFolders($folder.Id, $searchFilter, $folderView)
  if ($findFolderResults.TotalCount -gt 0)
  {
    $folder = $findFolderResults.Folders[0]
  }
  else
  {
    "$folderPath Not Found"
    exit
  }
}

$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$findItemResults = $ews.FindItems($folder.Id, $itemView)
$findItemResults | foreach {
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
Get-Recipient | foreach {
  $_.DisplayName
  $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
  $item.DisplayName = $_.DisplayName
  $item.FileAs = $_.DisplayName
  $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
  *******$item.Department = $_.Department
  $item.Save($folder.Id)
}

Open in new window


The line with the ******* (line 65) in front of it is one we tried adding but it's failing.  Do you have a list (or can you point me to a list) of valid pipeline fields that I can pick and choose from?

Thank you so very much - I feel we're very close.

--Roger
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38867778
What is the error message? That department line works fine here, and the department value is being correctly set on the contact item in the PF.
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38868012
0
 

Author Comment

by:RavenRB
ID: 38868628
This is the error we're receiving regarding the "department" field:

The term '$._Department' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.
At C:\GalSync.ps1:65 char:35
+   $item.Department = $._Department <<<<
    + CategoryInfo          : ObjectNotFound: ($._Department:String) [], Comma
   ndNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38868837
It should be $_.Department (which is what you have in the code you pasted earlier), not $._Department .
0
 

Author Comment

by:RavenRB
ID: 38870024
LeeDerbyshire,

Thank you so very much for your help.  You've been wonderful.

I think this is my final question: How do we get the "manager" field to come over?  Here's the code, as it sits right now:

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly

## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll


$folderPath = "\HFG Global Contact List Test"
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService("Exchange2007_SP1")
$ews.Url = "https://localhost/EWS/Exchange.asmx"
$rootFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::PublicFoldersRoot)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ews, $rootFolderId)
$arrPath = $folderPath.Split("\")
for ($i = 1; $i -lt $arrPath.length; $i++)
{
  $folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
  $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, $arrPath[$i])
  $findFolderResults = $ews.FindFolders($folder.Id, $searchFilter, $folderView)
  if ($findFolderResults.TotalCount -gt 0)
  {
    $folder = $findFolderResults.Folders[0]
  }
  else
  {
    "$folderPath Not Found"
    exit
  }
}

$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$findItemResults = $ews.FindItems($folder.Id, $itemView)
$findItemResults | foreach {
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
Get-Recipient | foreach {
  $_.DisplayName
  $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
  $item.DisplayName = $_.DisplayName
  $item.FileAs = $_.DisplayName
  $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
  $item.Department = $_.Department
  $item.JobTitle = $_.Title
  $item.Manager = $_.Manager
  $item.PhoneNumbers[2] = $_.Phone
  $item.Save($folder.Id)
}

Open in new window


We have our manager field populated in the GAL but it's returning nothing/blank.
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38870286
If I try
  $item.Manager = $_.Manager
here, I actually get something like this:
  domain/users/firstname lastname
so I tried
  $item.Manager = $_.Manager.Name
which just gives me the display name.
0
 

Author Comment

by:RavenRB
ID: 38881117
Thanks, LeeDerbyshire.

We're not getting anything when we try assigning from either $_.Manager or $_.Manager.Name.  It's always returning a blank value (without any errors, also).  We clearly have data in the Manager, Name field when looking at the Orginization Tab from within Active Directory (using Active Directory Users and Computers).

We are able to get data from the Job Title, Department and Company fields that are on the same Tab, though.

TestUser in Active Directory
0
 

Author Comment

by:RavenRB
ID: 38881194
Please ignore my last - I think I've got it figured out.  I'll report back in a bit.
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 

Author Comment

by:RavenRB
ID: 38881953
Hi again, LeeDerbyshire :)

I'm stuck at the Physical Address portion.  Here's the relevant snippet of the code:

Get-Recipient | foreach {
  $_.DisplayName
  IF ($_.Department -ne "")
    {
    $itemaddress = $ews.PhysicalAddressEntry
    $itemaddress.PostalCode = $_.PostalCode
    $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
    $item.DisplayName = $_.DisplayName
    $item.CompanyName = $_.Company
    $item.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Business] = $itemaddress
    $item.FileAs = $_.DisplayName
    $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
    $item.Department = $_.Department
    $item.JobTitle = $_.Title
    $item.Manager = $_.Manager.Name
    $item.PhoneNumbers[2] = $_.Phone
    $item.Save($folder.Id)
    }
    ELSE
      {
        "Skipped due to blank Department"
      }
}

Open in new window


I'm receiving errors from this line:

$itemaddress.PostalCode

It doesn't like the PostalCode property - and I'm having no luck finding out how to reference what should be the underlying fields City, CountryOrRegion, PostalCode, State or Street.

Here's the error:

Property 'PostalCode' cannot be found on this object; make sure it exists and i
s settable.
At C:\GalSync.ps1:64 char:18
+     $itemaddress. <<<< PostalCode = $_.PostalCode
    + CategoryInfo          : InvalidOperation: (PostalCode:String) [], Runtim
   eException
    + FullyQualifiedErrorId : PropertyNotFound

Any help would be greatly appreciated.  I think this is the last bit of information I need to gleen from the AD.

Thanks very much in advance.
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38882099
Instead of

$itemaddress = $ews.PhysicalAddressEntry

try

$itemaddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
0
 

Author Comment

by:RavenRB
ID: 38882127
Thanks.  That's working (I actually figured that out with lots more research!) and I'm able to assign all but the actual Street Address.  Here's the code:

Get-Recipient | foreach {
  $_.DisplayName
  IF ($_.Department -ne "")
    {
    $itemaddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
    $_.PhysicalAddress1
    $_.BusinessAddress1
    $_.Street1
    $_.StreetAddress1
    $_.StreetAddress
    $itemaddress.Street = $_.StreetAddress
    $itemaddress.City = $_.City
    $itemaddress.State = $_.StateOrProvince
    $itemaddress.PostalCode = $_.PostalCode
    $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
    $item.DisplayName = $_.DisplayName
    $item.GivenName = $_.FirstName
    $item.SurName = $_.LastName
    $item.CompanyName = $_.Company
    $item.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Business] = $itemaddress
    $item.FileAs = $_.DisplayName
    $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
    $item.Department = $_.Department
    $item.JobTitle = $_.Title
    $item.Manager = $_.Manager.Name
    $item.PhoneNumbers[2] = $_.Phone
    $item.Save($folder.Id)
    }
    ELSE
      {
        "Skipped due to blank Department"
      }
}

Open in new window


These lines, below, are me just trying to desperately get something to output that contains the actual physical street address:

    $_.PhysicalAddress1
    $_.BusinessAddress1
    $_.Street1
    $_.StreetAddress1
    $_.StreetAddress

Open in new window

0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38882434
Hm. Get-Recipient doesn't supply the street address, although it does show the rest (city, state, etc.). So, we have to assign it to a variable (because we'll need to use Get-User within the loop), and foreach the variable instead. Here's what I have so far, but now it's bedtime :)

$recipients = Get-Recipient
$recipients | foreach {
  $_.DisplayName
  $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
  $item.DisplayName = $_.DisplayName
  $item.FileAs = $_.DisplayName
  $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
  $item.Department = $_.Department
  $item.Manager = $_.Manager.Name
  $itemaddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
  if($_.RecipientType -eq "UserMailbox")
  {
    $x = get-user $_.Alias
    $itemaddress.Street = $x.StreetAddress
  }
  $itemaddress.City = $_.City
  $itemaddress.State = $_.StateOrProvince
  $itemaddress.CountryOrRegion = $_.CountryOrRegion
  $itemaddress.PostalCode = $_.PostalCode

  $item.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Business] = $itemaddress

  $item.Save($folder.Id)
}

Open in new window

0
 

Author Comment

by:RavenRB
ID: 38886958
Ha!  You did it again... that worked, LeeDirbyshire.  Thanks!

It seems I have just a cosmetic piece to clear up before this is ready for prime time.

Namely, the contacts that get created by this import process shows as Untitled when I double-click on them:

TestUserPublicFolderContact
How do I get it to now show up as "untitled", but actually show the Display Name as the contact card's title?
0
 

Author Comment

by:RavenRB
ID: 38887010
One other question: How do I show if a GAL account is disabled?  I don't want to import disabled accounts.  Thank you.
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38888758
For the 'untitled' bit. Add a line like this:

$item.Subject = $_.DisplayName

For the disabled thing, there is a little addition I made a few days ago that makes it exclude users that are hidden from the address list. It's possible that this will make it exclude the disabled accounts, too. But I'm not sure.

instead of

$recipients = Get-Recipient

try

$recipients = Get-Recipient | Where {$_.HiddenFromAddressListsEnabled -eq $false}
0
 

Author Comment

by:RavenRB
ID: 38889847
OK, that worked very well.  Thank you, again!

I mean no offense, but I have a couple of more questions.

How do I set the "Default Mailing Address" field?  I've tried several things but they don't work.

I've tried:

$item.MailingAddress = $itemaddress

Open in new window

and

$item.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::MailingAddress] = $itemaddress

Open in new window

and

$item.SelectedMailingAddress = 2

Open in new window


Also, how do I set the Display As under the e-mail address?

I've been looking here but haven't been able to figure out how to set more than just the e-mail address, per the code we already have in place:

$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()

Open in new window

I think it has something to do with this: EmailAddress(String, String)

Many thanks for all your help, LeeDirbyshire.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38889984
I'm not sure where the Default Mailing Address field is shown. I don't see it in Outlook anywhere. Where do you see it?

The Display As name should come from here:

  $item.DisplayName = $_.DisplayName

but I see from the image above that yours is showing an email address instead. Can you post again the complete code that you now have, so that I can try it here?
0
 

Author Comment

by:RavenRB
ID: 38890096
When double-clicking on a contact record from the Public Folder, you can see the This is the Mailing Address check box.  I want that checked for the Business Address.  Please see the screenshot, below:

Contact RecordHere's the code as it stands right now:
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue
Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

$TASource=@'
  namespace Local.ToolkitExtensions.Net.CertificatePolicy{
    public class TrustAll : System.Net.ICertificatePolicy {
      public TrustAll() { 
      }
      public bool CheckValidationResult(System.Net.ServicePoint sp,
        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
        System.Net.WebRequest req, int problem) {
        return true;
      }
    }
  }
'@ 
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly

## We now create an instance of the TrustAll and attach it to the ServicePointManager
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll

$folderPath = "\HFG Global Contact List Test"
$ews = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService("Exchange2007_SP1")
$ews.Url = "https://localhost/EWS/Exchange.asmx"
$rootFolderId = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::PublicFoldersRoot)
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($ews, $rootFolderId)
$arrPath = $folderPath.Split("\")
for ($i = 1; $i -lt $arrPath.length; $i++)
{
  $folderView = New-Object Microsoft.Exchange.WebServices.Data.FolderView(1)
  $searchFilter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName, $arrPath[$i])
  $findFolderResults = $ews.FindFolders($folder.Id, $searchFilter, $folderView)
  if ($findFolderResults.TotalCount -gt 0)
  {
    $folder = $findFolderResults.Folders[0]
  }
  else
  {
    "$folderPath Not Found"
    exit
  }
}

$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(10000)
$findItemResults = $ews.FindItems($folder.Id, $itemView)
$findItemResults | foreach {
$_.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
}
Get-Recipient | Where {$_.HiddenFromAddressListsEnabled -eq $false} | foreach {
  $_.DisplayName + " " + $_.FirstName + " " + $_.LastName
  IF ($_.Department -ne "")
    {
    $item = New-Object Microsoft.Exchange.WebServices.Data.Contact($ews)
    $item.DisplayName = $_.DisplayName
    $item.FileAs = $_.DisplayName
    $item.Subject = $_.DisplayName
    #$item.FileAsMapping = "DisplayName"
    $item.GivenName = $_.FirstName
    $item.SurName = $_.LastName
    $item.CompanyName = $_.Company
    $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
    #$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::Email1DisplayName] = $_.DisplayName
    $item.Department = $_.Department
    $item.JobTitle = $_.Title
    $item.Manager = $_.Manager.Name
    $item.OfficeLocation = $_.Office
    $item.PhoneNumbers[2] = $_.Phone
    $itemaddress = New-Object Microsoft.Exchange.WebServices.Data.PhysicalAddressEntry
    if($_.RecipientType -eq "UserMailbox")
      {
        $x = get-user $_.Alias
        $itemaddress.Street = $x.StreetAddress
      }
    $itemaddress.City = $_.City
    $itemaddress.State = $_.StateOrProvince
    $itemaddress.CountryOrRegion = $_.CountryOrRegion
    $itemaddress.PostalCode = $_.PostalCode
    $item.PhysicalAddresses[[Microsoft.Exchange.WebServices.Data.PhysicalAddressKey]::Business] = $itemaddress
    #$item.MailingAddress = $itemaddress
    
    $item.Save($folder.Id)
    }
    ELSE
      {
        "Skipped due to blank Department"
      }
}

Open in new window

0
 

Author Comment

by:RavenRB
ID: 38890204
I tried this, too:

    $EmailEntry = new-object Microsoft.Exchange.WebServices.Data.EmailAddress ($_.DisplayName, $_.PrimarySMTPAddress.ToString())
    $EmailEntry.Address = $_.PrimarySMTPAddress.ToString()
    $EmailEntry.Name = $_.DisplayName
    #$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()
    $item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $EmailEntry

Open in new window

It sets the e-mail address but NOT the Display As...

Grrrr.  :)
0
 

Author Comment

by:RavenRB
ID: 38890546
Another question:  One of the items I'm importing from the GAL is a Distribution List.  It's being imported as a "Contact".  How do I import it as a Distribution List with it's associated members?

Thanks very much, LeeDirbyshire.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38890669
WHen I try your full script in post ID: 38890096, it correctly sets the display name. I don't know why it should be different. Unless it's because I have E2010, and it somehow makes the adjustment.

For the Distribution Lists, well, I'll have a look, but I think that will take some time.
0
 

Author Comment

by:RavenRB
ID: 38890737
Thank you. I'm not sure if this post was overlooked or not as you didn't mention it:

When double-clicking on a contact record from the Public Folder, you can see the This is the Mailing Address check box.  I want that checked for the Business Address.

Thank you.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38890874
I didn't really forget it, but I'm only really able to work on one thing at a time. Otherwise I get a bit confused :)  This check box thing isn't not something I have a quick answer for.
0
 

Author Comment

by:RavenRB
ID: 38890937
I completely understand. Once I get done travelling I'm going to see if I can continue to assist. Thank you again for your help and willingness to do so.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38891127
No prob, I'm enjoying it. One thing you might try is to set the email address before the display name. Or, try updating the display name after it has been saved to the folder.

Or, try using an email address in the format:

"Firstname Surname" <firstname.surname@yourdomain.com>

(there ought to be a space between the two parts).
0
 

Author Comment

by:RavenRB
ID: 38891637
I used the format "Firstname Surname" <firstname.surname@yourdomain.com> and it now displays just the First and Last name fields in the Display As field (under the e-mail address field) on the Contact Card.  This is good enough.  The actual code I used was:
$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.DisplayName + " <" + $_.PrimarySMTPAddress.ToString() + ">"

Open in new window


I tried setting the Display Name after the e-mail address was assigned and that is just the "Full Name" field on the Contact card - it doesn't have anything to do with the E-mail Address field.

I think the open questions that I still need help with are:

1) When double-clicking on a contact record from the Public Folder, you can see the This is the Mailing Address check box.  I want that checked for the Business Address.

2) One of the items I'm importing from the GAL is a Distribution List.  It's being imported as a "Contact".  How do I import it as a Distribution List with it's associated members?
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38893729
Having tested a few contacts here, I'd suggest doing this

$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = """" + $_.DisplayName + """" + " <" + $_.PrimarySMTPAddress.ToString() + ">"

without the extra quotes, Outlook seems to sometimes fails to resolve the name when you right-click the contact, and try to send an email.

I still haven't found a way to set the mailing address, but I'm still looking. And it looks like creating Distribution Lists can't be done in EWS, so I'm not too hopeful about that. Since it gets saved as a contact with an email address, you can still, in theory, send email to the group. But you can't see the members.
0
 

Author Comment

by:RavenRB
ID: 38894675
Thanks.  I made the change adding the extra quotes. :)
0
 
LVL 31

Assisted Solution

by:LeeDerbyshire
LeeDerbyshire earned 500 total points
ID: 38901703
Well, I've made a bit more progress. I found that you can change the Email1DisplayName by assigning a value after it's been saved. So after
 
$item.Save($folder.Id)

Open in new window


do this
 
$GUID = New-Object Guid("00062004-0000-0000-C000-000000000046")
$ePD = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition($GUID, 32896, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$item.SetExtendedProperty($ePD, $_.DisplayName)
$item.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)

Open in new window


if it works for you too, then it means you can go back to

$item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1] = $_.PrimarySMTPAddress.ToString()

Open in new window


for the email address, instead of adding the display name in quotes, and using the angled brackets around the address

For setting the mailing address, I found this

$item.PostalAddressIndex = [Microsoft.Exchange.WebServices.Data.PhysicalAddressIndex]::Business

Open in new window


still struggling with the distribution lists, though.
0
 

Author Comment

by:RavenRB
ID: 38915311
Hello LeeDirbyshire,

I made the changes you suggested to my script, and it's working fine.  Thank you!

Any luck with the Distribution List?  If not, that's OK - I'm extremely happy with where things stand, now.  The Distribution List is icing on the cake, so to speak.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38915346
Well, I found out how do add a distribution list to the public folder. I just don't know how to add members to it yet. There don't seem to be many people doing it out there.
0
 

Author Closing Comment

by:RavenRB
ID: 38939300
LeeDerbyshire was awesome - very helpful and very patient.  I really appreciated his excellent and persistent work ethic in helping me with this solution.
0
 
LVL 31

Expert Comment

by:LeeDerbyshire
ID: 38941846
I'm going to give up for now on reproducing the GAL distribution lists in the public folder. It seems that a DL in a mailbox or public folder is completely different to one in the GAL, and so are the actual entries within them, even though they look the same from the client end. I'm not confident that even if I succeeded, that what I would have created was an accurate copy of what was in the GAL, so I think it's best to just create a contact record that points to the real DL in the GAL.

But I enjoyed it anyway :)
0

Featured Post

Don't lose your head updating email signatures!

Do your end users still have the wrong email signature? Do email signature updates bore you or fill you with a sense of dread? You can make this a whole lot easier on yourself by trusting an Exclaimer email signature management solution. Over 50 million users do...so should you!

Join & Write a Comment

Easy CSR creation in Exchange 2007,2010 and 2013
This article explains in simple steps how to renew expiring Exchange Server Internal Transport Certificate.
In this video we show how to create an Accepted Domain in Exchange 2013. We show this process by using the Exchange Admin Center. Log into Exchange Admin Center.: First we need to log into the Exchange Admin Center. Navigate to the Mail Flow >> Ac…
In this Micro Video tutorial you will learn the basics about Database Availability Groups and How to configure one using a live Exchange Server Environment. The video tutorial explains the basics of the Exchange server Database Availability grou…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now