BitTitan.Runbooks.ExchangeOnline.Beta.psm1

<#
.SYNOPSIS
    PowerShell module for common Exchange Online functions and resources used in BitTitan Runbooks.
.NOTES
    Version: 0.2.2
    Last updated: 23 October 2018
 
    Copyright (c) BitTitan, Inc. All rights reserved.
    Licensed under the MIT License.
#>


# Install/import BitTitan.Runbooks.Modules to bootstrap the install/import of the other modules
Install-Module BitTitan.Runbooks.Modules -Scope CurrentUser -AllowClobber
Import-Module BitTitan.Runbooks.Modules -Force

# Install/import the other BitTitan.Runbooks modules
Import-BT_Module BitTitan.Runbooks.MSPComplete -Quiet

<#
.SYNOPSIS
    This function connects to Exchange Online using admin account credentials or a MSPComplete Endpoint.
.DESCRIPTION
    This function connects to Exchange Online using admin account credentials or a MSPComplete Endpoint.
    It returns whether the connection and logon was successful.
.PARAMETER username
    The username of the Exchange Online admin account.
.PARAMETER password
    The password of the Exchange Online admin account.
.PARAMETER endpoint
    The MSPComplete Endpoint for the Exchange Online admin credentials.
    This endpoint can be masked or unmasked.
.EXAMPLE
    Connect-ExchangeOnlineAdminAccount -Endpoint $Endpoint
.EXAMPLE
    $Endpoint | Connect-ExchangeOnlineAdminAccount
.EXAMPLE
    Connect-ExchangeOnlineAdminAccount -Username $username -Password $password
#>

function Connect-ExchangeOnlineAdminAccount {
    param (
        # The username of the Exchange Online admin account.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [string]$username,

        # The password of the Exchange Online admin account.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [SecureString]$password,

        # The MSPComplete Endpoint for the Exchange Online admin credentials.
        [Parameter(Mandatory=$true, ParameterSetName="endpoint", ValueFromPipeline=$true)]
        $endpoint,

        # The maximum number of logon attempts. Each logon attempt can take up to 60 seconds.
        [Parameter(Mandatory=$false)]
        [ValidateScript({ $_ -gt 1 })]
        [Int]$maximumAttempts = 5
    )

    # If given endpoint, retrieve username and password
    if ($PSCmdlet.ParameterSetName -eq "endpoint") {
        $exchangeCredential = $endpoint | Get-CredentialFromMSPCompleteEndpoint
        $username = $exchangeCredential.Username
    }
    # Create the Exchange Online credential from the given username and password
    else {
        $exchangeCredential = New-Object System.Management.Automation.PSCredential($username, $password)
    }

    # Logon to Exchange Online
    $attemptNum = 0
    while ($true) {
        try {
            $exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange `
                -ConnectionUri https://outlook.office365.com/powershell-liveid/ `
                -Credential $exchangeCredential -Authentication Basic -AllowRedirection -Name "ExchangeOnline" `
                -ErrorVariable errorOutput
            if (![String]::IsNullOrWhiteSpace($errorOutput)) {
                Write-Host "Error output: $($errorOutput)"
            }

            # Additional Import-Module ensures that imported cmdlets are visible globally
            Import-Module (Import-PSSession -Session $exchangeSession -DisableNameChecking -AllowClobber) -Global

            # Logon was successful
            Write-Information "Logon to Exchange Online successful with username '$($username)'."
            return $true
        }
        catch {
            # Check if error was due to too many runspaces
            if ($errorOutput -like "*Fail to create runspace because you have exceeded your budget to create runspace*") {
                $attemptNum += 1
                if ($attemptNum -eq $maximumAttempts) {
                    return $false
                }
                Write-Host "Encountering throttling when connecting to Exchange Online. Waiting 60 seconds, then attempting again. (attempt $($attemptNum)/$($maximumAttempts))"

                # Wait 60 seconds and try to connect again
                Start-Sleep -Seconds 60
                continue
            }

            # Logon was unsuccessful due to other error
            Write-Error "Failed Exchange Online logon with username '$($username)'.`r`n$($_.Exception.Message)"
            return $false
        }
    }
}

<#
.SYNOPSIS
    This function disconnects from the current Exchange Online session.
.DESCRIPTION
    This function disconnects from the current Exchange Online session
    It returns whether the disconnect was successful.
#>

function Disconnect-ExchangeOnline {
    # Retrieve sessions
    $exchangeOnlineSession = Get-PSSession | Where-Object { $_.Name -eq "ExchangeOnline" }

    # There is at least one existing session
    if ($null -ne $exchangeOnlineSession) {
        # There is more than one existing session
        if ($null -ne $exchangeOnlineSession.length -and $exchangeOnlineSession.length -gt 1) {
            foreach ($session in $exchangeOnlineSession) {
                $session | Remove-PSSession
            }
        }

        # There is only one existing session
        else {
            $exchangeOnlineSession | Remove-PSSession
        }
        return $true
    }

    # There are no existing sessions
    else {
        Write-Warning "Attempting to disconnect Exchange Online session when there isn't one running."
        return $false
    }
}