<# | |
This script syncs SendAs permissions from Exchange on-Prem to Exchange Online to avoid a misconfigured hybrid environment | |
Uses Azure Automation for scheduling and safely storing the on-Prem credentials as well as the authentication certificate for Exchange Online | |
Prerequisites | |
* Azure Automation Account | |
* Hybrid Worker | |
* Setup App-only authentication (https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2) | |
* Install private certificate as exportable to Azure Automation Account as 'Exchange Hybrid Automation' | |
* Store OnPrem Exchange credentials in Azure Automation Account as 'Exchange onPrem' | |
#> | |
[CmdletBinding()] | |
param ( | |
# Change to your App Id | |
[Parameter(Mandatory = $false)] | |
[string] | |
$AppID = "3d907615-5f82-41da-9d8a-e3c3713497b5", | |
# Change to your tenant name | |
[Parameter(Mandatory = $false)] | |
[string] | |
$Organization = "bader.onmicrosoft.com", | |
# Change to your on Prem Exchange server | |
[Parameter(Mandatory = $false)] | |
[string] | |
$ExchangeServer = "exchangeserver.onprem.cloudbrothers.info" | |
) | |
# Basic settings | |
$ConfirmPreference = "None" | |
$ErrorActionPreference = "Stop" | |
# Retrieve private certificate and onPrem credentials | |
$EXOCertificate = Get-AutomationCertificate -Name 'Exchange Hybrid Automation' | |
$OnPremCred = Get-AutomationPSCredential -Name 'Exchange onPrem' | |
# Get a list of all On-Prem Shared Mailboxen (msExchRecipientTypeDetails = 4) which where modified in the last two days | |
$NewSharedMaiboxes = Get-ADUser -LDAPFilter "(msExchRecipientTypeDetails:1.2.840.113556.1.4.803:=4)" -Properties whenChanged, EmailAddress | Where-Object { $_.whenChanged -ge (Get-Date).AddDays(-2) } | |
if ( -not $NewSharedMaiboxes) { | |
Write-Output "[SHAREDMBX]`t Found no new shared mailboxes..." | |
} else { | |
#region Export PFX certificate | |
# Generate password | |
$Password = [System.Web.Security.Membership]::GeneratePassword(25, 5) | |
# Export certificate as pfx file | |
try { | |
# Define temporary file | |
$CertificatePath = Join-Path $env:temp "Exchange Hybrid Automation.pfx" | |
Write-Output "[PFXCERTIFICATE]`t Certificate is exported to: $CertificatePath" | |
# Export PFX to variable | |
$PFXCertificate = $EXOCertificate.Export("pfx", $Password) | |
# Write content of pfx cert to file | |
Set-Content -Value $PFXCertificate -Path $CertificatePath -Force -Encoding Byte | |
Write-Output "[PFXCERTIFICATE]`t Certificate exported successfully" | |
} catch { | |
throw "Could not export certificate - ($($_.Exception.Message))" | |
} | |
#endregion | |
#region Connect to Exchange on-Prem | |
try { | |
Write-Output "[EXOnPrem]`t Connecting to Exchange On-Prem ($ExchangeServer)..." | |
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$($ExchangeServer)/powershell" -Credential $OnPremCred | |
Write-Output "[EXOnPrem]`t Connection established, import module..." | |
# Import module while using the prefix OnPremExchange to distinguish between onPrem and Online | |
Import-Module ( Import-PSSession -Session $session -AllowClobber -DisableNameChecking -Prefix OnPremExchange ) -Global | |
# Thanks to Joshua Bines who posted the way of importing the module here: | |
# https://www.undocumented-features.com/2019/01/31/getting-around-the-basics-of-azure-automation-for-office-365/#comment-1934 | |
Write-Output "[EXOnPrem]`t Module successfully imported" | |
} catch { | |
throw "Exchange On-Prem connection could no be established - ($($_.Exception.Message))" | |
} | |
#endregion | |
#region Verbindung zu Exchange Online herstellen | |
try { | |
Write-Output "[EXO]`t Connecting to Exchange Online..." | |
Connect-ExchangeOnline -LogLevel All -LogDirectoryPath C:\Service\exolog -CertificateFilePath $CertificatePath -CertificatePassword (ConvertTo-SecureString -String $Password -AsPlainText -Force) -AppID $AppID -Organization $Organization | |
Write-Output "[EXO]`t Connection established and module successfully imported" | |
} catch { | |
throw "Exchange Online connection could no be established - ($($_.Exception.Message))" | |
} | |
#endregion | |
#region Synchronize permissions | |
foreach ($User in $NewSharedMaiboxes) { | |
# Get on-Prem mailbox for the AD User | |
$Mailbox = Get-OnPremExchangeMailbox $User.EmailAddress | |
# Retrieve every Send-As permission | |
# Exclude SELF and Deny | |
$SendAsPermissions = $Mailbox | Get-OnPremExchangeADPermission | Where-Object { $_.IsInherited -eq $false -and $_.ExtendedRights -match "Send-As" -and $_.Deny -eq $false -and "$($_.User)" -ne "NT AUTHORITY\SELF" } | |
# Loop through every entry and set the permission in Exchange Online | |
$SendAsPermissions | ForEach-Object { | |
try { | |
Write-Output "[$($User.UserPrincipalName)]`t Add recipient permission for $($_.User)" | |
Add-RecipientPermission -Identity $User.UserPrincipalName -Trustee $_.User -AccessRights SendAs -Confirm:$false | Out-Null | |
} catch { | |
Write-Error "[$($User.UserPrincipalName)]`t Permissions could not be added - ($($_.Exception.Message))" | |
} | |
} | |
} | |
#endregion | |
# Close connections | |
Disconnect-ExchangeOnline -Confirm:$false | |
$session | Remove-PSSession -ErrorAction SilentlyContinue -WhatIf:$false | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment