Functions/Connect-GoogleWorkspace.ps1
Function Connect-GoogleWorkspace { <# .LINK https://github.com/Sekers/GoogleWorkspaceAPI .SYNOPSIS Google API - Verify cached tokens exist and are not expired using Connect-GoogleWorkspace. Connect-GoogleWorkspace will automatically refresh tokens or reauthenticate to the Google API service, if necessary. .DESCRIPTION Google API - Verify cached tokens exist and are not expired using Connect-GoogleWorkspace. Connect-GoogleWorkspace will automatically refresh tokens or reauthenticate to the Google API service, if necessary. .PARAMETER ForceReauthentication Forces reauthentication. .PARAMETER ForceRefresh Forces token refresh. .PARAMETER ClearBrowserControlCache Used in conjunction with 'ForceReauthentication'. Clears the Microsoft Edge WebView2 control browser cache. Useful when troubleshooting authentication. .PARAMETER AuthenticationMethod Let's you specify how you want to authenticate if authentication is necessary: - EdgeWebView2 (default): Opens a web browser window using Microsoft Edge WebView2 for authentication. Requires the WebView2 Runtime to be installed. If not installed, will prompt for automatic installation. - MiniHTTPServer: Alternate method of capturing the authentication using your user account's default web browser and listening for the authentication response using a temporary HTTP server hosted by the module. .EXAMPLE Connect-GoogleWorkspace .EXAMPLE Connect-GoogleWorkspace -ForceReauthentication .EXAMPLE Connect-GoogleWorkspace -ForceReauthentication -ClearBrowserControlCache .EXAMPLE Connect-GoogleWorkspace -ForceReauthentication -AuthenticationMethod MiniHTTPServer .EXAMPLE Connect-GoogleWorkspace -ForceRefresh #> [CmdletBinding(DefaultParameterSetName='NoParameters')] Param( [parameter( Position=0, ParameterSetName = 'ForceReauthentication', ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [Switch]$ForceReauthentication, [parameter( Position=1, ParameterSetName = 'ForceRefresh', ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [Switch]$ForceRefresh, [parameter( Position=2, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [ValidateSet('EdgeWebView2','MiniHTTPServer','ServiceAccount')] # TODO ServiceAccount [string]$AuthenticationMethod ) DynamicParam { # Initialize Parameter Dictionary $ParameterDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new() # Make -ClearBrowserControlCache Parameter Only Appear if ForceReauthentication is Used # DynamicParameter1: ClearBrowserControlCache if ($ForceReauthentication) { $ParameterAttributes = [System.Management.Automation.ParameterAttribute]@{ ParameterSetName = "ForceReauthentication" Mandatory = $false ValueFromPipeline = $true ValueFromPipelineByPropertyName = $true } $AttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new() $AttributeCollection.Add($ParameterAttributes) $DynamicParameter1 = [System.Management.Automation.RuntimeDefinedParameter]::new( 'ClearBrowserControlCache', [switch], $AttributeCollection) $ParameterDictionary.Add('ClearBrowserControlCache', $DynamicParameter1) } return $ParameterDictionary } begin { $ClearBrowserControlCache = $PSBoundParameters['ClearBrowserControlCache'] } process { # Info: https://developers.google.com/identity/protocols/oauth2#installed:~:text=The%20Google%20OAuth%202.0%20endpoint%20supports%20applications%20that%20are,token%20to%20obtain%20a%20new%20one. # The Google OAuth 2.0 endpoint supports applications that are installed on devices such as computers, mobile devices, and tablets. # When you create a client ID through the Google API Console, specify that this is an Installed application, then select Android, Chrome app, # iOS, Universal Windows Platform (UWP), or Desktop app as the application type. # The process results in a client ID and, in some cases, a client secret, which you embed in the source code of your application. # (In this context, the client secret is obviously not treated as a secret.) # The authorization sequence begins when your application redirects a browser to a Google URL; # the URL includes query parameters that indicate the type of access being requested. Google handles the user authentication, session selection, and user consent. # The result is an authorization code, which the application can exchange for an access token and a refresh token. # The application should store the refresh token for future use and use the access token to access a Google API. # Once the access token expires, the application uses the refresh token to obtain a new one. # Get the config and set the connection information $google_workspace_config = Get-GoogleWorkspaceConfig -ConfigPath $google_workspace_api_config_file_path $client_id = $google_workspace_config.client_id $client_secret = $google_workspace_config.client_secret # If key file does not exist or the ForceReauthentication parameter is sent, go and get a new one-time use authorization code # so you can exchange for an access token and a refresh token. if ((-not (Test-Path $google_workspace_api_tokens_file_path)) -or ($ForceReauthentication)) { $HashArguments = @{ google_workspace_api_tokens_file_path = $google_workspace_api_tokens_file_path google_workspace_api_scopes = $google_workspace_api_scopes AuthenticationMethod = $AuthenticationMethod } Get-GoogleAPINewTokens @HashArguments -ClearBrowserControlCache:$ClearBrowserControlCache } # Get Tokens & Set Creation Times try { $Authorization = Get-GoogleWorkspaceAuthTokensFromFile $refresh_token_creation = $Authorization.refresh_token_creation $access_token_creation = $Authorization.access_token_creation } catch { throw "JSON token file is corrupted or invalid. Please run Connect-GoogleWorkspace with the -ForceReauthentication parameter to recreate it." } # If Refresh Token Has Expired Because it Hasn't Been Used for Max Refresh Token Timespan, Ask User to Reauthenticate if (-not (Confirm-TokenIsFresh -TokenCreation $refresh_token_creation -TokenType Refresh)) { $HashArguments = @{ google_workspace_api_tokens_file_path = $google_workspace_api_tokens_file_path google_workspace_api_scopes = $google_workspace_api_scopes AuthenticationMethod = $AuthenticationMethod } Get-GoogleAPINewTokens @HashArguments -ClearBrowserControlCache:$ClearBrowserControlCache # Get Tokens & Set Creation Times try { $Authorization = Get-GoogleWorkspaceAuthTokensFromFile $refresh_token_creation = $Authorization.refresh_token_creation $access_token_creation = $Authorization.access_token_creation } catch { throw "JSON token file is expired, corrupted or invalid. Please run Connect-GoogleWorkspace with the -ForceReauthentication parameter to recreate it." } } # If the Access Token Expired OR the -ForceRefresh Parameter is Set, Then Refresh Access Token if ((-not (Confirm-TokenIsFresh -TokenCreation $access_token_creation -TokenType Access)) -or ($ForceRefresh)) { # Run Invoke Command and Catch Responses [int]$InvokeCount = 0 [int]$MaxInvokeCount = 5 do { $InvokeCount += 1 $NextAction = $null try { $Authorization = Get-GoogleWorkspaceAuthTokensFromFile $Authorization = Get-AccessToken -client_id $client_id -client_secret $client_secret -refresh_token $($Authorization.refresh_token) -refresh_token_creation $($Authorization.refresh_token_creation) } catch { # Process Invoke Error $NextAction = CatchInvokeErrors($_) # Just in case the token was refreshed by the error catcher, update the $Authorization variable $Authorization = Get-GoogleWorkspaceAuthTokensFromFile } }while ($NextAction -eq 'retry' -and $InvokeCount -lt $MaxInvokeCount) if ($InvokeCount -ge $MaxInvokeCount) { throw "Invoke tried running $InvokeCount times, but failed each time.`n" ` + "JSON token file is corrupted or invalid. Please run Connect-GoogleWorkspace with the -ForceReauthentication parameter to recreate it." } # Save credentials to file $Authorization | Select-Object access_token, refresh_token, refresh_token_creation, access_token_creation | ConvertTo-Json ` | ConvertTo-SecureString -AsPlainText -Force ` | ConvertFrom-SecureString ` | Out-File -FilePath $google_workspace_api_tokens_file_path -Force } } } |