Functions/Connect-GSuiteAdminAccount.ps1

<#
.SYNOPSIS
    This function uses permanent refresh tokens of various scopes stored in an endpoint to get temporary GSuite access tokens.
#>

function Connect-GSuiteAdminAccount {
    [CmdletBinding(PositionalBinding=$false, DefaultParameterSetName = 'AllScopes')]
    [OutputType([Bool])]
    param (
        # The MSPComplete endpoint containing the application ID and client secret in the credential.
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [ValidateNotNull()]
        $endpoint,

        # Whether to retrieve access tokens using all available refresh tokens
        [Parameter(Mandatory=$false, ParameterSetName="AllScopes")]
        [ValidateNotNull()]
        [Switch]$allScopes,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.user'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$user,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.group'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$group,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.orgunit'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$organizationalUnit,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.userschema'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$useSchema,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.device.mobile'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$mobileDevice,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.user.security'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$security,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.customer'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$customer,

        # Whether to retrieve access token of the scope 'https://www.googleapis.com/auth/admin.directory.domain'
        [Parameter(Mandatory=$false, ParameterSetName="IndividualScope")]
        [ValidateNotNull()]
        [Switch]$domain,

        # Select the stream where the messages will be directed.
        [Parameter(Mandatory=$false)]
        [ValidateSet("Information", "Warning", "Error", "None")]
        [String]$outputStream = "Error"
    )

    # If no individual scope is specified, retrieve access tokens for all the scopes
    if ($PSCmdlet.ParameterSetName -eq "AllScopes") {
        $allScopes = [Switch]::Present
    }

    # Extract all the refresh tokens as well as the application ID and client secret from the endpoint
    $refreshTokensHashTable = ConvertFrom-GSuiteEndpoint -Endpoint $endpoint
    $applicationId = $refreshTokensHashTable.ApplicationId
    $clientSecret = $refreshTokensHashTable.ClientSecret

    # Initialize the access token hash table
    $Global:GSuiteAccessTokensHashTable = @{ }

    # Exchange refresh tokens for access tokens
    foreach ($refreshToken in $refreshTokensHashTable.GetEnumerator()) {

        # Skip the client secret and application ID
        if ($refreshToken.Name -eq "ClientSecret" -or $refreshToken.Name -eq "ApplicationID") {
            continue
        }

        # Skip the scope if the corresponding switch is not present
        if (!$allScopes -and !(Invoke-Expression "`$$($refreshToken.Name)")) {
            continue
        }

        # Validate that the refresh token exists
        if([String]::IsNullOrWhiteSpace($refreshToken.Value)){
            Write-OutputMessage "The refresh token of the scope '$($refreshToken.Name)' cannot be found in the endpoint." -OutputStream $outputStream -ReturnMessage:$false
            return $false
        }

        # Construct the REST call
        $invokeRestMethodParams = @{
            Uri     = "https://www.googleapis.com/oauth2/v4/token"
            Method  = "POST"
            Headers = @{
                "Content-Type" = "application/json"
            }
            Body    = @{
                client_id     = $applicationId
                client_secret = $clientSecret
                grant_type    = "refresh_token"
                refresh_token = $refreshToken.Value
            } | ConvertTo-Json
        }

        # Invoke the REST call
        Write-Information "Retrieving the GSuite access token using the refresh token of the scope '$($refreshToken.Name)'."
        try {
            $response = Invoke-RestMethod @invokeRestMethodParams
        }
        catch {
            Write-OutputMessage "Exception occurred while retrieving the GSuite access token of the scope '$($refreshToken.Name)'.`r`n$($_.Exception.Message)" -OutputStream $outputStream -ReturnMessage:$false
            return $false
        }

        # Verify the response
        if ($null -eq $response -or $response.expires_in -le 0 -or [String]::IsNullOrWhiteSpace($response.access_token)) {
            Write-OutputMessage "Failed to retrieve the GSuite access token of the scope '$($refreshToken.Name)'." -OutputStream $outputStream -ReturnMessage:$false
            return $false
        }

        # Update the hash table
        $Global:GSuiteAccessTokensHashTable.Add($refreshToken.Name, $response.access_token)
    }

    # Return true if all the access tokens are successfully retrieved
    return $true
}