2022/09/11に更新

【GASで時短】ファイルの共有権限を別のファイルへコピーする

スプレッドシート小技実験的

ファイルの共有権限を他のファイルと揃えてくれるGoogle Apps Scriptです。権限設定って結構めんどくさいですよね。

こんな悩みを解決します


  • 共有権限の設定がめんどくさい!
  • あのファイルの権限を一発でこのファイルにも適用したい!

用意するもの


特にありません。スプレッドシートのコンテナバインド型プロジェクトとして作りました。

このスクリプトで出来ること


  • ファイルの共有権限(閲覧、編集)をコピーすることができます。
  • コピー元とコピー先のファイルは、プロンプトで指定可能です。
  • 権限変更の実行前に、処理内容を確認することができます。

使い方


1.スクリプトの実行

上のメニューにある「スクリプト実行」から「共有権限をコピーする」を実行します。

権限コピー元のファイルURLが聞かれます。
権限設定済みのファイルURLを入力してください。スプレッドシートに限らず、スライドやドキュメント等でも問題ない(はず)です。

次は権限コピー先のファイルURLを入力してください。

現在の権限付与状況と、これから実施する処理内容が表示されます。
問題がなければOKを押し、しばらく待つと処理が完了します。

2.権限がすでに揃っているとき

コピー元とコピー先ですでに共有権限が一致している場合は「コピー元と先のファイルで、共有権限の差分はありません。処理を中止します。」とメッセージを表示し何もしません。

3.注意点

大量のユーザーに権限が付与されているファイルを用意できず、動作確認が非常に限定的です。業務で使う場合は不要なファイルで検証されることを強くおすすめします。

権限付与の処理を連続して実行すると反映されないケースがあったため、sleep()を挟んでいます。権限を持つユーザーの数によっては時間を延ばす必要があるかもしれません。

スクリプト


/**
 * このスクリプトの説明、使い方はこちら。
 * https://myfunc.jp/items/00143/index.html
 */

function onOpen() {
  // スプレッドシートを開いたときに実行される関数

  // UIの取得
  const ui = SpreadsheetApp.getUi()

  // メニューの表示名
  const menu = ui.createMenu('スクリプト実行');

  // メニューに追加するボタン
  menu.addItem('共有権限をコピーする', 'copy_access_rights');

  // メニューを画面に追加する
  menu.addToUi();
}


function copy_access_rights() {

  // メッセージを表示するためUIオブジェクトを取得
  const ui = SpreadsheetApp.getUi();

  // コピー元のファイルURLを入力するプロンプトを表示
  const prompt1 = ui.prompt('権限コピー「元」のファイルURLを入力してください', '例:https://docs.google.com/spreadsheets/d/************', ui.ButtonSet.OK_CANCEL);

  // キャンセルボタンが押されたら処理を中止
  if (prompt1.getSelectedButton() == ui.Button.CANCEL) {
    return;
  }

  // コピー先のファイルURLを入力するプロンプトを表示
  const prompt2 = ui.prompt('権限コピー「先」のファイルURLを入力してください', '例:https://docs.google.com/spreadsheets/d/************', ui.ButtonSet.OK_CANCEL);

  // キャンセルボタンが押されたら処理を中止
  if (prompt2.getSelectedButton() == ui.Button.CANCEL) {
    return;
  }

  // ファイルのIDを正規表現で取り出す
  const file1_id = prompt1.getResponseText().match(/^https:\/\/.*\/d\/(.*)\/.*$/)[1];
  const file2_id = prompt2.getResponseText().match(/^https:\/\/.*\/d\/(.*)\/.*$/)[1];

  // IDからファイルを取得する
  const file1 = DriveApp.getFileById(file1_id);
  const file2 = DriveApp.getFileById(file2_id);

  // 権限コピー元ファイルの閲覧者、編集者を取得する
  const file1_viewers = file1.getViewers();
  const file1_editors = file1.getEditors();

  // 権限コピー先ファイルの閲覧者、編集者を取得する
  const file2_viewers = file2.getViewers();
  const file2_editors = file2.getEditors();

  // 権限コピー元ファイルの権限保有者メールアドレスを格納する変数
  const file1_viewers_email = [];
  const file1_editors_email = [];

  // 権限コピー先ファイルの権限保有者メールアドレスを格納する変数
  const file2_viewers_email = [];
  const file2_editors_email = [];

  // 権限保有者の数だけ、メールアドレスを取り出す(コピー元の閲覧者)
  for (let i = 0; i < file1_viewers.length; i++) {
    file1_viewers_email.push(file1_viewers[i].getEmail());
  }

  // 権限保有者の数だけ、メールアドレスを取り出す(コピー元の編集者)
  for (let i = 0; i < file1_editors.length; i++) {
    file1_editors_email.push(file1_editors[i].getEmail());
  }

  // 権限保有者の数だけ、メールアドレスを取り出す(コピー先の閲覧者)
  for (let i = 0; i < file2_viewers.length; i++) {
    file2_viewers_email.push(file2_viewers[i].getEmail());
  }

  // 権限保有者の数だけ、メールアドレスを取り出す(コピー先の編集者)
  for (let i = 0; i < file2_editors.length; i++) {
    file2_editors_email.push(file2_editors[i].getEmail());
  }

  // コピー元と先の権限保有者の配列を比較し、追加 or 削除すべきメールアドレスを取り出す
  const viewers_add = file1_viewers_email.filter(i => file2_viewers_email.indexOf(i) == -1);
  const viewers_delete = file2_viewers_email.filter(i => file1_viewers_email.indexOf(i) == -1);

  const editors_add = file1_editors_email.filter(i => file2_editors_email.indexOf(i) == -1);
  const editors_delete = file2_editors_email.filter(i => file1_editors_email.indexOf(i) == -1);

  // 差がない場合は処理する必要がないのでスクリプトを終了する
  if (
    viewers_add.length == 0 &&
    viewers_delete.length == 0 &&
    editors_add.length == 0 &&
    editors_delete.length == 0
  ) {
    ui.alert('コピー元と先のファイルで、共有権限の差分はありません。処理を中止します。')
    return;
  }

  // 実行前の確認メッセージを組み立てる
  let message = `----現在の設定----\n【コピー元】\n閲覧者: ` + file1_viewers_email.join(',') +
    `\n編集者: ` + file1_editors_email.join(',') +
    `\n\n【コピー先】\n閲覧者: ` + file2_viewers_email.join(',') +
    `\n編集者: ` + file2_editors_email.join(',') +
    `\n\n----コピー先への処理内容----\n追加される閲覧権限:` + viewers_add.join(',') +
    `\n削除される閲覧権限:` + viewers_delete.join(',') +
    `\n追加される編集権限:` + editors_add.join(',') +
    `\n削除される編集権限:` + editors_delete.join(',') +
    `\n\n処理を実行してもよろしいですか?`;

  // 実行確認メッセージを表示する
  const confirm = ui.alert('実行の確認', message, ui.ButtonSet.OK_CANCEL);

  // キャンセルが押されたらスクリプトを終了する
  if (confirm == ui.Button.CANCEL) {
    return;
  }

  // 閲覧者の削除を実行する
  for (let i = 0; i < viewers_delete.length; i++) {
    file2.removeViewer(viewers_delete[i]);
  }

  // 権限追加削除が反映されない場合があったので、遅延させる(念の為)
  Utilities.sleep(5000);

  // 編集者の削除を実行する
  for (let i = 0; i < editors_delete.length; i++) {
    file2.removeEditor(editors_delete[i]);
  }
  Utilities.sleep(5000);

  // 閲覧者の追加を実行する
  for (let i = 0; i < viewers_add.length; i++) {
    file2.addViewer(viewers_add[i]);
  }
  Utilities.sleep(5000);

  // 編集者の追加を実行する
  for (let i = 0; i < editors_add.length; i++) {
    file2.addEditor(editors_add[i]);
  }

}

関連するアプリ


タグ一覧

最新のアプリ

人気のアプリ

ページトップに戻る
myfunc.jp