Workloads/ExchangeOnline.ps1
function Connect-MSCloudLoginExchangeOnline { [CmdletBinding()] param( [Parameter()] [switch] $SkipPSSessionEvaluation ) $InformationPreference = 'SilentlyContinue' $ProgressPreference = 'SilentlyContinue' $source = 'Connect-MSCloudLoginExchangeOnline' Add-MSCloudLoginAssistantEvent -Message 'Trying to get the Get-AcceptedDomain command from within MSCloudLoginAssistant' -Source $source if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad.Count -eq 0) { $loadAllCmdlets = $true } Add-MSCloudLoginAssistantEvent "Current loaded module: $($Script:MSCloudLoginCurrentLoadedModule)" -Source $source if ($Script:MSCloudLoginCurrentLoadedModule -eq 'EXO') { try { Get-AcceptedDomain -ErrorAction Stop if (-not $loadAllCmdlets) { Add-MSCloudLoginAssistantEvent 'Checking for missing commands' -Source $source Add-MSCloudLoginAssistantEvent "Cmdlets to load: $($Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad -join ',')" -Source $source Add-MSCloudLoginAssistantEvent "Loaded Cmdlets: $($Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedCmdlets -join ',')" -Source $source $missingCommands = $Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad | Where-Object -FilterScript { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedCmdlets -notcontains $_ } Add-MSCloudLoginAssistantEvent "Missing commands: $($missingCommands -join ',')" -Source $source } # $missingCommands is null if no missing commands are found Add-MSCloudLoginAssistantEvent "Loaded all cmdlets: $($Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedAllCmdlets)" -Source $source if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedAllCmdlets -or (-not $loadAllCmdlets -and $null -eq $missingCommands)) { Add-MSCloudLoginAssistantEvent -Message 'Succeeded' -Source $source $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true return } } catch { Add-MSCloudLoginAssistantEvent -Message 'Failed' -Source $source } } try { Add-MSCloudLoginAssistantEvent "Current domain: $($(Get-AcceptedDomain).Name)" -ErrorAction Continue -Source $source } catch { Add-MSCloudLoginAssistantEvent -Message 'Failed to load Get-AcceptedDomain' -Source $source -EntryType 'Error' } if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected -and ` $Script:MSCloudLoginConnectionProfile.ExchangeOnline.SkipModuleReload) { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true return } Add-MSCloudLoginAssistantEvent -Message "Loaded Modules: $(Get-Module | Select-Object -ExpandProperty Name)" -Source $source $alreadyLoadedEXOProxyModules = Get-Module | Where-Object -FilterScript { $_.ExportedCommands.Keys.Contains('Get-AcceptedDomain') } foreach ($loadedModule in $alreadyLoadedEXOProxyModules) { Add-MSCloudLoginAssistantEvent -Message "Removing module {$($loadedModule.Name)} from current EXO session" -Source $source Remove-Module $loadedModule.Name -Force -Verbose:$false | Out-Null } [array]$activeSessions = Get-PSSession | Where-Object -FilterScript { $_.ComputerName -like '*outlook.office*' -and $_.State -eq 'Opened' } Add-MSCloudLoginAssistantEvent -Message "Active Sessions: $($activeSessions | Out-String)" -Source $source if (-not $SkipPSSessionEvaluation -and $activeSessions.Length -ge 1) { Add-MSCloudLoginAssistantEvent -Message "Found {$($activeSessions.Length)} existing Exchange Online Session" -Source $source $ProxyModule = Import-PSSession $activeSessions[0] ` -DisableNameChecking ` -AllowClobber Add-MSCloudLoginAssistantEvent -Message "Imported session into $ProxyModule" -Source $source Import-Module $ProxyModule -Global ` -Verbose:$false | Out-Null $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true Add-MSCloudLoginAssistantEvent -Message 'Reloaded the Exchange Module' -Source $source # Rerun the function to make sure we have all the necessary commands loaded # but prevent an infinite loop by skipping the PSSession evaluation Connect-MSCloudLoginExchangeOnline -SkipPSSessionEvaluation return } Add-MSCloudLoginAssistantEvent -Message 'No active Exchange Online session found.' -Source $source # Make sure we disconnect from any existing connections Disconnect-ExchangeOnline -Confirm:$false $CommandName = @{} if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad.Count -gt 0) { # Make sure we have the Get-AcceptedDomain command available if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad -notcontains 'Get-AcceptedDomain') { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad += 'Get-AcceptedDomain' } # Include the previously loaded commands, if available $combinedCmdlets = ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.CmdletsToLoad + $Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedCmdlets) | Select-Object -Unique $CommandName.Add('CommandName', $combinedCmdlets) Add-MSCloudLoginAssistantEvent -Message "Commands to load: $($CommandName.CommandName -join ',')" -Source $source } if ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.AuthenticationType -eq 'ServicePrincipalWithThumbprint') { Add-MSCloudLoginAssistantEvent -Message "Attempting to connect to Exchange Online using AAD App {$($Script:MSCloudLoginConnectionProfile.ExchangeOnline.ApplicationId)}" -Source $source try { if ($null -eq $Script:MSCloudLoginConnectionProfile.OrganizationName) { $Script:MSCloudLoginConnectionProfile.OrganizationName = Get-MSCloudLoginOrganizationName ` -ApplicationId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ApplicationId ` -TenantId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.TenantId ` -CertificateThumbprint $Script:MSCloudLoginConnectionProfile.ExchangeOnline.CertificateThumbprint } if ($null -ne $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Endpoints -and ` $null -ne $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Endpoints.ConnectionUri -and ` $null -ne $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Endpoints.AzureADAuthorizationEndpointUri) { Add-MSCloudLoginAssistantEvent -Message 'Connecting by endpoints URI' -Source $source Connect-ExchangeOnline -AppId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ApplicationId ` -Organization $Script:MSCloudLoginConnectionProfile.OrganizationName ` -CertificateThumbprint $Script:MSCloudLoginConnectionProfile.ExchangeOnline.CertificateThumbprint ` -ShowBanner:$false ` -ShowProgress:$false ` -ConnectionUri $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Endpoints.ConnectionUri ` -AzureADAuthorizationEndpointUri $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Endpoints.AzureADAuthorizationEndpointUri ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null } else { Add-MSCloudLoginAssistantEvent -Message 'Connecting by environment name' -Source $source Connect-ExchangeOnline -AppId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ApplicationId ` -Organization $Script:MSCloudLoginConnectionProfile.OrganizationName ` -CertificateThumbprint $Script:MSCloudLoginConnectionProfile.ExchangeOnline.CertificateThumbprint ` -ShowBanner:$false ` -ShowProgress:$false ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null } $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $false Add-MSCloudLoginAssistantEvent -Message "Successfully connected to Exchange Online using AAD App {$ApplicationID}" -Source $source } catch { throw $_ } } elseif ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.AuthenticationType -eq 'Credentials') { try { Add-MSCloudLoginAssistantEvent -Message 'Attempting to connect to Exchange Online using Credentials without MFA' -Source $source Connect-ExchangeOnline -Credential $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials ` -ShowProgress:$false ` -ShowBanner:$false ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -ErrorAction Stop ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $false Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using Credentials without MFA' -Source $source } catch { if ($_.Exception -like '*you must use multi-factor authentication to access*') { Connect-MSCloudLoginExchangeOnlineMFA -Credentials $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials } else { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $false throw $_ } } } elseif ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.AuthenticationType -eq 'CredentialsWithTenantId') { try { Add-MSCloudLoginAssistantEvent -Message 'Attempting to connect to Exchange Online using Credentials without MFA' -Source $source Connect-ExchangeOnline -Credential $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials ` -ShowProgress:$false ` -ShowBanner:$false ` -DelegatedOrganization $Script:MSCloudLoginConnectionProfile.ExchangeOnline.TenantId ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -ErrorAction Stop ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $false Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using Credentials & TenantId without MFA' -Source $source } catch { if ($_.Exception -like '*you must use multi-factor authentication to access*') { Connect-MSCloudLoginExchangeOnlineMFA -Credentials $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials ` -TenantId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.TenantId } else { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $false throw $_ } } } elseif ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.AuthenticationType -eq 'Identity') { Add-MSCloudLoginAssistantEvent -Message 'Attempting to connect to Exchange Online using Managed Identity' -Source $source try { if ($null -eq $Script:MSCloudLoginConnectionProfile.OrganizationName) { $Script:MSCloudLoginConnectionProfile.OrganizationName = Get-MSCloudLoginOrganizationName -Identity } Connect-ExchangeOnline -AppId $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ApplicationId ` -Organization $Script:MSCloudLoginConnectionProfile.OrganizationName ` -ManagedIdentity ` -ShowBanner:$false ` -ShowProgress:$false ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $false $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $true Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using Managed Identity' -Source $source } catch { throw $_ } } elseif ($Script:MSCloudLoginConnectionProfile.ExchangeOnline.AuthenticationType -eq 'AccessTokens') { Add-MSCloudLoginAssistantEvent -Message 'Connecting to EXO with AccessTokens' -Source $source try { $AccessTokenValue = $Script:MSCloudLoginConnectionProfile.ExchangeOnline.AccessTokens[0] if ($AccessTokenValue.GetType().Name -eq 'PSCredential') { $Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($AccessTokenValue.Password) $AccessTokenValue = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr) [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr) } Connect-ExchangeOnline -AccessToken $AccessTokenValue ` -Organization $Script:MSCloudLoginConnectionProfile.ExchangeOnline.TenantId ` -ShowBanner:$false ` -ShowProgress:$false ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $false $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $false Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using Access Token' -Source $source } catch { throw $_ } } else { Add-MSCloudLoginAssistantEvent -Message 'No valid authentication type found' -Source $source throw 'No valid authentication type found' } $Script:MSCloudLoginCurrentLoadedModule = 'EXO' # Usually the tmpEXO* modules, but it might also be from another PSSession $loadedEXOProxyModule = Get-Module | Where-Object -FilterScript { $_.ExportedCommands.Keys.Contains('Get-AcceptedDomain') } $loadedEXOModule = Get-Module -Name 'ExchangeOnlineManagement' $Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedCmdlets = $loadedEXOProxyModule.ExportedCommands.Keys + $loadedEXOModule.ExportedCommands.Keys if ($loadAllCmdlets) { $Script:MSCloudLoginConnectionProfile.ExchangeOnline.LoadedAllCmdlets = $true } } function Connect-MSCloudLoginExchangeOnlineMFA { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $Credentials, [Parameter()] [System.String] $TenantId ) $ProgressPreference = 'SilentlyContinue' $source = 'Connect-MSCloudLoginExchangeOnlineMFA' try { if ([System.String]::IsNullOrEmpty($TenantId)) { Add-MSCloudLoginAssistantEvent -Message 'Creating a new ExchangeOnline Session using MFA' -Source $source Connect-ExchangeOnline -UserPrincipalName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials.UserName ` -ShowBanner:$false ` -ShowProgress:$false ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using credentials with MFA' -Source $source } else { Add-MSCloudLoginAssistantEvent -Message 'Creating a new ExchangeOnline Session using MFA with Credentials and TenantId' -Source $source Connect-ExchangeOnline -UserPrincipalName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Credentials.UserName ` -ShowBanner:$false ` -ShowProgress:$false ` -DelegatedOrganization $TenantId ` -ExchangeEnvironmentName $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ExchangeEnvironmentName ` -Verbose:$false ` -SkipLoadingCmdletHelp ` @CommandName | Out-Null Add-MSCloudLoginAssistantEvent -Message 'Successfully connected to Exchange Online using credentials and tenantId with MFA' -Source $source } $Script:MSCloudLoginConnectionProfile.ExchangeOnline.ConnectedDateTime = [System.DateTime]::Now.ToString() $Script:MSCloudLoginConnectionProfile.ExchangeOnline.Connected = $true $Script:MSCloudLoginConnectionProfile.ExchangeOnline.MultiFactorAuthentication = $true } catch { throw $_ } } |