Public/Get-GSToken.ps1

function Get-GSToken {
<#
.Synopsis
   Gets a Service Account Access Token from Google Apps
.DESCRIPTION
   Requests Access Token using Service Account and P12 key file, returns the token directly. Defaults to 3600 seconds token expiration time.
.EXAMPLE
   $token = Get-GSToken -P12KeyPath "C:\PSGoogle.p12" -Scopes "https://www.googleapis.com/auth/admin.directory.user" -AppEmail "psg@nf.iam.gserviceaccount.com" -AdminEmail "google.admin.account@domain.com"
.EXAMPLE
   $token = Get-GSToken
#>

    Param
    (
      [parameter(Mandatory=$false,HelpMessage="What is the full path to your Google Service Account's P12 key file?")]
      [ValidateNotNullOrEmpty()]
      [String]
      $P12KeyPath = $Script:PSGSuite.P12KeyPath,
      [parameter(Mandatory=$true)]
      [ValidateNotNullOrEmpty()]
      [string[]]
      $Scopes,
      [parameter(Mandatory=$false)]
      [ValidateNotNullOrEmpty()]
      [String]
      $AppEmail = $Script:PSGSuite.AppEmail,
      [parameter(Mandatory=$false)]
      [ValidateNotNullOrEmpty()]
      [String]
      $AdminEmail = $Script:PSGSuite.AdminEmail
    )
$NugetDir="$ModuleRoot\nuget"
Add-Type -Path "$NugetDir\owin.1.0.0\lib\net40\Owin.dll"
Add-Type -Path "$NugetDir\microsoft.owin.3.0.1\lib\net45\Microsoft.Owin.dll"
Add-Type -Path "$NugetDir\microsoft.owin.security.3.0.1\lib\net45\Microsoft.Owin.Security.dll"
$encoder = New-Object Microsoft.Owin.Security.DataHandler.Encoder.Base64UrlTextEncoder
$googleCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("$P12KeyPath", "notasecret",[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable )
$rsaPrivate = $googleCert.PrivateKey
$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$rsa.ImportParameters($rsaPrivate.ExportParameters($true))
$rawheader = [Ordered]@{
    alg = "RS256"
    typ = "JWT"
} | ConvertTo-Json -Compress
$header = $encoder.Encode([System.Text.Encoding]::UTF8.GetBytes($rawheader))
$now = (Get-Date).ToUniversalTime()
$createDate = [Math]::Floor([decimal](Get-Date($now) -UFormat "%s"))
$expiryDate = [Math]::Floor([decimal](Get-Date($now.AddMinutes(59)) -UFormat "%s"))
$rawclaims = [Ordered]@{
    iss = "$AppEmail"
    sub = "$AdminEmail"
    scope = "$($Scopes -join " ")"
    aud = "https://www.googleapis.com/oauth2/v4/token"
    exp = "$expiryDate"
    iat = "$createDate"
} | ConvertTo-Json
$claims = $encoder.Encode([System.Text.Encoding]::UTF8.GetBytes($rawclaims))
$toSign = [System.Text.Encoding]::UTF8.GetBytes($header + "." + $claims)
$sig = $encoder.Encode($rsa.SignData($toSign,"SHA256"))
$jwt = $header + "." + $claims + "." + $sig
$fields = [Ordered]@{grant_type='urn:ietf:params:oauth:grant-type:jwt-bearer';assertion=$jwt}
try
    {
    Write-Verbose "Acquiring access token..."
    $response = Invoke-RestMethod -Uri "https://www.googleapis.com/oauth2/v4/token" -Method Post -Body $fields -ContentType "application/x-www-form-urlencoded" -ErrorAction Stop -Verbose:$false | Select-Object -ExpandProperty access_token
    Write-Verbose "Access token acquired!"
    return $response
    }
catch
    {
    Write-Verbose "Failed to acquire access token!"
    $result = $_.Exception.Response.GetResponseStream()
    $reader = New-Object System.IO.StreamReader($result)
    $reader.BaseStream.Position = 0
    $reader.DiscardBufferedData()
    $response = $reader.ReadToEnd() | 
        ConvertFrom-Json | 
        Select-Object @{N="WebError";E={$Error[0]}},@{N="Code";E={"401"}},@{N="Error";E={$_.error}},@{N="Description";E={$_.error_description}}
    throw "$($MyInvocation.MyCommand) : $(Get-HTTPStatus -Code $response.Code): $($response.Error) / $($response.Description)"
    }
}