New-SharedMailboxV5.ps1
Function New-SharedMailbox { <#PSScriptInfo .DESCRIPTION Create a shared mailbox in a hybrid exchange environment. .VERSION 1.0 .GUID 5456f964-3a57-4dd2-9a55-fd9649e1c69d .AUTHOR Alex Curley #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String] $Alias, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String] $DisplayName, [parameter(mandatory=$false)] [system.string[]] $Users, [System.Management.Automation.CredentialAttribute()] $o365AdminCredential, [System.Management.Automation.CredentialAttribute()] $ADAdminCredential )# param end begin { #Functions #Connect Exchange Online Function Connect-ExchangeOnline ($o365AdminCredential) { $EOSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri 'https://outlook.office365.com/powershell-liveid/?proxymethod=rps' -Credential $o365AdminCredentials -Authentication Basic -AllowRedirection Write-Host -ForegroundColor Magenta "Attempting to connect to Exchange Online" -NoNewline try { Import-PSSession $EOSession -AllowClobber -DisableNameChecking | Out-Null Write-Host -ForegroundColor Cyan ' OK' } catch { Write-Host -ForegroundColor Red 'Could not connect to Exchange. Exiting.' Write-Host '' Write-Error -Message "$_" -ErrorAction Stop return; } } #Connect Exchange On Premise Function Connect-ExchangeOnprem ($Server, $ADAdminCredential) { Write-Host -ForegroundColor Magenta "Attempting to connect to Exchange On Premise." -NoNewline $so = New-PSSessionOption -SkipCACheck:$true -SkipCNCheck:$true -SkipRevocationCheck:$true $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$server/powershell/" -Credential $ADAdminCredential -SessionOption $so try { Import-PSSession $Session -AllowClobber -DisableNameChecking | Out-Null Write-Host -ForegroundColor Cyan " OK" } catch { Write-Host -ForegroundColor Red 'Could not connect to Exchange. Exiting.' Write-Host '' Write-Error -Message "$_" -ErrorAction Stop return; } } #Replicate Active Directory Function Replicate-AD ([string[]]$Controllers,$ADAdminCredential) { Write-Host -ForegroundColor Magenta "Replicating Active Directory." -NoNewline foreach ($controller in $Controllers) { $controller $x=0 start-sleep -Seconds 3 while ($x -lt 3) { $x = $x+1 # write-host -ForegroundColor red $x Invoke-Command -ComputerName $controller -Credential $ADAdminCredential -ScriptBlock { cmd /c "repadmin /syncall /AdeP" } start-sleep -Seconds 1 } } Write-Host -ForegroundColor Cyan ' OK' } #Sync Azure AD Function Sync-AD ($Server,$ADAdminCredential) { Write-Host -ForegroundColor Magenta "Performing Delta AADSync." -NoNewLine Invoke-Command -ComputerName $Server -Credential $ADAdminCredential -ScriptBlock { Start-ADSyncSyncCycle -PolicyType Delta } Write-Host -ForegroundColor Cyan ' OK' } #Connect to MsolService Function Connect-Msol { Write-Host -ForegroundColor Magenta 'Attempting to connecto to MsolService.' -NoNewline try { Connect-MsolService -Credential $o365adminCredentials -ErrorAction Stop Write-Host -ForegroundColor Cyan ' OK' } catch { Write-Host -ForegroundColor Red 'Could not connect to MsolService. Exiting.' Write-Error -Message "$_" -ErrorAction Stop return; } } #Modules #Variables $domain = 'usip' [regex]$rgx = "'.+'.couldn't.be.found.on" $transcript = 'C:\temp\Transcript.txt' $upn_smtp = "$alias@$domain.org" $proxy = "$alias@$domain.mail.onmicrosoft.com" $target = $proxy.Split('@')[1] $DC = 'hq-dc01' $controllers = 'hq-dc01','hq-dc5' $ExchangeServer = 'msx13hybrid' $ExchangeFQDN = 'msxbridge.usip.org' $AADServer = 'hq-aadsync' $OU = 'ou=stand alone email accounts,ou=exchange,dc=usip,dc=local' #Confirm $users exist in AD if ($Users){ Write-Host -ForegroundColor Magenta "Checking if users exist in AD" foreach ($user in $users){ try{ get-aduser -Identity $user | out-null Write-Host -ForegroundColor Cyan "Found" -NoNewLine Write-Host -ForegroundColor White " $User" } catch { Write-Host -ForegroundColor Red "Could not find $user. Exiting" Write-Host '' Write-Error -Message $_ -ErrorAction Stop return; } } } } process { Write-Host '' #Create user mailbox onprem, then add mail.onmicrosoft.com proxy address for migration Connect-ExchangeOnprem -Server $ExchangeServer -ADAdminCredential $ADAdminCredential Write-Host -ForegroundColor Magenta "Creating mailbox." -NoNewline try { $Global:ErrorActionPreference = 'Stop' New-Mailbox -Password (ConvertTo-SecureString -AsPlainText 'USIP@1984' -Force) -DisplayName $displayname -Name $displayName -Alias $alias -SamAccountName $alias -UserPrincipalName $upn_smtp -PrimarySmtpAddress $upn_smtp -OrganizationalUnit $OU -DomainController $DC -Confirm:$false -ErrorAction Stop | Out-Null Write-Host -ForegroundColor Cyan " OK" } catch { Write-Host -ForegroundColor Red "Failed to create mailbox. Exiting." Write-Host '' write-error -Message $_ -ErrorAction Stop return; } Write-Host -ForegroundColor Magenta "Adding proxy address for migration." #Give exchange and DC little time to catch up with itself Start-Sleep -Seconds 5 #Add the proxy address user@DOMAIN.mail.onmicrosoft.com try { Set-Mailbox -Identity $Alias -EmailAddresses @{add="$proxy"} -DomainController $DC -ErrorAction 'Stop' | Out-Null Write-Host -ForegroundColor Cyan "Added " -NoNewline Write-Host -ForegroundColor White $proxy -NoNewline Write-Host -ForegroundColor Cyan " as a proxy address." } catch { Write-Host -ForegroundColor Red "Failed to add SMTP proxy address. Cannot migrate without it. Exiting" Write-Host '' Write-Error -Message $_ return; } #Close connection to Exchange on premise Get-PSSession | Remove-PSSession #Replicate Active Directory and Sync to Azure Write-Host '' Replicate-AD -Controllers $controllers -ADAdminCredential $ADAdminCredential | out-null Sync-AD -Server $AADServer -ADAdminCredential $ADAdminCredential | out-null Write-Host -ForegroundColor Magenta "Sleeping 30s." -NoNewline Start-Sleep -Seconds 30 Write-Host -ForegroundColor Cyan ' OK' Write-Host '' #Connect to MsolService and wait for user to sync Connect-Msol Write-Host -ForegroundColor Magenta 'Waiting for Get-MsolUser to return something...' -NoNewline do { Get-MsolUser -UserPrincipalName $upn_smtp -ErrorAction SilentlyContinue | Out-Null } while (!(Get-MsolUser -UserPrincipalName $upn_smtp -ErrorAction SilentlyContinue)) Write-Host -ForegroundColor Cyan ' OK' #Connect to Exchange Online, wait for mailbox to become available, and migrate #I didn't know how to test whether or not the mailbox was available to migrate, so I used transcript and regex. #Start-transcript will not include the successful whatif below, which I would prefer to match. Apparently it's a bug, so i'm matching the most common error (can't find mailbox) Connect-ExchangeOnline Write-Host '' Write-Host -ForegroundColor Magenta 'Waiting for New-MoveRequest -WhatIf to stop returning errors.' do { $ErrorActionPreference = 'Continue' $Global:ErrorActionPreference = 'Continue' Start-Transcript -LiteralPath $transcript | out-null New-MoveRequest -BatchName $Alias -Identity $Alias -Remote -RemoteHostName $ExchangeFQDN -TargetDeliveryDomain $target -RemoteCredential $ADAdminCredential -BadItemLimit 0 -LargeItemLimit 0 -WhatIf Stop-Transcript | out-null Start-Sleep -Seconds 20 } while ((gc $transcript) -match $rgx) Write-Host -ForegroundColor Cyan ' OK' #Migrate Write-Host -ForegroundColor Magenta 'Starting migration.' -NoNewline New-MoveRequest -BatchName $Alias -Identity $Alias -Remote -RemoteHostName $ExchangeFQDN -TargetDeliveryDomain $target -RemoteCredential $ADAdminCredential -BadItemLimit 0 -LargeItemLimit 0 | Out-Null Write-Host -ForegroundColor Cyan ' OK' Write-Host -ForegroundColor Magenta 'Waiting for the status below to show "Completed"' #Wait for migration to complete do { Get-MoveRequest | ? alias -eq $Alias | % { '{0,1} {1,20}' -f $_.batchname,$_.status } start-sleep -Seconds 20 } while ((Get-MoveRequest | ? alias -eq $Alias).Status -ne 'Completed') Get-MoveRequest | ? alias -eq $Alias | Format-Table batchname,status #Set mailbox to shared, enable messagecopyforsendas, set ad attributes for hybrid shared mbox, and disable ad user Write-Host '' Write-Host -ForegroundColor Cyan 'Setting mailbox type to' -NoNewline Write-Host " Shared" -NoNewline Write-Host -ForegroundColor Magenta "and enabling" -NoNewline Write-Host ' MessageCopyForSendOnBehalfEnabled.' try { $Global:ErrorActionPreference = 'Stop' Set-Mailbox -Identity $upn_smtp -Type Shared -MessageCopyForSendOnBehalfEnabled $true | Out-Null Write-Host -ForegroundColor Cyan " OK" } catch { Write-Host -ForegroundColor Red "Failed to set mailbox. Exiting." Write-Host '' write-error -Message $_ -ErrorAction Stop return; } #Set AD attributes Write-Host -ForegroundColor Magenta "Setting msExchRemoteRecipientType to" -NoNewline Write-Host " 100" Write-Host -ForegroundColor Magenta "Setting msExchRecipientTypeDetails to" -NoNewline Write-Host " 34359738368." try { Set-ADUser $Alias -Replace @{msExchRemoteRecipientType=100; msExchRecipientTypeDetails=34359738368} -Server $DC -Credential $ADAdminCredential | Out-Null Write-Host -ForegroundColor Cyan ' OK' } catch { Write-Host -ForegroundColor Red "Failed to set AD attributes. Exiting." Write-Host '' write-error -Message $_ -ErrorAction Stop return; } #Disable AD object Write-Host -ForegroundColor Magenta 'Setting AD Object to' -NoNewline Write-Host ' Disabled' try { Disable-ADAccount -Identity $Alias -Server $DC -Credential $ADAdminCredential | Out-Null Write-Host -ForegroundColor Cyan 'OK' } catch { Write-Host -ForegroundColor Red "Failed to disable object. Exiting." Write-Host '' write-error -Message $_ -ErrorAction Stop return; } #Add FullAccess and SendAs permissions #Try/Catch doesn't work well with PS remoting if ($Users){ foreach ($User in $Users){ Write-Host -ForegroundColor Magenta 'Assigning' -NoNewLine Write-Host -ForegroundColor White " $user" -NoNewline Write-Host -ForegroundColor Magenta 'FullAccess and SendAs rights on' -NoNewline Write-Host -ForegroundColor White " $Alias" -NoNewline Add-MailboxPermission -Identity $upn_smtp -AccessRights FullAccess -User $user -Confirm:$false | Out-Null Add-RecipientPermission -Identity $upn_smtp -AccessRights SendAs -Trustee $user -Confirm:$false | Out-Null Write-Host ' OK' } } } end { $trustees = $users -join ', ' $mailbox = Get-Mailbox -Identity $Alias | select primarysmtpaddress,name,recipienttypedetails $permiss = Get-MailboxPermission -Identity $Alias | Where-Object {$_.user -in $Users} | select user,accessrights $sendas = Get-RecipientPermission -Identity $Alias | Where-Object {$_.Trustee -in $Users} | select trustee,accessrights Write-Host "Shared mailbox $Alias created and configured" Write-Host "Email address: $($mailbox.primarysmtpaddress)" Write-Host "Displayname: $($mailbox.Name)" Write-Host "$trustees have full access to $Alias and the ability to send as that address" Get-PSSession | Remove-PSSession #output text to put in ticket resolution: Email address, display name, access rights, sendonbehalf, type } } |