Googleドライブ

Googleドライブ共有 相手がアカウントなし問題をGASで解決!コピペで作るファイル送受信システム

ファイル共有
t.inoue

「この資料、メールで送るには重すぎるな…」

「取引先にファイルを送りたいけど、Googleアカウント持ってないって言われちゃった…」

私たちのような小さな町工場では、こんな「ファイル共有」の悩み、日常茶飯事ですよね。無料のファイル転送サービスを使うのも、毎回広告が出たり、相手に使い方を説明したりと、地味に面倒…。

もし、自社専用の「ファイル送受信ボックス」のようなものが、誰でも簡単に、しかも安全に使えたら…?

実は、いつも使っているGoogle Workspace、その中でもGoogle Apps Script(GAS)という機能を使えば、そんな夢のようなシステムを自分で作れてしまうんです!

この記事では、PCが苦手な方でも大丈夫なように、コピペだけで完成する「Googleアカウント不要のファイル共有システム」の作り方を、手順を追って丁寧に解説します。合わせて、Googleアカウントを持っている相手とのスマートな共有方法もご紹介するので、もうファイル共有で悩むことはありません。

さあ、面倒なファイル授受作業を、気持ちいいくらいの快感に変えていきましょう!

なぜ?Googleアカウント不要のファイル共有システムが必要なのか

そもそも、なぜ専用のシステムが必要なのでしょうか?理由は3つあります。

取引先のITスキルは様々だから

私たちの取引先が、みんなITに詳しいわけではありません。

「Googleアカウントって何?」と言われてしまうこともありますよね。そんな相手に「アカウント作ってください」とは、なかな言いにくいものです。相手を選ばないシステムは、円滑な関係を築く上で欠かせません。

メール添付や無料ツールの限界

大容量ファイルをメールで送るのはマナー違反ですし、そもそも送れません。

かといって、無料のファイル転送サービスは、セキュリティは大丈夫?と不安になったり、ダウンロード期限が短すぎたりと、何かと不便を感じることが多いのが現実です。

「ちゃんとしてる感」は信頼に繋がる

自社専用のURLからファイルをアップロードしてもらう仕組みは、相手に「この会社はしっかりしているな」という安心感と信頼感を与えます。

これも、小さな町工場が生き抜くための大切なブランディングの一つです。

まずは基本!Googleアカウントを持つ相手とのスマートな共有方法

本題に入る前に、まずは基本のおさらいです。もし、共有したい相手がGoogleアカウントを持っているなら、Googleドライブの標準機能を使うのが一番手軽で安全です。

方法1:特定のユーザーとフォルダを共有する(一番安全!)

これは、決まった相手とだけファイルを共有したい場合に最適な方法です。

Googleドライブで共有したいフォルダを右クリックし、「共有」を選択
Googleドライブ 共有設定
「ユーザーやグループを追加」の欄に、相手のGoogleアカウント(Gmailアドレスなど)を入力
Googleドライブ 共有設定
相手の権限を「閲覧者」「閲覧者(コメント可)」「編集者」から選択。ファイルをアップロードしてもらいたい場合は「編集者」に設定。
Googleドライブ 共有設定
「送信」をクリックすれば完了です。相手に通知メールが届き、そのフォルダが共有されます。
Googleドライブ 共有設定

この方法なら、指定した人以外は絶対にアクセスできないので、セキュリティは万全です。

方法2:「リンクを知っている全員」と共有する

不特定多数の人にファイルを見てもらいたい、ダウンロードだけしてもらいたい、という場合に便利な方法です。

方法1 と同様に共有したいフォルダやファイルを右クリックし、「共有」を選択
Googleドライブ 共有設定
「一般的なアクセス」の項目を「制限付き」から「リンクを知っている全員」に変更
Googleドライブ 共有設定
権限が「閲覧者」になっていることを確認し、「リンクをコピー」して相手に伝えます
Googleドライブ 共有設定

ただし、この方法はリンクさえ知っていれば誰でもアクセスできてしまうため、機密性の高い情報の共有には向いていません。あくまで、公開しても問題ない資料の配布などに使いましょう。

本日の主役!GASで作る「アカウント不要・双方向」ファイル共有システム

お待たせしました!ここからが本番です。 これから作るのは、Googleアカウントを持っていない相手とも、安全にファイルのアップロード・ダウンロードが双方向でできる、夢のようなWebシステムです。

完成すると、こんな専用ページが出来上がります。

ウェブアプリ完成形

このURLにアクセスすれば、誰でも直感的にファイルを操作できるんです。

このシステムでできること

  • アカウント不要: 取引先はURLにアクセスするだけ。
  • 双方向: こちらからの送付、相手からの受取、両方に対応。
  • 簡単操作: ドラッグ&ドロップでファイルをアップロード可能。
  • 一括処理: 複数のファイルをまとめてダウンロード(ZIP化)&削除。

難しそうに聞こえるかもしれませんが、大丈夫。ここから先の3ステップを真似するだけで、あなたの会社にもこのシステムが導入できます!

初心者でも安心!コピペでOK!システム構築の3ステップ

さあ、実際に手を動かして作っていきましょう!

まずは説明の通りにやってみて下さい。名称を変えたい場合は、Geminiにコードを投げて修正してもらえば良いので。

ステップ1:Googleドライブに専用フォルダを準備しよう

まずは、ファイルの保管場所となるフォルダをGoogleドライブに作成します。

Googleドライブに、このシステムの「親」となるフォルダを一つ作成
Googleドライブに、このシステムの「親」となるフォルダを一つ作成
作成した親フォルダの中に、ファイルをアップロードするためのフォルダを2つ作成
作成した親フォルダの中に、ファイルをアップロードするためのフォルダを2つ作成

※このフォルダ名はサンプルです。分かりやすければ何でもOK!

作成した2つのフォルダの「フォルダID」をコピー

フォルダIDは、フォルダを開いたときのURLの末尾にある、ランダムな英数字の羅列です。 https://drive.google.com/drive/folders/ここに表示されているのがフォルダID

この2つのフォルダIDは後で使うので、メモ帳などに貼り付けておきましょう。

アップロードするフォルダの共有設定を変更
アップロードするフォルダの共有設定を変更

相手がこちらのフォルダへアクセスすることになりますので、共有設定を「リンクを知っている全員」「編集者」へ変更しておきます。

ステップ2:Google Apps Scriptにコードを貼り付けよう

次に、システムの心臓部となるプログラムを設置します。

Googleドライブから「+ 新規」をクリック

「その他」→「Google Apps Script」を選択します。

Google Apps Scriptが開くので名前を変更
Google Apps Scriptが開くので名前を変更

赤枠部分をクリックして分かりやすい名前に変更しておきます。

コード.gsファイルにコードを入力

  • 元々書いてあるコードは消してしまって以下のコードをコピペします。

/**
 * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
 * ★ 設定項目:ご自身のGoogleドライブのフォルダIDに合わせて設定してください ★
 * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
 */
const FOLDER_IDS = {
  自社アップロード: "自社用フォルダIDを貼り付け", 
  山田様アップロード: "相手用フォルダIDを貼り付け" 
};

const TEMP_FOLDER_NAME = "WebApp_Temp_Zips";

/**
 * Webアプリにアクセスしたときに最初に実行される関数
 */
function doGet(e) {
  if (e.parameter.download && e.parameter.fileId) {
    try {
      const file = DriveApp.getFileById(e.parameter.fileId);
      const targetId = file.getTargetId();
      const actualFile = targetId ? DriveApp.getFileById(targetId) : file;
      const blob = actualFile.getBlob();
      const fileName = actualFile.getName();
      const base64Data = Utilities.base64Encode(blob.getBytes());
      const dataUrl = `data:${blob.getContentType()};base64,${base64Data}`;
      const html = `
        <!DOCTYPE html><html><head><title>Downloading...</title><style>body { font-family: sans-serif; text-align: center; padding-top: 50px; }</style></head>
        <body><p>ダウンロードが開始されました。</p><p>このタブは自動的に閉じられます。閉じない場合は手動で閉じてください。</p>
          <a id="dl" href="${dataUrl}" download="${fileName}" style="display:none;"></a>
          <script>document.getElementById('dl').click(); setTimeout(function(){ window.close(); }, 1000);</script>
        </body></html>`;
      return HtmlService.createHtmlOutput(html);
    } catch (err) {
      return ContentService.createTextOutput(`ファイルのダウンロードに失敗しました。ファイルサイズが50MBを超えている可能性があります。エラー詳細: ${err.message}`);
    }
  }
  return HtmlService.createTemplateFromFile('index').evaluate().setTitle('ファイル共有システム').addMetaTag('viewport', 'width=device-width, initial-scale-1');
}

/**
 * 指定された会社のフォルダ内にあるファイルリストを取得する関数
 */
function getFileList(company) {
  try {
    const folderIdToList = company === '自社' ? FOLDER_IDS.山田様アップロード : FOLDER_IDS.自社アップロード;
    const folder = DriveApp.getFolderById(folderIdToList);
    const files = folder.getFiles();
    const fileList = [];
    while (files.hasNext()) {
      let file = files.next();
      const targetId = file.getTargetId();
      let originalFile = file;
      let fileName = file.getName();
      let fileIdForAction = file.getId();
      if(targetId){
        try {
          originalFile = DriveApp.getFileById(targetId);
          fileName = originalFile.getName();
        } catch(e) {
          fileName = file.getName() + " (リンク先不明)";
          fileList.push({ name: fileName, id: fileIdForAction, size: 0, url: '#' });
          continue;
        }
      }
      fileList.push({
        name: fileName,
        id: fileIdForAction,
        size: originalFile.getSize(),
        url: originalFile.getUrl()
      });
    }
    return fileList.sort((a, b) => a.name.localeCompare(b.name));
  } catch (e) {
    return `エラー: ${e.message}`;
  }
}

/**
 * ファイルをGoogleドライブにアップロードする関数
 */
function uploadFile(data, fileName, mimeType, uploaderCompany) {
  try {
    const destinationFolderId = uploaderCompany === '自社' ? FOLDER_IDS.自社アップロード : FOLDER_IDS.山田様アップロード;
    const decodedData = Utilities.base64Decode(data.split(',')[1]);
    const blob = Utilities.newBlob(decodedData, mimeType, fileName);
    const folder = DriveApp.getFolderById(destinationFolderId);
    folder.createFile(blob);
    return "アップロードが完了しました。";
  } catch (e) {
    return `アップロードに失敗しました: ${e.message}`;
  }
}

/**
 * ファイルのダウンロード用URLを生成する関数
 */
function getDownloadUrl(fileId) {
  const webAppUrl = ScriptApp.getService().getUrl();
  return `${webAppUrl}?download=true&fileId=${fileId}`;
}

/**
 * 指定されたIDのファイルをゴミ箱に移動する関数
 */
function deleteFiles(fileIds) {
  try {
    if (!fileIds || fileIds.length === 0) { return "ファイルが選択されていません。"; }
    let deletedCount = 0;
    fileIds.forEach(id => { DriveApp.getFileById(id).setTrashed(true); deletedCount++; });
    return `${deletedCount}個のファイルを削除しました。`;
  } catch (e) {
    return `削除中にエラーが発生しました: ${e.message}`;
  }
}

/**
 * 複数のファイルをZIP形式に圧縮し、一時フォルダに保存してそのIDを返す関数
 */
function createZipAndReturnId(fileIds) {
  try {
    if (!fileIds || fileIds.length === 0) { return "ファイルが選択されていません。"; }
    const parentFolder = DriveApp.getFolderById(FOLDER_IDS.自社アップロード);
    let tempFolders = parentFolder.getFoldersByName(TEMP_FOLDER_NAME);
    const tempFolder = tempFolders.hasNext() ? tempFolders.next() : parentFolder.createFolder(TEMP_FOLDER_NAME);
    const blobs = fileIds.map(id => {
      const file = DriveApp.getFileById(id);
      const targetId = file.getTargetId();
      const actualFile = targetId ? DriveApp.getFileById(targetId) : file;
      return actualFile.getBlob();
    });
    const zipName = `download_${new Date().getTime()}.zip`;
    const zipBlob = Utilities.zip(blobs, zipName);
    const zipFile = tempFolder.createFile(zipBlob);
    const oldFiles = tempFolder.getFiles();
    while(oldFiles.hasNext()){
      const file = oldFiles.next();
      if(new Date().getTime() - file.getDateCreated().getTime() > 60 * 60 * 1000){ file.setTrashed(true); }
    }
    return zipFile.getId();
  } catch (e) {
    return `ZIPファイルの作成に失敗しました: ${e.message}`;
  }
}

※◯◯様という文字は扱えないので山田様へ変更してます。

 重要ポイント

貼り付けたコードの7行目と8行目にある FOLDER_IDS"" の中に、先ほどステップ1でコピーした2つのフォルダIDをそれぞれ貼り付けてください。

名前もフォルダ名に修正しておくと分かりやすいです。

画面左側の「ファイル」の横にある「+」アイコンをクリックし、「HTML」を選択

ファイル名を「index」として作成し、生成されたファイルに以下のコードを全てコピーして貼り付けます。

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      :root {
        --primary-color: #3498DB;
        --primary-hover-color: #2E86C1;
        --danger-color: #E74C3C;
        --danger-hover-color: #D34231;
        --success-color: #48C9B0;
        --success-hover-color: #40B5A0;
        --light-gray-color: #F3F3F3;
        --medium-gray-color: #E1E1E1;
        --dark-gray-color: #333333;
        --font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
      }
      body { font-family: var(--font-family); margin: 0; background-color: var(--light-gray-color); display: flex; align-items: center; justify-content: center; min-height: 100vh; color: var(--dark-gray-color); }
      .container { max-width: 800px; width: 100%; margin: 20px; background-color: #fff; padding: 40px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); box-sizing: border-box; }
      h1 { font-size: 28px; font-weight: 600; margin-top: 0; }
      h2 { font-size: 20px; font-weight: 600; border-bottom: 1px solid var(--medium-gray-color); padding-bottom: 10px; margin-top: 30px;}
      button, .button-link { border: none; border-radius: 5px; cursor: pointer; font-size: 16px; font-weight: 600; margin: 5px; padding: 12px 24px; text-align: center; text-decoration: none; transition: all 0.2s ease-in-out; display: inline-block; color: white; }
      .button-primary { background-color: var(--primary-color); }
      .button-primary:hover { background-color: var(--primary-hover-color); transform: translateY(-1px); }
      .button-primary:disabled { background-color: #BDBDBD; cursor: not-allowed; transform: none; }
      .app-header { display: flex; justify-content: space-between; align-items: center; }
      .back-button { display: inline-block; text-decoration: none; font-size: 14px; padding: 8px 15px; background-color: #6c757d; color: white; border-radius: 4px; border: none; cursor: pointer; }
      .back-button:hover { background-color: #5a6268; }
      #company-selection { text-align: center; padding: 40px 0; }
      #company-selection button { padding: 20px 40px; font-size: 20px; }
      #app-container { display: none; }
      #upload-form { margin-bottom: 30px; padding: 30px; border: 2px dashed var(--medium-gray-color); border-radius: 8px; text-align: center; transition: all 0.2s ease-in-out; }
      #upload-form.dragover { background-color: #E9F5FF; border-color: var(--primary-color); }
      input[type="file"] { display: none; }
      .file-list-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; flex-wrap: wrap; }
      .bulk-actions button { font-size: 14px; padding: 8px 15px; background-color: var(--primary-color); }
      #bulk-delete { background-color: var(--danger-color); }
      #bulk-delete:hover { background-color: var(--danger-hover-color); }
      #file-list { list-style-type: none; padding: 0; margin-top: 20px; }
      #file-list li { background-color: white; border: 1px solid var(--medium-gray-color); padding: 15px; margin-bottom: 10px; border-radius: 5px; display: flex; align-items: center; word-break: break-all; transition: all 0.2s ease-in-out; }
      #file-list li:hover { border-color: var(--primary-color); box-shadow: 0 2px 5px rgba(0,0,0,0.05); }
      .file-checkbox { margin-right: 15px; transform: scale(1.2); }
      .file-name { flex-grow: 1; margin-right: 10px; }
      .button-group { display: flex; gap: 8px; flex-shrink: 0; }
      .download-link { background-color: var(--success-color); font-size: 14px; padding: 8px 15px; }
      .download-link:hover { background-color: var(--success-hover-color); }
      .delete-button { background-color: var(--danger-color); font-size: 14px; padding: 8px 15px; }
      .delete-button:hover { background-color: var(--danger-hover-color); }
      #status { margin-top: 15px; font-weight: 500; }
    </style>
  </head>
  <body>
    <div class="container">
      <div id="company-selection"><h1>ファイル共有システム</h1><p>どちらの会社として利用しますか?</p><button class="button-primary" onclick="selectCompany('自社')">自社</button><button class="button-primary" onclick="selectCompany('山田様')">山田様</button></div>
      <div id="app-container">
        <div class="app-header"><h1 id="welcome-message"></h1><a href="<?!= ScriptApp.getService().getUrl() ?>" class="back-button button-link">ホーム画面に戻る</a></div>
        <div id="upload-form"><h2>ファイルをアップロード</h2><p>ファイルをここにドラッグ&ドロップするか、下のボタンをクリックしてください。</p><input type="file" id="file-input" multiple onchange="handleFileSelect(this.files)"><button class="button-primary" onclick="document.getElementById('file-input').click()">ファイルを選択</button><div id="status"></div></div>
        <div id="file-list-container"><div class="file-list-header"><h2>受信ファイル一覧</h2><div class="bulk-actions"><button onclick="handleBulkDownload()">選択をダウンロード</button><button id="bulk-delete" onclick="handleBulkDelete()">選択を削除</button></div></div>
          <div><input type="checkbox" id="select-all" onclick="toggleAllCheckboxes(this.checked)"> <label for="select-all">すべて選択</label></div>
          <ul id="file-list"></ul>
        </div>
      </div>
    </div>
    <script>
      let currentCompany = null;
      let currentFiles = [];
      const webAppUrl = "<?!= ScriptApp.getService().getUrl() ?>";
      const MAX_DOWNLOAD_SIZE = 50 * 1024 * 1024;

      const uploadForm = document.getElementById('upload-form');
      uploadForm.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); uploadForm.classList.add('dragover'); });
      uploadForm.addEventListener('dragleave', (e) => { e.preventDefault(); e.stopPropagation(); uploadForm.classList.remove('dragover'); });
      uploadForm.addEventListener('drop', (e) => { e.preventDefault(); e.stopPropagation(); uploadForm.classList.remove('dragover'); handleFileSelect(e.dataTransfer.files); });

      function formatBytes(bytes, decimals = 2) {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const dm = decimals < 0 ? 0 : decimals;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
      }

      function showFiles(files) {
        if (typeof files === 'string') { alert(files); return; }
        currentFiles = files;
        const list = document.getElementById('file-list');
        list.innerHTML = "";
        document.getElementById('select-all').checked = false;
        if (files.length > 0) {
          files.forEach(file => {
            const li = document.createElement('li');
            const fileSizeFormatted = formatBytes(file.size);
            let actionButtonHtml = '';
            if (file.size > MAX_DOWNLOAD_SIZE) {
              actionButtonHtml = `<a href="${file.url}" target="_blank" class="download-link button-link" title="ファイルサイズが50MBを超過しているため、Googleドライブで開きます">ドライブで開く</a>`;
            } else {
              const downloadUrl = `${webAppUrl}?download=true&fileId=${file.id}`;
              actionButtonHtml = `<a href="${downloadUrl}" target="_blank" class="download-link button-link">ダウンロード</a>`;
            }
            li.innerHTML = `
              <input type="checkbox" class="file-checkbox" data-file-id="${file.id}">
              <span class="file-name">${file.name} (${fileSizeFormatted})</span>
              <div class="button-group">
                ${actionButtonHtml}
                <button class="delete-button" onclick="handleDelete('${file.id}', '${file.name}')">削除</button>
              </div>`;
            list.appendChild(li);
          });
        } else {
          list.innerHTML = '<li>受信したファイルはありません。</li>';
        }
      }

      function handleFileSelect(files) { if (files.length > 0) Array.from(files).forEach(file => handleUpload(file)); }
      
      function handleUpload(file) {
        if (!file) return;
        const statusDiv = document.getElementById('status');
        statusDiv.innerHTML += `<p>${file.name}: アップロード中...</p>`;
        const reader = new FileReader();
        reader.onload = (e) => {
          google.script.run.withSuccessHandler((response) => {
            statusDiv.innerHTML = `<p>${file.name}: ${response}</p>`;
            loadFiles();
          }).uploadFile(e.target.result, file.name, file.type, currentCompany);
        };
        reader.readAsDataURL(file);
      }
      
      function handleDelete(fileId, fileName) { if (confirm(`本当に「${fileName}」を削除しますか?`)) { google.script.run.withSuccessHandler(alertAndReload).deleteFiles([fileId]); } }
      function toggleAllCheckboxes(checked) { document.querySelectorAll('.file-checkbox').forEach(cb => cb.checked = checked); }
      function getSelectedFileIds() { return Array.from(document.querySelectorAll('.file-checkbox:checked')).map(cb => cb.dataset.fileId); }
      
      function handleBulkDelete() {
        const ids = getSelectedFileIds();
        if (ids.length === 0) { alert('ファイルを選択してください。'); return; }
        if (confirm(`${ids.length}個のファイルを本当に削除しますか?`)) { google.script.run.withSuccessHandler(alertAndReload).deleteFiles(ids); }
      }

      function handleBulkDownload() {
        const ids = getSelectedFileIds();
        if (ids.length === 0) { alert('ファイルを選択してください。'); return; }
        let hasLargeFile = false;
        let largeFileNames = [];
        ids.forEach(id => {
          const file = currentFiles.find(f => f.id === id);
          if (file && file.size > MAX_DOWNLOAD_SIZE) {
            hasLargeFile = true;
            largeFileNames.push(file.name);
          }
        });
        if (hasLargeFile) {
          alert(`サイズが50MBを超えるファイルは一括ダウンロードに含めることができません。\n以下のファイルは個別に「ドライブで開く」からダウンロードしてください。\n\n- ${largeFileNames.join('\n- ')}`);
          return;
        }
        const statusDiv = document.getElementById('status');
        statusDiv.textContent = 'ZIPファイルを準備中です...';
        google.script.run.withSuccessHandler((zipFileId) => {
          statusDiv.textContent = '';
          if (zipFileId && !String(zipFileId).includes('失敗')) {
            const downloadUrl = `${webAppUrl}?download=true&fileId=${zipFileId}`;
            window.open(downloadUrl, '_blank');
            statusDiv.textContent = 'ダウンロードを開始しました。';
          } else {
            alert(zipFileId);
          }
        }).createZipAndReturnId(ids);
      }

      function alertAndReload(response) { alert(response); loadFiles(); }

      function selectCompany(company) {
        currentCompany = company;
        document.getElementById('company-selection').style.display = 'none';
        document.getElementById('app-container').style.display = 'block';
        document.getElementById('welcome-message').textContent = `${company} として利用中`;
        loadFiles();
      };
      
      function loadFiles() {
        document.getElementById('file-list').innerHTML = '<li>読み込み中...</li>';
        google.script.run.withSuccessHandler(showFiles).getFileList(currentCompany);
      };
    </script>
  </body>
</html>
最後に、画面上部のフロッピーディスクのアイコン「プロジェクトを保存」をクリック
画面上部のフロッピーディスクのアイコン「プロジェクトを保存」をクリック

コードの入力方法についてはこちらの記事を参考にして下さい ↓

参考記事
GASの入力方法を3ステップで解説!Geminiに聞けばコード知識ゼロでOK
GASの入力方法を3ステップで解説!Geminiに聞けばコード知識ゼロでOK
AI活用ポイント

もしコードをカスタマイズしたくなったら? 「ファイル名に日付を自動で付けたいな…」「デザインの色を変えたいな…」 もしそんな風に思ったら、AIアシスタントのGeminiに相談してみましょう!

例えば、こんな風に質問します。 「このGoogle Apps Scriptコードを修正して、アップロードされたファイル名の先頭にYYYY-MM-DD形式の日付を自動で追加する機能を追加してください。」

これだけで、Geminiが修正案を提示してくれます。プログラミングが分からなくても、頼れる相棒がいれば安心して機能追加に挑戦できますよ!

    ステップ3:Webアプリとしてデプロイ(公開)しよう

    いよいよ最終ステップです!作成したプログラムを、インターネット上で使えるように「公開(デプロイ)」します。

    デプロイ→新しいデプロイをクリック
    デプロイ→新しいデプロイをクリック

    Apps Scriptエディタの右上にある青い「デプロイ」ボタンをクリックし、「新しいデプロイ」を選択します。

    設定から「ウェブアプリ」を選択
    設定から「ウェブアプリ」を選択

    歯車のアイコンの横にある「種類の選択」をクリックし、「ウェブアプリ」を選択します。

    設定を変更

    設定を以下のように変更します。

    • 説明: (空欄でOK、または分かりやすい説明を記入)
    • 次のユーザーとしてアプリを実行:自分
    • アクセスできるユーザー:全員
    「デプロイ」ボタンをクリック
    「デプロイ」ボタンをクリック
    ウェブアプリのリンクが発行されるのでコピーして相手にお知らせ
    ウェブアプリのリンクが発行されるのでコピーして相手にお知らせ

    初回のみ、「アクセスの承認」を求められます。画面の指示に従い、自分のGoogleアカウントを選択し、「許可」をクリックしてください。

    • 「このアプリはGoogleで確認されていません」 という警告画面が表示されることがあります。これは自作のプログラムでは必ず表示されるものなので、心配はいりません。「詳細」をクリックし、画面下部の「(プロジェクト名)に移動(安全でないページ)」を選択して進んでください。
    動作確認のためシークレットモードで開いてみる
    動作確認のためシークレットモードで開いてみる

    何もログインしていない状態で動作確認をしたいので、GoogleChromeの右上の「︙」から「新しいシークレットウインドウ」をクリックしてシークレット状態にします。

    そして先ほどのウェブアプリのURL入力して入ってみると・・・

    ウェブアプリ ホーム画面

    見事、ウェブアプリのホーム画面が開きました。

    動作確認なので相手側から入ってファイルを保存したりしてきちんとアップロードできるか確認してみましょう。

    あとはこのURLを取引先に共有すれば、すぐにでもファイルのやり取りを開始できます。ブックマークしておきましょう!

    Geminiに聞いてみた!このシステムをさらに便利にするアイデア

    Geminiに聞いてみた!このシステムをさらに便利にするアイデア

    せっかくなので、AIアシスタントのGeminiに、このシステムをさらにパワーアップさせるアイデアを聞いてみました。

    私: 「このファイル共有システムに、ファイルがアップロードされたらGoogle Chatに通知を送る機能を追加したいんだけど、どうすればいい?」

    Gemini: 「お任せください!uploadFile関数の最後に、Google ChatのWebhook URLへ通知を送るコードを追加すれば実現できますよ。こちらがサンプルコードです。」

    // (Geminiが提案したサンプルコード)
    function sendToGoogleChat(fileName, uploaderCompany) {
      const webhookUrl = 'ここにあなたのGoogle ChatのWebhook URLを貼り付け';
      const message = {
        'text': `${uploaderCompany} からファイルがアップロードされました!\nファイル名: ${fileName}`
      };
      const options = {
        'method': 'post',
        'contentType': 'application/json',
        'payload': JSON.stringify(message)
      };
      UrlFetchApp.fetch(webhookUrl, options);
    }

    すごいですよね!こんな風にAIと対話しながら、システムをどんどん自社仕様に育てていくことができるんです。これぞ、小さな町工場のDX化の醍醐味です! (※Webhook URLの取得方法は、こちらのGoogle公式ヘルプなどを参考にしてください。)

    まとめ:小さな一歩が、未来の余裕を生み出す

    GASを使った「アカウント不要のファイル共有システム」イメージ画像

    今回は、Googleアカウントを持っている相手との基本的な共有方法から、GASを使った「アカウント不要のファイル共有システム」の構築まで、幅広くご紹介しました。

    一見、難しそうに見えたかもしれませんが、一つ一つのステップは単純な作業だったはずです。このシステム一つで、日々の面倒なファイル授受の手間がなくなり、セキュリティの心配からも解放されます。

    そうして生まれた「時間の余裕」は、新しい技術の習得や、もっと創造的な仕事に挑戦するための大切な原動力になります。

    まずはこの記事を参考に、あなたの会社だけのファイル共有システムを構築してみてください。そして、もし何か困ったり、もっと良くしたいと思ったら、ぜひGeminiに話しかけてみてください。きっと最高の相棒になってくれますよ。

    あなたの会社のDX化が、今日この瞬間から、楽しく加速していくことを応援しています!

    ABOUT ME
    TAKA社長
    TAKA社長
    Google Workspace見習い
    小さな町工場の社長。 日々業務に追われ何とか打開する策として『Google Workspace』を契約。実際にアナログで手間だった作業の問題事例とDX化で改善していく方法を詳しく紹介していきます。 DX化・システム化とか言ってますが、基本的にはAI(Gemini)任せでお願いしているだけなので作業としてはとても簡単。 ですので、GoogleWorkspaceの各アプリを効率的に使う方法や便利な機能などを理解してもらえば嬉しいです。
    記事URLをコピーしました