PowerShellとGoogle Drive APIを使ってローカルファイルをGoogle Driveにアップロードしてみた

 2023.12.01 Yudai Imai

ss

はじめに

はじめまして、CI部の今井です。本記事はNI+C TeamGCP Advent Calendar 2023の1日目の記事となります。

Google Driveは、ユーザーがコンテンツを保存、共有、編集するための優れたクラウドベースのストレージサービスです。一方、PowerShellはWindowsベースのスクリプト言語で、システム管理者やエンドユーザーがコマンドラインからさまざまなタスクを自動化できる有用なツールです。

これら2つの強力なツールを組み合わせて、ローカルファイルを簡単かつ効率的にGoogle Driveにアップロードする方法はいろいろと解説されているかと思いますが、外部ライブラリを使う方法が多いことが問題になることがあると思います。そのため、本ブログでは、外部ライブラリをできるだけ使わないPowerShellとGoogle Drive APIを使用してローカルファイルをGoogle Driveにアップロードする方法について詳しく解説します。

具体的な手順、必要な設定情報、コードサンプルなどを通じて、このプロセスを容易に理解し、実装できるようになることを目指します。Windowsユーザーであれば、誰でもここで説明する手順を追って、ファイルのアップロードを自動化し、作業の効率化につなげることができます。

ちなみに今回作成しているブログは以前私が作成したブログ「Powershellの標準コマンドだけを使ってGoogle Cloudに接続する方法」の番外編的な立ち位置となります。

それではさっそく、PowerShellとGoogle Drive APIを駆使してローカルファイルをGoogle Driveにアップロードする手順について解説していきます。

前提条件

今回のブログでは以下のものが用意されていることが前提となります。

  • Googleアカウントがある
  • 課金が有効になっているGoogle Cloudのプロジェクトが存在している
    • Google Drive APIを利用するために必要になります
    • 無料のAPIを利用するため課金は発生いたしません
  • PowerShellが利用できるWindows端末がある

今回のブログでは新しいGoogleアカウントとGoogle Cloudプロジェクトを作成して進めていくようにいたしますが、GoogleアカウントとGoogle Cloudプロジェクトの作成については説明いたしません。ほかのブログなどをご参考にご用意してください。

準備

GoogleアカウントとGoogle Cloudプロジェクトの作成が完了したら以下の作業をGoogle Cloudプロジェクトのコンソールで実施してください。

  1. Google Cloudプロジェクトでサービスアカウントを作成する
  2. 作成したサービスアカウントの秘密鍵を作成し、ローカル環境にダウンロードする
  3. Google CloudでGoogle Drive APIを有効にする
  4. Google Drive上にファイルをアップロードするためのフォルダを作成し、①で作成したサービスアカウントに権限を付与する

①と②については、以前私が作成したこちらのブログを参考に実施してください。今回のブログとの違いはアクセス権の付与が不要となるのみとなります。

今回はGoogleアカウントは「powershell2drive@gmail.com」、Google Cloudプロジェクトは「powershell-to-drive(ID:powershell-to-drive-406205)」、サービスアカウント名は「powershell2drive(メールアドレス:powershell2drive@powershell-to-drive-406205.iam.gserviceaccount.com)」としました。このブログを公開した時にはすべて削除しています

③については、Google Cloudコンソールのサイドメニュー内の「APIとサービス」からアクセスした画面の「APIとサービスの有効化」を押下した後に検索欄にGoogle Drive APIを検索していただき、その先の画面で「有効にする」を押下していただくことで有効にすることができます。

sss1

ss2

ss3

④についてはGoogle Driveのマイドライブ上にフォルダーを作成し、①で作成したサービスアカウントにそのフォルダに対しての編集者権限を付与してください。今回はマイドライブには「test-folder」というフォルダを作成しました。

ss4

ss5

ss6

ここまでを実施していただければ準備は終了となります。次のセクションでは作成したPowerShellスクリプトについて説明します。

Google DriveにファイルをアップロードするためのPowerShellスクリプト

今回作成したPowerShellスクリプトはGoogleの公式ドキュメントに記載されている内容を参考に作成しています。こちらの記事では以下の順番で認証トークンを作成した後にその認証トークンを利用してGoogle Drive APIを呼び出すようにします。

  1. ヘッダー、クレームセット、署名を含む JSON Web Token(JWT、発音)を作成します。
  2. Google OAuth 2.0 認可サーバーにアクセス トークンをリクエストします。
  3. 承認サーバーが返す JSON レスポンスを処理します。

上記の内容を参考にして作成したものが以下のコードとなります。いくつかの部分でご自身の環境にあわせて変更していただく必要がありますので、後述のセクションにて解説を入れさせていただきます。

Add-Type -AssemblyName System.Security
Add-Type -AssemblyName System.Net
$VerbosePreference = "Continue"

# スクリプトとアップロードするファイルのパスを設定
$ScriptFolderPath = Split-Path $MyInvocation.MyCommand.path
$UploadFileName = "アップロードするファイル名" # アップロードするファイル名

# アップロードするファイルのパスを定義
$UploadFilePath = $ScriptFolderPath + "\" + $UploadFileName

# 秘密鍵ファイルのパスとパスワード、トークンリクエストに使用するその他の変数を設定
$CertFile = $ScriptFolderPath + "\" + "サービスアカウントの秘密鍵のファイル名.p12" # サービスアカウントの秘密鍵のファイル名に修正してください
$CertPassword = "サービスアカウントの秘密鍵のパスワード" # サービスアカウントの秘密鍵のパスワード
$Project = "Google CloudのプロジェクトID" # Google CloudのプロジェクトID
$ServiceAccountName = "作成したサービスアカウント名" # 作成したサービスアカウント名
$ServiceAccount = "作成したサービスアカウントのメールアドレス" # 作成したサービスアカウントのメールアドレス
$Scope = "https://www.googleapis.com/auth/drive.file"
$ExpirationSeconds = 3600

# 証明書をロードし、プライベートキーを取得し、RSA暗号サービスプロバイダを作成
$Certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($CertFile, $CertPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$RSACryptoServiceProvider = New-Object System.Security.Cryptography.RSACryptoServiceProvider
$RSACryptoServiceProvider.ImportParameters($Certificate.PrivateKey.ExportParameters($true))

# JWTヘッダーを構造化、エンコード、URLエンコード
$JwtHeader = '{"alg":"RS256","typ":"JWT"}'
$JwtHeaderBase64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($JwtHeader))
$JwtHeaderBase64UrlEncoded = $JwtHeaderBase64 -replace "/", "_" -replace "\+", "-" -replace "=", ""

# 現在の時間をUnixタイムスタンプ形式で取得し、有効期限を計算し、それをUnixタイムスタンプに変換
$Now = (Get-Date).ToUniversalTime()
$NowUnixTimestamp = (Get-Date -Date ($Now.DateTime) -UFormat %s)
$Expiration = $Now.AddSeconds($ExpirationSeconds)
$ExpirationUnixTimestamp = (Get-Date -Date ($Expiration.DateTime) -UFormat %s)

# JWTクレームセットを構造化、エンコード、URLエンコード
$JwtClaimSet = @"
{"iss":"$ServiceAccount","scope":"$Scope","aud":"https://oauth2.googleapis.com/token","exp":$ExpirationUnixTimestamp,"iat":$NowUnixTimestamp}
"@

# JWTシグネチャを定義し、完全なJWTを組み立て
$JwtClaimSetBase64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($JwtClaimSet))
$JwtClaimSetBase64UrlEncoded = $JwtClaimSetBase64 -replace "/", "_" -replace "\+", "-" -replace "=", ""
$StringToSign = $JwtHeaderBase64UrlEncoded + "." + $JwtClaimSetBase64UrlEncoded
$SHA256 = [System.Security.Cryptography.SHA256]::Create()
$Hash = $SHA256.ComputeHash([Text.Encoding]::UTF8.GetBytes($StringToSign))
$SignatureBase64 = [Convert]::ToBase64String($RSACryptoServiceProvider.SignData([System.Text.Encoding]::UTF8.GetBytes($StringToSign), "SHA256"))
$SignatureBase64UrlEncoded = $SignatureBase64 -replace "/", "_" -replace "\+", "-" -replace "=", ""
$Jwt = $JwtHeaderBase64UrlEncoded + "." + $JwtClaimSetBase64UrlEncoded + "." + $SignatureBase64UrlEncoded

# トークンリクエストの本文を定義
$Body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=$Jwt"

# トークンリクエストを送信し、アクセストークンを取得
$Uri = "https://www.googleapis.com/oauth2/v4/token"
$AccessToken = Invoke-RestMethod -Method Post -Uri $Uri -Body $Body -ContentType "application/x-www-form-urlencoded" | Select-Object -ExpandProperty access_token

# アップロードするファイルをbase64エンコーディングされた文字列として取得する
$SourceItem = Get-Item $UploadFilePath
$SourceBase64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes($UploadFilePath))

# アップロードのファイルメタデータを設定
$UploadMetadata = @{
    name    = $SourceItem.Name
  parents = @('アップロード先のGoogle DriveのフォルダID') # アップロード先のGoogle DriveのフォルダID
}

# アップロードリクエストの本文を構築
$UploadBody = @"
--boundary
Content-Type: application/json; charset=UTF-8

$($UploadMetadata | ConvertTo-Json)

--boundary
Content-Transfer-Encoding: base64
Content-Type: text/csv

$SourceBase64
--boundary--
"@

# アップロードリクエストのヘッダーを定義
$UploadHeaders = @{
    "Authorization"  = "Bearer $AccessToken"
    "Content-Type"   = 'multipart/related; boundary=boundary'
    "Content-Length" = $UploadBody.Length
}

# アップロードリクエストを送信し、レスポンスを取得
$Response = Invoke-RestMethod -Uri "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" -Method Post -Headers $UploadHeaders -Body $UploadBody

PowerShellスクリプトの注意事項

PowerShellスクリプトの中のUploadFileNameについてはご自身の環境のものに変更してください。今回の私の環境では「uploadfile.txt」という空ファイルを作成したので、この文字列に変更しました。

# スクリプトとアップロードするファイルのパスを設定
$ScriptFolderPath= Split-Path $MyInvocation.MyCommand.path
$UploadFileName= "アップロードするファイル名" # アップロードするファイル名

次に秘密鍵ファイルやGoogle Cloudのプロジェクト名、サービスアカウントの情報の部分もご自身の環境のものに変更してください。

# 秘密鍵ファイルのパスとパスワード、トークンリクエストに使用するその他の変数を設定
$CertFile = $ScriptFolderPath + "\" + "サービスアカウントの秘密鍵のファイル名.p12" # サービスアカウントの秘密鍵のファイル名に修正してください
$CertPassword = "サービスアカウントの秘密鍵のパスワード" # サービスアカウントの秘密鍵のパスワード
$Project = "Google CloudのプロジェクトID" # Google CloudのプロジェクトID
$ServiceAccountName = "作成したサービスアカウント名" # 作成したサービスアカウント名
$ServiceAccount = "作成したサービスアカウントのメールアドレス" # 作成したサービスアカウントのメールアドレス
$Scope = "https://www.googleapis.com/auth/drive.file"
$ExpirationSeconds = 3600

最後にアップロード先のGoogle DriveのフォルダIDの情報の部分もご自身の環境のものに変更してください。

# アップロードのファイルメタデータを設定
$UploadMetadata = @{
    name    = $SourceItem.Name
  parents = @('アップロード先のGoogle DriveのフォルダID') # アップロード先のGoogle DriveのフォルダID
}

以上でPowerShellスクリプトの注意点は終了となります。

PowerShellスクリプトの実行と確認

作成したPowerShellスクリプトを実行する準備をします。今回は同じフォルダの中にスクリプトファイルと秘密鍵ファイル、アップロード対象のファイルを配置します。スクリプトのファイル名はshell.ps1という名前で保存しています。

ss7

このshell.ps1ファイルを右クリックしていただき、「PowerShellで実行」を押していただくとuploadfile.txtファイルがGoogle Driveにアップロードされます。もし、アップロードできずエラーになってしまった場合は、前セクションの注意事項を再度確認してみてください。

ss8

ss9

終わりに

今回の記事では、PowerShellの標準コマンドを使って、Google Driveにファイルをアップロードする方法を紹介しました。この方法を使用することで、PowerShellの標準コマンドとGoogle Drive APIを使用することで、より柔軟な環境でGoogle Driveに接続できるようになります。

また、今回のPowerShellのスクリプトを使用して、自動化された処理を実行することができます。これによって、より迅速に反応し、より正確な操作を実行することができます。

最後に、この記事がどなたかのGoogle Drive接続に役立つことを願っています。PowerShellの標準コマンドとGoogle Drive APIを使用することで、より柔軟で生産的な環境でGoogle Cloudに接続することができます。是非、この方法を活用して、より効率的な開発を実現してください。

 


PowerShellとGoogle Drive APIを使ってローカルファイルをGoogle Driveにアップロードしてみた

BACK TO LIST