LoginSignup
3
4

More than 3 years have passed since last update.

PowerShell で Google API を利用するためのトークンを取得する方法

Last updated at Posted at 2019-05-08

やりたいこと

ローカルの PowerShell スクリプト(*.ps1)から Google API を使うためのトークンを取得する。

経緯

Google Spreadsheets に登録されている情報を元に Internal の Redmine へ REST API でチケットを新規作成する処理が必要になったため。

前提環境

  • OS は Windows
  • 余計なミドルウェアを入れないで使えるものとしては PowerShell 一択

Google Apps Script(https://script.google.com) から直接 Redmine(http://redmine.localhost)に対してリクエストできたら良いのですが、Redmine 側が Internal なのでそういうワケにもいかず :sweat_smile:

やり方

1. Google API の Client ID と Client Secret の取得

まず、Google API を使うためにはトークンが必要なのですが、トークンを取得するためには OAuth で認証するための

  1. Client ID と
  2. Client Secret

が必要なので、こちらの記事(【Google API Console】クライアントID・クライアントシークレットを取得する - Qiita )を参考に取得します。当該記事と現在の GCP の画面デザインは多少異なるかもしれませんがオペレーションに大した違いはありません。

後ほど取得した Client ID と Client Secret は使うのでメモしておきます。

2. PowerShell でスクリプトを作成

Google APIのアクセストークンをPowerShellでリフレッシュトークンも考えて取得する - Qiita を参考にスクリプトを作成しました。当該記事では Client ID、Client Secret、Refresh Token、Access Token をローカルのテキストファイルに設定・保存していますが、スクリプト実行環境を複数人が使用するケースも有り得ますし、実行ユーザー以外に参照させないためにもユーザーの環境変数に保存するように処理を変更しています。

Gist

下記のソースは Gist に保存しています。必要であればダウンロードしてください。
gist.github.com/takeru08ma/GoogleAPI-Get-AccessToken.ps1
※ Gist って Qiita に埋め込みできないんですね。。

ソース

GoogleAPI-Get-AccessToken.ps1
<#
.SYNOPSIS
  Google API を使用するするために必要なトークンを取得する。

.DESCRIPTION
  Google Cloud Platform (GCP) で、自身のアカウント(*@gmail.com など)を用いて
  Client ID、Client Secret を取得してメモしておく。
  Client ID と Client Secret の準備ができたら当スクリプトを . で読み込む。

  $Scope を指定して GoogleAPI-Get-AccessToken 関数を実行する。

  スクリプト実行時に Client ID と Client Secret の入力を求められるので
  入力する。正常に処理されると続いて認証コードの入力を求められる。

  Client ID, Client Secret, Refresh Token, Access Token はユーザーの環境変数に
  保存されます。

  環境変数:
    User:
      GOOGLE_API_CLIENT_ID
      GOOGLE_API_CLIENT_SECRET
      GOOGLE_API_REFRESH_TOKEN
      GOOGLE_API_ACCESS_TOKEN

.PARAMETER Scope
  どの範囲で Google API を利用するかスコープ(Uris)を指定する。
  例: Google Spreadsheets のデータを読み込み専用で使用するスコープの場合は、 
      https://www.googleapis.com/auth/spreadsheets.readonly になります。
      (指定がなければこれがデフォルトになります。)

.INPUTS
  処理中に求められるデータの順番。

  1. Google API の Client ID
  2. Google API の Client Secret
  3. 認証コード

  Client ID と Client Secret が正常であれば認証コードを入力します。

.LINK
  Google API OAuth2
    https://developers.google.com/identity/protocols/OAuth2

  Scopes
    https://developers.google.com/identity/protocols/googlescopes
    https://developers.google.com/gmail/api/auth/scopes
    https://developers.google.com/sheets/api/guides/authorizing
    https://developers.google.com/drive/api/v2/about-auth

.EXAMPLE
  . ./GoogleAPI-Get-AccessToken.ps1
  # Spreadsheets を読み取り専用の権限で使用する
  GoogleAPI-Get-AccessToken "https://www.googleapis.com/auth/spreadsheets.readonly"

.EXAMPLE
  . ./GoogleAPI-Get-AccessToken.ps1
  # Gmail の読み書きと Drive の読み取り専用で使用する
  GoogleAPI-Get-AccessToken "https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/drive.readonly"
#>
function GoogleAPI-Get-AccessToken([String]$Scope = "https://www.googleapis.com/auth/spreadsheets.readonly") {
  # エラー発生時に Continue させない
  $ErrorActionPreference = "Stop"

  try {
    $RefreshToken = [System.Environment]::GetEnvironmentVariable("GOOGLE_API_REFRESH_TOKEN", "User")
    if (!$RefreshToken) {
      $Scope = [System.Web.HttpUtility]::UrlEncode($Scope)
      return GoogleAPI-Get-AccessTokenFromAuthorizationCode $Scope
    }

    $ClientID = [System.Environment]::GetEnvironmentVariable("GOOGLE_API_CLIENT_ID", "User")
    $ClientSecret = [System.Environment]::GetEnvironmentVariable("GOOGLE_API_CLIENT_SECRET", "User")

    $RefreshData = @{
      refresh_token = $RefreshToken;
      client_id = $ClientID;
      client_secret = $ClientSecret;
      grant_type = "refresh_token";
    }

    $Response = Invoke-WebRequest -Body $RefreshData -Uri "https://www.googleapis.com/oauth2/v4/token" -Method Post 
    $Token = $Response.Content | ConvertFrom-Json
    [System.Environment]::SetEnvironmentVariable("GOOGLE_API_ACCESS_TOKEN", $Token.access_token, "User")
    return $Token.access_token
  }
  catch [Exception] {
    $ErrorFile = "${PSScriptRoot}/" + $myInvocation.MyCommand.name + "_" + $env:USERNAME + "_Error_" + (Get-Date).ToString("yyyyMMdd-HHmmss-fff") + ".log"
    $error[0] | Out-File -File $ErrorFile -Encoding Default
    Write-Host ($myInvocation.MyCommand.name + " で例外が発生しました。エラー内容は下記パスに保存されました。`r`n${ErrorFile}")
    return $false
  }
}

function GoogleAPI-Get-AccessTokenFromAuthorizationCode([String]$Scope) {
  $ClientID = [System.Environment]::GetEnvironmentVariable("GOOGLE_API_CLIENT_ID", "User")
  # Client ID を貼り付けて実行
  if (!$ClientID) {
    $ClientID = Read-Host "Google API の Client ID を入力してください"
    if ($ClientID -eq "") {
      Write-Error "Google API の Client ID がユーザー環境変数に設定されていないため処理を中止します。"
    }
    [System.Environment]::SetEnvironmentVariable("GOOGLE_API_CLIENT_ID", $ClientID, "User")
  }

  $ClientSecret = [System.Environment]::GetEnvironmentVariable("GOOGLE_API_CLIENT_SECRET", "User")
  if (!$ClientSecret) {
    # Client Secret を貼り付けて実行
    $ClientSecret = Read-Host "Google API の Client Secret を入力してください"
    if ($ClientSecret -eq "") {
      Write-Error "Google API の Client Secret がユーザー環境変数に設定されていないため処理を中止します。"
    }
    [System.Environment]::SetEnvironmentVariable("GOOGLE_API_CLIENT_SECRET", $ClientSecret, "User")
  }

  $RedirectUri = "urn:ietf:wg:oauth:2.0:oob"

  Write-Host "ブラウザ認証を行います"

  $Uri = "https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=$ClientID&redirect_uri=$RedirectUri&scope=$Scope&access_type=offline"
  Write-Host $Uri

  # ブラウザを開いて Client ID と Client Secret で承認を行い、認証コードを取得する。
  Start-Process $Uri

  # 認証コードを貼り付けて実行
  $AuthorizationCode = Read-Host "認証コードを入力してください"

  $AuthData = @{
    code = $AuthorizationCode;
    client_id = $ClientID;
    client_secret = $ClientSecret;
    redirect_uri = $RedirectUri;
    grant_type = "authorization_code";
    access_type = "offline";
  }

  $TokenResponse = Invoke-WebRequest -Body $AuthData -Uri "https://www.googleapis.com/oauth2/v4/token" -Method Post 
  $Token = $TokenResponse.Content | ConvertFrom-Json
  [System.Environment]::SetEnvironmentVariable("GOOGLE_API_ACCESS_TOKEN", $Token.access_token, "User")
  [System.Environment]::SetEnvironmentVariable("GOOGLE_API_REFRESH_TOKEN", $Token.refresh_token, "User")

  return $Token.access_token
}

# [Debug]
# GoogleAPI-Get-AccessToken "https://www.googleapis.com/auth/spreadsheets.readonly"

3. PowerShell で Google API を使うためのトークンを取得

下記のコマンドを実行していきます。

PowerShell
# スクリプトを読み込み
. .\GoogleAPI-Get-AccessToken.ps1

# ヘルプを表示
Get-Help GoogleAPI-Get-AccessToken

# Spreadsheets を読み取り専用で使うためのスコープ
GoogleAPI-Get-AccessToken "https://www.googleapis.com/auth/spreadsheets.readonly"
Google API  Client ID を入力してください:     # Client ID を貼り付け
Google API  Client Secret を入力してください: # Client Secret を貼り付け
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&redirect_uri=urn:iet
f:wg:oauth:2.0:oob&scope=https%3a%2f%2fwww.googleapis.com%2fauth%2fspreadsheets.readonly&access_type=offline
認証コードを入力してください: 
  • スクリプト実行中にブラウザが起動し、
  • Google のアクセスリクエストの許可画面が表示されますので、
  • 許可したいアカウントを指定して 許可 を選択すると、
  • 認証コードが表示されます。 このコードをコピーして PowerShell に貼り付けてください。

PowerShell
認証コードを入力してください: # 認証コードを貼り付け

これでユーザーの環境変数に認証に必要なトークンの情報が保存されました。

参考文献

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4