やりたいこと
ローカルの 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 なのでそういうワケにもいかず
やり方
1. Google API の Client ID と Client Secret の取得
まず、Google API を使うためにはトークンが必要なのですが、トークンを取得するためには OAuth で認証するための
- Client ID と
- 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 に埋め込みできないんですね。。
ソース
<#
.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 を使うためのトークンを取得
下記のコマンドを実行していきます。
# スクリプトを読み込み
. .\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 に貼り付けてください。
認証コードを入力してください: # 認証コードを貼り付け
これでユーザーの環境変数に認証に必要なトークンの情報が保存されました。