Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
363 lines (254 sloc) 12.6 KB
function Connect-Exchange {
<#
.Synopsis
Connect-Exchange (a.k.a. conex)
.Description
Connect to Exchange or Exchange Online PowerShell (requires EXO PS module
for EXO). Run with no parameters to see helpful usage tips.
.Parameter UserPrincipalName
[Optional/Recommended] Helps to keep sessions alive by allowing the refresh
and access tokens to update automatically. Implies EXO.
.Parameter Credential
[Optional] Credentials for on-premises Exchange / EXO.
.Parameter ExchangeFqdn
[Optional] FQDN for on-premises Exchange (server).
.Parameter CommandName
[Optional] Pass-through parameter for Import-PSSession. Refer to:
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-pssession
.Example
Connect-Exchange [Enter]
PS C:\>conex [Enter]
.Example
$creds = Get-Credential
PS C:\>$server = exsrv25.jb365.ca
PS C:\>conex -Credential $creds -ExchangeFqdn $server -CommandName *mailbox*
.Example
conex -CommandName Set-M*, Get-Transp*, *database*
.Example
conex -UserPrincipalName exoadmin@jb365.ca
PS C:\>conex exoadmin@jb365.ca # <--: -UserPrincipalName is in position 0
.Link
https://github.com/JeremyTBradshaw/PowerShell/blob/master/.functions/Connect-Exchange.ps1
#>
#Requires -Version 3
[CmdletBinding(DefaultParameterSetName = 'EXO')]
param (
[Parameter(ParameterSetName = 'EXO', ValueFromRemainingArguments = $true)]
[string]$UserPrincipalName = '',
[Parameter(ParameterSetName = 'ExOnP')]
[string]$ExchangeFqdn,
[Parameter(ParameterSetName = 'EXO')]
[Parameter(ParameterSetName = 'ExOnP')]
[System.Management.Automation.PSCredential]$Credential,
[Parameter(ParameterSetName = 'EXO')]
[Parameter(ParameterSetName = 'ExOnP')]
[ValidatePattern('(^[a-zA-Z*]{0,12})([*-]{0,1})([a-zA-Z*]{1,50}$)')]
[string[]]$CommandName = "*"
)
$DetectedSession = Get-PSSession |
Where-Object {$_.ConfigurationName -eq 'Microsoft.Exchange'}
if ($DetectedSession) {
$SessionDetectedMenu = [System.Management.Automation.Host.ChoiceDescription[]] @(
'&Abort',
'&End current session',
'&New PowerShell window'
)
$SessionDetectedChoice = $host.UI.PromptForChoice(
"Existing Exchange PowerShell session detected.`n",
$null,
$SessionDetectedMenu, 0
)
switch ($SessionDetectedChoice) {
0 {$break = $true}
1 {
$DetectedSession | Remove-PSSession
Get-Module tmp_* | Remove-Module
Remove-Module Microsoft.Exchange.Management.ExoPowershellModule -ErrorAction:SilentlyContinue
Remove-Module CreateExoPSSession -ErrorAction:SilentlyContinue
}
2 {
Invoke-Item $PSHOME\powershell.exe
$break = $true
}
}
if ($break) {break}
}
if (-not ($PSBoundParameters.ContainsKey('UserPrincipalName')) -and
-not ($PSBoundParameters.ContainsKey('ExchangeFqdn'))
) {
$ConexBanner = " _________________________________`n`n" +
" Connect-Exchange (a.k.a. conex) `n" +
" _________________________________`n"
$ConexTipCaption = " Random Tip:`n"
$ConexTips = @()
$ConexTips += " - Tired of MFA/credential re-prompts? Specify -UserPrincipalName to enable seamless and silent AAD token refreshes.`n`n" +
" e.g. PS C:\> conex -UserPrincipalName ExAdmin@contoso.com`n" +
" PS C:\> conex ExAdmin@contoso.com`n`n" +
" * Implies connecting to Exchange Online.`n" +
" * Requires EXO PS module to be installed (aka.ms/exopspreview).`n" +
" * Recommended when logging in with the current user.`n" +
" * Recommended for logging in with a different user when:`n" +
" - AAD Connect Seamless SSO is not enabled, or...`n" +
' - Intranet automatic-logon is not enabled (i.e. Internet Options).'
$ConexTips += " - Use -Credential for Exchange on-premises or EXO (if not MFA-enabled).`n`n" +
" e.g. PS C:\> Connect-Exchange -Credential $myAdminCreds`n" +
' e.g. PS C:\> Connect-Exchange $myAdminCreds -ExchangeFqdn mail.contoso.com'
$ConexTips += " - Use -ExchangeFqdn for Exchange on-premises.`n`n" +
' e.g. PS C:\> Connect-Exchange -ExchangeFqdn mail.contoso.com -Credential $myAdminCreds'
$ConexTips += " - Try -CommandName to download only the commands you plan on using.`n`n" +
' e.g. PS C:\> Connect-Exchange -CommandName *et-*Mailbox, Get-MessageTrackingLog'
$ConexTips += " - Call Connect-Exchange by its preferred name:`n`n" +
" New-Alias -Name conex -Value Connect-Exchange`n`n" +
' * This is already done and ready for you if you''re using the conex module.'
$ConexTips += " - Let this menu and its prompt sequences do some of the heavy lifting for you:`n`n" +
" PS C:\> conex [Enter]`n" +
' PS C:\> Connect-Exchange [Enter]'
$ConexTips += " - Need assistance? Try:`n`n" +
" Get-Help Connect-Exchange`n" +
" Get-Help Connect-Exchange -Examples | -Detailed | -Full | -Online`n" +
" Connect-Exchange -?`n" +
' conex -?'
$ExchangeConnectionMenuOptions = [System.Management.Automation.Host.ChoiceDescription[]] @(
'&Abort',
'&Exchange Online',
'Enter Exchange server &FQDN'
)
Write-Host -Object $ConexBanner -ForegroundColor Green
Write-Host -Object $ConexTipCaption -ForegroundColor DarkGray
Write-Host -Object (Get-Random $ConexTips) -ForegroundColor DarkGray
$ExchangeConnectionChoice = $host.UI.PromptForChoice(
" Where to connect?`n`n",
$null,
$ExchangeConnectionMenuOptions, 0
)
}
elseif ($PSBoundParameters.ContainsKey('UserPrincipalName')) {$ExchangeConnectionChoice = 1}
else {$ExchangeConnectionChoice = 2}
$ImportPSSessionProps = @{
AllowClobber = $true
DisableNameChecking = $true
CommandName = $CommandName
FormatTypeName = @($CommandName -replace '.*-','*')
ErrorAction = 'Stop'
}
switch ($ExchangeConnectionChoice) {
1 {
try {
$ExoPSModuleSearchProperties = @{
Path = "$($env:LOCALAPPDATA)\Apps\2.0\"
Filter = 'Microsoft.Exchange.Management.ExoPowerShellModule.dll'
Recurse = $true
ErrorAction = 'Stop'
}
$ExoPSModule = Get-ChildItem @ExoPSModuleSearchProperties |
Where-Object {$_.FullName -notmatch '_none_'} |
Sort-Object LastWriteTime |
Select-Object -Last 1
Import-Module $ExoPSModule.FullName -ErrorAction:Stop
$ExoPSModuleManifest = $ExoPSModule.FullName -replace '\.dll','.psd1'
$NewExoPSModuleManifestProps = @{
Path = $ExoPSModuleManifest
RootModule = $ExoPSModule.Name
ModuleVersion = "$((Get-Module $ExoPSModule.FullName -ListAvailable).Version.ToString())"
Author = 'Jeremy Bradshaw (https://github.com/JeremyTBradshaw)'
CompanyName = 'jb365'
}
New-ModuleManifest @NewExoPSModuleManifestProps
Import-Module $ExoPSModule.FullName -Global -ErrorAction:Stop
$CreateExoPSSessionPs1 = Get-ChildItem -Path $ExoPSModule.PSParentPath -Filter 'CreateExoPSSession.ps1'
$CreateExoPSSessionManifest = $CreateExoPSSessionPs1.FullName -replace '\.ps1','.psd1'
$CreateExoPSSessionPs1 = $CreateExoPSSessionPs1 |
Get-Content |
Where-Object {-not ($_ -like 'Write-Host*')}
$CreateExoPSSessionPs1 -join "`n" |
Set-Content -Path "$($CreateExoPSSessionManifest -replace '\.psd1','.psm1')"
$NewCreateExoPSSessionManifest = @{
Path = $CreateExoPSSessionManifest
RootModule = Split-Path -Path ($CreateExoPSSessionManifest -replace '\.psd1','.psm1') -Leaf
ModuleVersion = '1.0'
Author = 'Jeremy Bradshaw (https://github.com/JeremyTBradshaw)'
CompanyName = 'jb365'
}
New-ModuleManifest @NewCreateExoPSSessionManifest
Import-Module "$($ExoPSModule.PSParentPath)\CreateExoPSSession.psm1" -Global -ErrorAction:Stop
}
catch {
Write-Warning -Message "Tried but failed to import the EXO PS module.`n`nError message:"
throw $_
}
try {
$global:UserPrincipalName = $UserPrincipalName
$global:ConnectionUri = 'https://outlook.office365.com/PowerShell-LiveId'
$global:AzureADAuthorizationEndpointUri = 'https://login.windows.net/common'
$global:PSSessionOption = New-PSSessionOption -CancelTimeout 5000 -IdleTimeout 43200000
$global:BypassMailboxAnchoring = $false
$ExoPSSession = @{
UserPrincipalName = $global:UserPrincipalName
ConnectionUri = $global:ConnectionUri
AzureADAuthorizationEndpointUri = $global:AzureADAuthorizationEndpointUri
PSSessionOption = $global:PSSessionOption
BypassMailboxAnchoring = $global:BypassMailboxAnchoring
}
if ($PSBoundParameters.Credential) {$ExoPSSession['Credential'] = $Credential}
$ExoPSSession = New-ExoPSSession @ExoPSSession -ErrorAction:Stop
Import-Module (Import-PSSession $ExoPSSession @ImportPSSessionProps) -Global -DisableNameChecking -ErrorAction:Stop
UpdateImplicitRemotingHandler
}
catch {
Write-Warning -Message "Failed to connect to EXO via the imported EXO PS module.`n`nError message:"
throw $_
}
}
2 {
if (-not $ExchangeFqdn) {$ExchangeFqdn = Read-Host -Prompt "`nExchange PowerShell FQDN (e.g. mail.contoso.com)"}
$AuthenticationMenuOptions = [System.Management.Automation.Host.ChoiceDescription[]] @(
'&Basic (HTTPS)',
'&Default (HTTP/S)'
)
$AuthenticationChoice = $host.UI.PromptForChoice(
'Authentication method?',
"`n",
$AuthenticationMenuOptions, 0
)
switch ($AuthenticationChoice) {
0 {
$Authentication = 'Basic'
$Protocol = 'https'
}
1 {
$Authentication = 'Default'
$ProtocolMenu = [System.Management.Automation.Host.ChoiceDescription[]] @(
'HTT&P',
'HTTP&S'
)
$ProtocolChoice = $host.UI.PromptForChoice(
'Protocol?',
'Options:',
$ProtocolMenu, 0
)
switch ($ProtocolChoice) {
0 {$Protocol = 'http'}
1 {$Protocol = 'https'}
}
}
}
if (-not $PSBoundParameters.Credential) {$Credential = Get-Credential -Message 'Exchange On-Premises Credentials'}
$ExchPSSessionProps = @{
Credential = $Credential
ConfigurationName = 'Microsoft.Exchange'
AllowRedirection = $true
ConnectionUri = "$($Protocol)://$($ExchangeFqdn)/powershell"
Authentication = $Authentication
}
try {
$ExchPSSession = New-PSSession @ExchPSSessionProps -ErrorAction:Stop
Import-Module (Import-PSSession $ExchPSSession @ImportPSSessionProps) -Global -DisableNameChecking -ErrorAction:Stop
}
catch {
Write-Warning -Message "Failed to connect to $($Protocol)://$($ExchangeFqdn)/powershell with credentials for username $($Credential.UserName).`n`nError message:"
throw $_
}
}
} # end switch ($ExchangeConnectionChoice)
} # end function Connect-Exchange
New-Alias -Name conex -Value Connect-Exchange
You can’t perform that action at this time.