Google Apps Scriptで共有ドライブをコントロールする【GAS】

Google Driveをファイルサーバのように扱える「Team Drive」こと「共有ドライブ」という機能があります。チームやプロジェクト単位で共有するドライブで、誰が見ても同じフォルダ・ファイル構成で、オーナーは特定個人ではなく共有ドライブ自身がオーナーになるため、ファイルサーバから移行がしやすい機能ですね。

さて、この共有ドライブですが、Google Apps Scriptから「作成」やファイルの移動が出来るのですが、これまでのようなDriveAppで単純に操作ができません。使えないわけではないのですが、以上のような共有ドライブの特性上そのままだと一部、操作ができないようになっている為です。

今回のまとめは、Google Apps Scriptから共有ドライブを操作する一連の作業となります。

今回使用するスプレッドシート

2023年にGoogle Apps Scriptにて、Drive API v3が利用可能になりました。大規模な変更はないのですが、細かいところで操作方法に差が出ています。例えばドライブの情報の取得などはデフォルトでv3の場合、最低限しか返ってきません。v3を使う場合の手法については以下を参考に装備が必要です。

Google Apps ScriptでDrive API v3にてファイル情報を取得する

事前準備

Drive APIを有効にする

今回のスクリプトはDrive API v2を利用します。よって、以下の手順に従って、Drive APIをONにする必要性があります。

  1. スクリプトエディター画面に於いて、サービス欄の+記号をクリック
  2. Drive APIを探しだして、選択する
  3. 追加ボタンをクリックする

これでDrive APIがGoogle Apps ScriptでDrive APIを使えるようになります。場合によっては、Cloud Console側でもONにし、プロジェクト番号を紐つける必要性もあります。紐付け作業はこちらのページを参考にしてみてください。

図:Drive APIをオンにした

権限一覧を整備する

共有ドライブにメンバーを追加や権限付与する場合には、スプレッドシートの権限一覧シートに於いてメンバーのメアド、権限を選択して整備する必要があります。この時、権限ですが、以下の通りとなります。

  • organizer : 管理者
  • fileOrganizer : コンテンツ管理者
  • writer : 投稿者
  • commenter : 閲覧者(コメント可)
  • reader : 閲覧者

管理者は複数設定できます。但し、1人に与えられる権限は1個です。

ソースコード

新規作成

  • 共有ドライブを直接作成するコードです。
  • 変数teamDriveには、ドライブのIDなどの情報が返ってきます。
  • ドライブのIDといっても、通常のフォルダと同じで、ドライブ直下のディレクトリのIDと同じです。
  • 名前を指定して作成を実行するだけです。

共有権限一覧取得

  • 対象の共有ドライブ上に設定されている権限(メアドと権限名)を返します。

図:権限の一覧がダイアログで表示される

共有ドライブ一覧

  • 現在用意されている共有ドライブの一覧(名前とID)を返します。

共有ドライブ管理者一覧

  • 対象の共有ドライブに管理者権限を持っている人の一覧を返します。

共有ドライブの設定変更をする

共有ドライブの作成時やあとから設定を一括で変更したい場合に使うメソッドです。右クリック=>共有ドライブの設定で出てくる4つの項目を変更します。

  • Drive.Drives.Updateにて設定を変更します。
  • domainUsersOnlyが「officeforest 外のユーザーにファイルへのアクセスを許可する」の設定になります。
  • driveMembersOnlyが「共有ドライブのメンバー以外のユーザーにファイルへのアクセスを許可する」の設定になります。
  • copyRequiresWriterPermissionが「閲覧者およびコメント可の閲覧者にファイルのダウンロード、印刷、コピーを許可する」の設定になります。
  • sharingFoldersRequiresOrganizerPermissionが「コンテンツ管理者にフォルダの共有を許可する」の設定になります。
  • ただしややこしいのですが、許可するという項目なのにoptionの指定が例えばドメインのメンバーのみという形で指定方法が逆になってるので、true/falseの指定に関しては要注意です。

図:共有ドライブの設定が変更された

共有ドライブに権限付与

共有ドライブへのアクセス権限の新規追加と更新の構文です。削除は後述の「権限の削除」と全く同じ構文になるので、そちらを参照する。

アクセス権限を新規追加

  • 対象の共有ドライブに権限付与・新規メンバーの追加を行います。
  • スプレッドシートの権限一覧シートから設定を行います。

アクセス権限を更新する

  • メールで指定するのではなく、メールからgetIdForEmailでPermissionIdを取得して、これをもって更新を指定する
  • roleに変更するロールを指定する
  • あとはPermission.insertと同じような構文で実行する

共有ドライブの特定フォルダに権限を付与

権限を追加する

前述までは、Drive APIを利用してチームドライブのメンバーとして追加を行っていました。しかし、一部のフォルダに対してだけ外部共有を許可したい場合には、事前に外部共有の設定は必要ですが、DriveAppで外部メンバーを追加する事が可能です。

アップロードを許可するならば投稿者権限が必要ですが、これは通常のマイドライブの「編集者」と同じであるため、以下の構文で追加が可能です。

Google Workspaceで安全に外部とファイルを共有する方法

権限を削除する

ところが、ユーザの削除でremoveEditorをしてみたところ「そんなユーザーは居ない」と怒られたので、こちらはDrive APIを使って削除をしてみます。しかし、Drive APIでの共有権限の削除はユーザのメールアドレスではなく権限リストについてくるpermissionIdというものが必要であるため、少々手間が掛かります。

  • まずは、permission.listで対象のディレクトリの権限一覧を取得
  • ユーザのメアドと一致するデータを見つけたら、idを取得(これがpermissionIdとなる
  • Drive.Permissions.removeで対象の権限を削除する

共有ドライブにファイル作成

  • 通常のドライブと同じく、DriveAppにて新規ファイル作成が可能です。
  • ただし、ファイルのremoveaddは使えません。あくまでも新規作成だけです。

共有ドライブにフォルダコピー

  • これがちょっとややこしく、素直にDriveAppで.addメソッドで行おうとすると失敗します。
  • makeCopyメソッドで複製させます。
  • 移動の場合は、複製後に移動元のファイルをremoveすればOK
  • 今回のメソッドはフォルダ構造維持してまるごとコピーします。

共有ドライブにファイル移動や削除

GASだけで共有ドライブの間でファイルの移動ができるか?といったら答えはNoです。新規に作る分にはDriveAppが使えますが。共有ドライブのファイルの編集自体はDrive APIを介して行う事ができます。

  • この方法では、コピーではなく移動ができています。なので、ファイルのIDが変更されることがありません
  • ファイルの削除も編集作業なので、Drive APIを用いて行います。
  • 共有ドライブ間のファイルの移動も可能です。
  • targetfolderidが移動先のフォルダのID、fileidが移動させるファイルのIDになります。

共有ドライブからフォルダを移動

2022年4月に共有ドライブに対してのフォルダの移動に関して、GUIでは簡単に移動させることができるようになりました。またこれまでDriveAppで使っていたようなフォルダ内部のファイルを移動先に登録し、移動元から削除するといったような冗長的なコードは不要になります。

しかし、2022年当時では共有ドライブのフォルダに対してmoveToで移動を指定すると、エラーが生じるという報告がなされていました。今回コメント欄に同様の話題を頂いたため、改めて以下の設定の通りにし、コードを実行したところ、共有ドライブA⇒共有ドライブBに移動ができました。再帰処理など使用していないので、スクリプトがタイムアウトすることなく処理が可能です。

設定は以下の通りです。

  • 共有ドライブの設定は特にチェックなどをしない
  • 移動を実行するユーザの権限は「管理者」としてる。コンテンツ管理者にも許可する場合は前術の設定で各ロールの権限の「コンテンツ管理者にフォルダの共有を許可する」のチェックが必要
  • 移動元、移動先それぞれは共有ドライブの特定のフォルダのIDを指定する

実行したコードは以下のとおりです。

実際にコードを実行してみましたが、エラーが発生することなく、共有ドライブ間でフォルダを移動することができました。もちろん、フォルダの中身もそのまま移動してるので、タイムアウトなども発生せずに一括で処理が可能です。

ファイルの他のユーザとの共有設定をオンオフ

ファイル共有には「他のユーザとの共有設定」というものがあり、ここのチェックはチェックすると閲覧権限者に対してコピー、ダウンロード、印刷を許可するかどうかという特殊なオプションが働きます。これが有効な場合は閲覧者はコピーやダウンロードが出来るわけです。

このチェックのオンオフを共有ドライブ内のファイルに対して行おうというコードになります。現状の設定を取得して逆のフラグを割り当てるようにしているので、クリックひとつでオンオフ切り替えになります。Drive APIを介して行う事ができます。

  • Drive.Files.Updateの第一引数に変更オプションであるcopyRequiresWriterPermission:trueなどの項目を入れます
  • こちらの動作のチェックは、公式ドキュメント上でも確認が可能です。
  • testという変数にまず、現在のチェックの状態を取得し、それを反転、パーミッション設定変更で割り当てています。
  • 当然、supportsAllDrivesのオプション設定は必要です。

図:この設定を変更したい

共有ドライブのゴミ箱を空にする

通常のマイドライブのゴミ箱は自分自身でゴミ箱を空にすることが可能です。しかし、共有ドライブは自分自身の所有ではなく、このゴミ箱を空にできる人は権限的には「管理者権限」を持つ人だけです。また、共有ドライブは最大50万個という制限があるため、ファイルを捨てて減らそうとしても、ゴミ箱を空に出来ないと、カウントは減ることがありません。

とはいえ、全員に管理者権限を与えてしまうと、あっさり削除されてしまい事故が起きかねません。故にこういった仕様になっています。そこでウェブアプリを作って管理者権限で動かし、管理者権限を持たない一部の人にだけ実行を許可する仕組みを作って自分は対処しています。そのゴミ箱を空にする手法が以下のとおりです。

  • DriveAPIでゴミ箱フラグのついてるものだけをリストアップ
  • driveIdは、共有ドライブを開いた直下のフォルダIDを指します。これを指定する
  • 共有ドライブのゴミ箱はそれぞれの共有ドライブに入ってゴミ箱を開かないと中身が出てこない仕様です。
  • ピックアップして、Drive.Files.removeでゴミ箱を空にしてしまいます。
  • これをウェブアプリで作ったUIから管理者権限で実行し、操作してる人のメアドがスプレッドシートに登録されてる人だったら、関数を実行するように組めば、特定の人だけに使わせる事が可能です。
  • いちいちゴミ箱を空にするために現場の人に管理者権限を与えずに特定の作業だけをこれで許可する事が可能です。

図:これが管理者じゃないと出てこない

Google Apps Scriptでアクセスしてるユーザを元に処理をする方法【GAS】

ファイルの個数を調べたい

Google Apps Scriptで調べる方法

Drive API v2

共有ドライブの制限の1つとして、「1共有ドライブ内のファイルは50万個までのファイルしか格納出来ない」というものがあります。そのため、長い間利用していて制限に達してしまうとファイルを作ったり追加する事ができなくなります。このドライブの使用割合はadminコンソールからは共有ドライブの管理からは残り何%か確認出来ます。

しかし、この割合や現在のドライブのファイル個数は現在スクリプト等からも取得出来ず、Admin SDKDrive API V3Reports APIにも該当のメソッドが存在しません。リクエストは出ているようですが・・・Google Cloud Console上で取得するPythonスクリプトはあるようですが、これでは誰でも確認出来ない。

ということで、力技ですが、以前作成したドライブの探索スクリプトをDrive API V2で実装し直したものを作成しました。

このスクリプトを使うに当たってはいくつかの注意点があります。

  • Drive APIのdrive.files.listは1度に取得できるファイル・フォルダのリストは1000個までなので、pageTokenを使ってループで何度も回す必要があります。
  • quotaに380000を指定してるのは95%に到達でメッセージを出すようにしています。
  • フォルダのみを取り出すqueryとファイルのみを取り出すqueryの2つを使います。サブフォルダまで含めたフォルダのIDの配列を作成するchkFolderList関数を回し、その配列を用いて、ファイルのみを取り出すcountFilesInFolder関数で個数を調べています。
  • 但し、50万個近くあるファイルの場合、ひょっとしたらGASの実行時間制限の6分を超える可能性がある・・・

スマートな手法ではない&時間が掛かる為、複雑なフォルダ構成になってる場合には、フォルダのリストは1度スプレッドシートに出力し、単純に各フォルダIDのファイル個数をカウントする関数に処理を分離して、それぞれを別個に実行するようにするなど、工夫が必要と思います。

Google Apps Scriptで6分の壁(タイムアウト)を突破する - 番外編【GAS】

Google Apps Scriptでファイルフォルダの探索【GAS】

図:ここの値が簡単に取れないという・・・

Drive API v3

Drive API v3がGASで利用できるようになったのでコードを改変してみましたが、基本的な条件は殆ど変わっていないので、6分を超えるテクニック等を使う必要性はあります。10000ファイル調べるのに40秒ほど掛かっているので、10万ファイルで6分を超えてしまいます。

VBAとパソコン版Google Driveを利用する方法

Windowsのパソコン限定ですが、パソコン版Google Driveをインストールし、認証してドライブが見える状態になっている場合には、VBAを利用して対象の共有ドライブ以下のファイルの総数をサブフォルダまで含めて調査することが結構簡単に短時間で行う事が可能です。VBSでも行けるのではないかと。

FileSystemObjectを利用して、サブフォルダまで再帰的にファイル数を取得して最後に数を返すコードになります。こちらのほうが時間の制限も無く、GASで行うよりも短時間で調査が可能で、Excelのシートに共有フォルダのパスをすべて記述しておいて、順番に読み出して調査するといった事ができるため、オススメです。

PC版Google Driveを使う上での注意点

公式に容量リミットのバナーが装備

ようやくというか、2024年3月15日に対象の共有ドライブに対して編集権限を持つ人に対して、ドライブの個数制限400,000個に対して、残が20%以下になった場合に、容量のリミットが来ていることを知らせるバナーが装備されました。

実際どういう表示になるのかはわからないのですが、Business Standard以上に於いて対応しており、これによりリミットが迫ってることをユーザが認識することが可能になります。これまではリミットに達してるのかどうかは管理者画面からしかわからず、達してる場合にファイルを追加アップしてもエラーとなるだけで、リミットに達してるかどうかはわからないという状態でしたので、情シスへの問い合わせもこれで減るのではないかと思います。

共有ドライブを削除する

共有ドライブはもちろんフォルダIDを与えられてはいるものの、特殊なフォルダ扱いであるため簡単には削除が出来ません。例えば手動で削除するにしても

  • 共有ドライブ内のファイルは全て空にしておく必要性がある
  • ごみ箱に移動したファイルについても同様に空にしておく必要がある

といったように、ファイルを一切残していない状態でなければ削除が出来ません。故にDriveAppなどでフォルダとして削除が出来ないのですが、Drive APIを用いた場合は、ファイルがある状態であっても一発でドライブ毎削除が可能です(それゆえに運用は慎重に行わないと本当に消えます)

  • allowItemDeletionをTrueにすることで、ファイルがある状態でもドライブを削除が可能
  • 但し、このオプションを有効にするにはuseDomainAdminAccessもTrueにする必要性があるので管理者権限が必要です。
  • ドライブのIDを指定して実行すれば即時に削除されますので、別途ファイルやフォルダの削除、ゴミ箱を空にするコードは不要です。

尚、以前使っていたファイルやフォルダを全部きれいにゴミ箱行きにするコードは以下のものです。参考までに。

関連リンク

Google Apps Scriptで共有ドライブをコントロールする【GAS】” に対して8件のコメントがあります。

  1. hajimechan より:

    チームドライブ内の特定のフォルダから、チームドライブ内の別のフォルダに、
    特定のスプレッドシートを移動させることは可能でしょうか。

    1. akanemaru2017 より:

      記事に、チームドライブ内のファイルの削除およびチームドライブ間ファイルの移動のコードを追加しておきました。
      こちらもDriveAppでは操作ができません。Drive APIを利用する事になります。

      1. hajimechan より:

        ありがとうございます!試してみます。

      2. hajimechan より:

        試したところ、成功しました。ありがとうございます。

        ただ、Drive APIを有効にする部分もGAS内で済ませたく「UrlFetchApp」を使って認証させようとしたのですが、うまくいかず困ってます。

        GASのスクリプトからDrive APIを有効化させることは可能でしょうか?

        1. akanemaru2017 より:

          Cloud Console側は、コードを記述するだけでDrive APIは有効になるようです。ですが、GAS側は手動で行わないと出来ないようです。
          https://qiita.com/tanaike/items/1d49f73ab05403d0fe4c

          ですが、Drive APIは様式さえ守れば、色々なアプリからHTTP通信で叩けるので、以下のサイトのようにUrlFetchAppにて直接APIを叩くことで同様のことは実現できます。
          ただし、コードがかなり冗長にはなるかと思います。
          https://stackoverflow.com/questions/48310761/how-to-make-a-drive-api-batch-request-with-urlfetchapp-in-google-apps-script

  2. tichikawa より:

    参考にさせてもらって助かりました。
    ところで自分の環境では権限の中に permission.deleted が trueなものがあって、
    それを除いて取得する必要がありました。

    あと、共有ドライブの『設定』は
    teamDrive.restrictions.xxx で見えるものっぽいですが、
    Drive.Drives.list({~, fields:’*’ }) とかも付けておかないと取れないもののようですね。

  3. 片山朋子 より:

    大変参考にさせていただいています。

    共有ドライブのファイルを特定の共有ファイルに異動させることは、記載いただいているソースで可能なようですが、
    共有ドライブの特定フォルダ(下層フォルダまで)を別の共有ドライブの特定のフォルダに移動することは、まだできないのでしょうか?
    下記ソース(1部です、フォルダ移動の部分のみ抜粋)で、私のソースに間違いがある可能性も多々ありですが、このmoveFolderで下記エラーとなります。
    Exception: 共有ドライブ アイテムではこの操作を利用できません。
    id:移動元フォルダID
    dstFoldername:移動先フォルダ名
    dstFolderID:移動先フォルダID
    moveFolder(id, dstFolderName,dstFolderID) {
    const folder = DriveApp.getFolderById(id);//移動元フォルダー
    let dstFolder;

    if (dstFolderName === “”) {
    Logger.log(“エラーdstFolderName=”+dstFolderName);
    } else {
    if (checkFolderExists(dstFolderID, dstFolderName) ) {
    // dstFolder = DriveApp.getFoldersById(dstFolderID).next();
    dstFolder = DriveApp.getFolderById(dstFolderID);
    } else {
    //dstFolder = DriveApp.createFolder(dstFolderName);
    Logger.log(“エラーdstFolderName=”+dstFolderName);
    Logger.log(“エラーid=”+dstFolderID);
    }
    }

    folder.moveTo(dstFolder);
    const resultStr = 【成功】移動先フォルダURL:${dstFolder.getUrl()};
    return resultStr;
    }

    //共有ドライブ内検索
    function checkFolderExists(driveId, folderName) {
    var folders = DriveApp.getFolderById(driveId).getFolders();
    while (folders.hasNext()) {
    var folder = folders.next();
    if (folder.getName() === folderName) {
    return true;
    }
    }
    return false;
    }
    ————————————————-
    今直近でやろうとしている、移動元の共有ドライブと移動先の共有ドライブのアクセス権限は
    同じです。

    これで、実行すると
    Exception: 共有ドライブ アイテムではこの操作を利用できません。となります。

    1. officeの杜 より:

      Issue Trackerを検索してみたところ、moveToでの移動に関してはバグがあり、以前は共有ドライブの場合はフォルダの移動ができないようです。
      https://issuetracker.google.com/issues/163080678

      しかし、実際に検証してコードと説明を「共有ドライブからフォルダを移動」に追加しましたが、こちらのコードでは問題なく移動することができました。
      対象の共有ドライブに対して、コードを実行するユーザの権限が管理者もしくは許可を与えた状態のコンテンツ管理者であるならば移動ができると思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)