This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
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