Forum Discussion
Share address book from one to other tenants in O365
- Jan 29, 2019With that said, feel free to vote on the uservoice for sharing GAL between tenants! Quite a big one!
https://office365.uservoice.com/forums/273493-office-365-admin/suggestions/10087845-gal-federation-between-different-o365-tenants
Regards / Adam
Bernd_SchneiderI have a similar issue that I'm dealing with and would appreciate if you could share a detailed insight on the script used and steps taken.
Sunil50 Hi, that's the script.
It could be optimized, but it works:
# Publish O365 Users as Contacts in another tenant
# BSSE GmbH, Bernd Schneider
#
# Note:
# The text โ (Source-Tenant)โ is appended to every contact to mark the contacts
# of the source company.
# Use at own risk!
# Connect Source-Tenant
Write-Output "Connect Source-Tenant"
$credObject = Get-AutomationPSCredential -Name "Source-Tenant-Admin"
Connect-MsolService -Credential $credObject
# Get Source-Tenant Users Excluding Guest Accounts
Write-Output "Read Source-Tenant MSOLUser"
$mySourceUsers=Get-MSOLUser -all|Where-Object {($_.UserPrincipalName -LIKE "*@Source-Tenant.*") -AND (-NOT ($_.UserPrincipalName -LIKE ("*#EXT#*"))) }
Get-PSSession | Remove-PSSession
# Create AzureRunAsConnection
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
Write-Output "Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch
{
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
# Connect Target-Tenant
Write-Output "Connect Target-Tenant"
$credObject = Get-AutomationPSCredential -Name "Target-Tenant-Admin"
Connect-MsolService -Credential $credObject
# Function: Update-ExchangeOnlineContact
function Update-ExchangeOnlineContact {
param (
$User
)
$NameAndOrg=$User.DisplayName+" (Source-Tenant)"
Set-Mailcontact $User.UserPrincipalName -Name $NameAndOrg -DisplayName $NameAndOrg -FirstName $User.FirstName -LastName $User.Lastname `
-CustomAttribute9 "BSSE Office 365 Synchronisation"
}
# Function: Update-ExchangeOnlineContactEmail
function Update-ExchangeOnlineContactEmail {
param (
$User
)
$NameAndOrg=$User.DisplayName+" (Source-Tenant)"
Get-MailContact -resultsize 99999|where-object {$User.DisplayName -eq $NameAndOrg}| ยด
Set-Mailcontact -ExternalEmailAddress $User.UserPrincipalName -CustomAttribute9 "BSSE Office 365 Synchronisation"
}
# Function: New-ExchangeOnlineContact
function New-ExchangeOnlineContact {
param (
$User
)
$NameAndOrg=$User.DisplayName+" (Source-Tenant)"
New-Mailcontact -Name $NameAndOrg -DisplayName $NameAndOrg -FirstName $User.FirstName -LastName $User.LastName `
-ExternalEmailAddress $User.UserPrincipalName
Set-Mailcontact -Identity $User.UserPrincipalName -CustomAttribute9 "BSSE Office 365 Synchronisation"
}
# Function: Connect to Exchange Online
function Connect-ExchangeOnline {
param (
$Creds
)
Write-Output "Connecting to Exchange Online"
Get-PSSession | Remove-PSSession
$Session = New-PSSession โConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $Creds -Authentication Basic -AllowRedirection
$Commands = @("Get-Recipient","New-Mailcontact","Set-Mailcontact","Set-Mailbox","Get-Mailbox","Get-Contact","Get-MailContact", "Remove-Mailcontact", "Get-MailUser")
Import-PSSession -Session $Session -DisableNameChecking:$true -AllowClobber:$true -CommandName $Commands | Out-Null
}
# Connect to Exchange Online
Write-Output "Connect Target-Tenant Exchange"
Connect-ExchangeOnline -Creds $credObject
# Load Data in Buffer
$SourceDisplay=Get-MailContact -resultsize 99999|where-object {$_.DisplayName -like "*(Source-Tenant)"}
$SourceContacts=Get-MailContact -resultsize 99999|where-object {$_.PrimarySMTPAddress -like "*Source-Tenant.*"}
$SourceExternal=Get-MailUser -resultsize 99999|where-object {$_.PrimarySMTPAddress -like "*Source-Tenant.*" -and $_.RecipientTypeDetails -eq "GuestMailUser"}
# Check if new Account using Email address
ForEach($User in $MySourceUsers) {
$TempContact = $SourceContacts|where {$SourceContacts.PrimarySMTPAddress -eq ($User.UserPrincipalName)}
if ($TempContact) {
Write-Output ("Existing Contact: "+$User.DisplayName)
# Check for Update using time last changed
if ($User.Value.WhenModified.addday -gt (get-date).adddays(-2)) {
Write-Output ("Update Contact: "+$User.DisplayName)
Update-ExchangeOnlineContact -User $User
}
}
else {
$TempContact = $SourceExternal|where {$SourceExternal.PrimarySMTPAddress -like $User.UserPrincipalName}
# Check if external contact, if yes, ignore
if ($TempContact) {
Write-Output ("External Contact: "+$User.UserPrincipalName)
}
else {
$TempDisplay = $SourceDisplay|where {$SourceDisplay.DisplayName -eq ($User.DisplayName + " (Source-Tenant)")}
# Check, if same Displayname exists
if ($TempDisplay) {
# Change Email-Address
Write-Output ("New Email Address: "+$User.DisplayName+", "+$User.UserPrincipalName)
Update-ExchangeOnlineContactEmail -User $User
}
else {
# Create new Contact
Write-Output ("New Contact: "+$User.DisplayName)
New-ExchangeOnlineContact -User $User
}
}
}
}
$MySourceUsers|ft UserPrincipalName, DisplayName
# Check Account deletion
ForEach($Contact in $SourceContacts) {
$TempUser = $MySourceUsers|where {($MySourceUsers.UserPrincipalName) -like $Contact.PrimarySMTPAddress}
if ($TempUser) {
Write-Output ("Do not delete: "+$Contact.identity)
}
else {
Write-Warning ("Delete Contact: "+$Contact.identity)
Write-Output ($Contact.PrimarySMTPAddress)
$contact|Remove-MailContact -confirm:$false
}
}
# Close Session
Get-PSSession | Remove-PSSession
Write-Output "Script Completed!"
- Bernd_SchneiderJul 20, 2020Copper ContributorI'seen that pasting the script looses some of the hash characters.
Hope you see whit is comment. ๐ - Bernd_SchneiderJul 20, 2020Copper ContributorRemark:
You can also use that method with on premise Exchange, but then you have to split the script. One runs with a local agent in your domain, saving the results in a global variable, the other one picks up the content of the variable and runs in azure.