Googleドライブの共有状況を把握してみよう！

先日非エンジニアの方から
**「Googleドライブの共有状況を把握したい！！」**
と話しているのを発見。

セキュリティの観点から共有状況を知ることは大切だと思います。
特に組織外の人に共有している場合は、しっかり管理しておく必要があります。

**「これしか共有していないつもりだったのに・・・」**

と大切な情報が漏れては大変です。
しっかり管理できるところはやっておきましょう。

# 共有状況を知る方法
共有状況を知る方法が以下の方法があります。

**1. Google ドライブ の標準機能を使う**
**2. Google Workspace（旧名称 G Suite ）を使う**
**3. ツールを使う**

それぞれのメリット・デメリットはこちらのサイトでまとめられています。

https://drivechecker.taf-jp.com/blog/20733


# ツールをGAS使って自作しちゃおう

上記3点の方法を挙げたのですが、個人で作っちゃうのが一番ではないかと結論づけました。
調べてみるとGASを使えば解決なようです。

https://note.com/gas_lab/n/nd3cd953d890b

## 作成方法

### 1. 準備
- Sheet_ID（スプレッドシートのID)
 結果を出力したいスプレッドシートのIDになります。
写真の赤い枠内です※下記のIDは例
![スクリーンショット 2023-09-13 22.20.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/534dc8c6-317a-1938-fe44-badb146abffe.png)
- Drive_ID（共有ドライブのID)
共有状況を確認したいドライブのIDになります。
写真の赤い枠内です※下記のIDは例
![スクリーンショット 2023-09-13 22.24.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/c5981122-ceb1-2594-cb27-87b5114f7d2e.png)
- DriveAPIの有効化
  Google Apps Scriptエディタの左部のサービス[+] をクリックし、Drive API を選択して追加します。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/392d32c8-6e1a-7d19-9cbd-b1833e222a28.png)




### 2. スクリプトに書く
こんな風に書いてみました。

#### 2.1. 変数定義
今回はファイルとフォルダの一覧を取得するため、DATA_TYPEがBOTHとなっています。
ちなみにフォルダのみなら **「FOLDERS」**、ファイルのみなら **「FILES」** となります。

```.gs
const SHEET_ID = 'Sheet_ID'; 
const DRIVE_ID = 'Drive_ID'; 
const SHEET_NAME = 'シート1';
let DATA_TYPE = 'BOTH'; // 'FILES', 'FOLDERS', 'BOTH'

let startTime = new Date().getTime();
const rootFolder = DriveApp.getFolderById(SHARED_DRIVE_ID);
```

#### 2.2. ドライブチェック
```.gs
if (!rootFolder) {
    throw new Error('指定された共有ドライブIDに該当するフォルダが存在しないか、アクセス権限がありません。');
}
```


#### 2.3. 内容チェック
```.gs
function processFolder(folder, folderPath, parentEditors, sheet, sharedDriveMembers) {
    let folderEditors = folder.getEditors().map(user => user.getEmail());
    let combinedEditors = [...new Set([...folderEditors, ...sharedDriveMembers])].join(', ');
    let viewers = folder.getViewers().map(user => user.getEmail()).join(', ');
    viewers = viewers ? viewers : "-";

    if (DATA_TYPE === 'FOLDERS' || DATA_TYPE === 'BOTH') {
        sheet.appendRow([folderPath, folder.getName(), 'フォルダ', folder.getUrl(), combinedEditors, viewers, folder.getAccess(DriveApp.Access.ANYONE) !== DriveApp.Permission.NONE ? '公開中' : '非公開']);
    }

    var files = folder.getFiles();
    while (files.hasNext() && (DATA_TYPE === 'FILES' || DATA_TYPE === 'BOTH')) {
        var file = files.next();
        let fileEditors = file.getEditors().map(user => user.getEmail());
        let combinedFileEditors = [...new Set([...fileEditors, ...sharedDriveMembers])].join(', ');
        let fileViewers = file.getViewers().map(user => user.getEmail()).join(', ');
        fileViewers = fileViewers ? fileViewers : "-";
        sheet.appendRow([folderPath, file.getName(), 'ファイル', file.getUrl(), combinedFileEditors, fileViewers, file.getAccess(DriveApp.Access.ANYONE) !== DriveApp.Permission.NONE ? '公開中' : '非公開']);
    }

    var subFolders = folder.getFolders();
    while (subFolders.hasNext()) {
        var subFolder = subFolders.next();
        var subFolderPath = folderPath + (folderPath === '/' ? '' : '/') + subFolder.getName();
        processFolder(subFolder, subFolderPath, combinedEditors.split(', '), sheet, sharedDriveMembers);
    }
}
```

#### 2.3. 実行
```.gs
function listFilesInSharedDrive() {
    const scriptProperties = PropertiesService.getScriptProperties();
    const lastExecution = scriptProperties.getProperty('last_execution');
    const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(SHEET_NAME);
    const sharedDriveMembers = getSharedDriveMembers(DRIVE_ID).members;

    if (!lastExecution) {
        sheet.clear();
        sheet.appendRow(['共有ドライブ名', getSharedDriveMembers(DRIVE_ID).name]);
        sheet.appendRow(['メンバー', sharedDriveMembers.join(', ')]);
        sheet.appendRow(['', '']);
        sheet.appendRow(['パス', 'ファイル/フォルダ名', 'タイプ', 'URL', '編集権限ユーザー', '閲覧権限ユーザー', '公開状態']);
    }

    const rootFolder = DriveApp.getFolderById(lastExecution || SHARED_DRIVE_ID);
    const rootEditors = rootFolder.getEditors().map(user => user.getEmail());

    processFolder(rootFolder, '/', rootEditors, sheet, sharedDriveMembers);

    sheet.appendRow(["", "処理が完了しました", "", "", "", "", ""]);

    scriptProperties.deleteProperty('last_execution');
}

function getSharedDriveMembers(driveId) {
    const drive = Drive.Drives.get(driveId);
    const permissions = Drive.Permissions.list(driveId, { supportsAllDrives: true });
    const members = permissions.items.map(permission => permission.emailAddress);

    return {
        name: drive.name,
        members: members
    };
}
```
## スクリプト実行
プルダウンからlistFilesSharedDriveを選択し、実行を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/a9276290-7bf0-4de7-f863-394994f0dedc.png)

## 実行結果
下記のように出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/f6f5fa80-9416-bbba-03f5-6546d253ff69.png)

# まずは考えよう
企業が本格的にDX化するには利益の３０％ほどを費やさないといけないそうです。
それはかなりの投資額となってしまいます。
今回のような「Googleドライブの共有状況把握」のためのツールは1000円前後とそれほど高額ではありません。しかし作ってしまえばタダです。
GASはプログラミング初学者でも扱いやすいと思いますし、ぜひ挑戦してみて欲しいです。

ここまでありがとうございました！！