GASでGoogle Driveの共有ドライブと所属ユーザ一の一覧を出力する

## 目的
Gsuite管理者なら、Google Driveの共有ドライブや所属ユーザ一の管理が煩雑になりがちで、管理状況を可視化したい場面は多いと思います。
そこでGASを使って、日次で共有ドライブと所属ユーザ一の一覧をスプレッドシートに出力することにしました。

### 出力イメージ
以下の通り2種類のレイアウトで出力します。

#### ドライブの所属ユーザーと権限を横軸に出力するパターン
横軸にユーザーのアドレスと権限をセットで出力します。ユーザーが多い共有ドライブは少し見辛いですが、1つのセルに1ユーザーを出力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/4dde335e-eb9e-6a1b-6a5b-a9ca94074cdf.png)

#### ドライブの権限ごとのセルにユーザーをまとめて出力するパターン
1つのセルの中に複数ユーザーを出力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/279cc6e1-f732-eb55-dd7c-f2d9887fb797.png)

#### 権限一覧
ユーザーごとに以下の権限を１つ付与できます。
詳細：[共有ドライブのアクセスレベル](https://support.google.com/a/answer/7337554?hl=ja)

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

## 内容

### 事前準備

* GAS実行アカウントを用意し、全ての共有ドライブの管理者として登録する
共有ドライブのユーザの一覧を取得するには対象の共有ドライブの管理者である必要があるので、全ての共有ドライブの管理者にGAS実行アカウントを追加する必要があります。

* Drive APIを有効にする
今回のスクリプトはDrive API v2を利用します。よって、スクリプトエディタの`リソース`の`Googleの拡張サービス`からDrive APIをONにする必要性があります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/386a890b-80b7-69dd-82a4-4fa0bc5ad31d.png" width=60%>


### GASの内容

* ドライブの所属メンバーと権限を横軸に出力するパターン

```js:getDriveUser.gs

var SheetName = "getDriveUser";
activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SheetName)

function getDriveUser() {

  firstStep();
  adminListAllTeamDrives();
  
}

function firstStep(sheetName) {

  //初期化する 
  activeSheet.clear();

  activeSheet.getRange(1, 1).setValue("ドライブ名")
  activeSheet.getRange(1, 1).setBackground("#7169e5");
  activeSheet.getRange(1, 1).setFontColor("#ffffff");
  
}  

function adminListAllTeamDrives(){
  //変数の宣言
  var pageTokenDrive;
  var pageTokenMember;
  var teamDrives;
  var permissions;
 
  //ドライブ名の一覧を取得
  do{
    teamDrives = Drive.Drives.list({pageToken:pageTokenDrive,maxResults:100,useDomainAdminAccess:true})
    if(teamDrives.items && teamDrives.items.length > 0){
      
      for (var i = 0; i < teamDrives.items.length; i++) {
        
        var teamDrive = teamDrives.items[i];
        //ドライブ名の一覧情報を転記
        activeSheet.getRange(i+2, 1).setValue(teamDrive.name)
        
          //ドライブごとのメンバーの権限を取得
          do{
            permissions = Drive.Permissions.list(teamDrive.id, {maxResults:40,pageToken:pageTokenMember,supportsAllDrives:true}) ;
            if(permissions.items && permissions.items.length > 0){
              for (var j = 0,k = 2; j < permissions.items.length; j++,k=k+2) {
                
              activeSheet.getRange(1, k).setValue("メンバー")
              activeSheet.getRange(1, k+1).setValue("権限")
              activeSheet.getRange(1, k, 1,k).setBackground("#7169e5");
              activeSheet.getRange(1, k, 1,k).setFontColor("#ffffff");
              
              
              //権限情報を取得して変数に格納
              var permission = permissions.items[j];
              activeSheet.getRange(i+2, k).setValue(permission.emailAddress)
              
              switch(permission.role){
              case "organizer":
                activeSheet.getRange(i+2, k+1).setValue("管理者")
                break;
              case "fileOrganizer":
                activeSheet.getRange(i+2, k+1).setValue("コンテンツ管理者")
                break;
              case "writer":
                activeSheet.getRange(i+2, k+1).setValue("投稿者")
                break;
              case "commenter":
                activeSheet.getRange(i+2, k+1).setValue("閲覧者(コメント可)")
                break;
              case "reader":
                activeSheet.getRange(i+2, k+1).setValue("閲覧者")
                break;
              }
            }
            }else{
              Logger.log("メンバー/権限が見つかりませんでした。");
            }
    
          //次のページのpageTokenを取得する
          pageTokenMember = permissions.nextPageTokens
          }while(pageTokenMember)
    }
      
    }else{
      Logger.log("共有ドライブが見つかりませんでした。");
    }
    
    //次のページのpageTokenを取得する
    pageTokenDrive = teamDrives.nextPageToken
    }while(pageTokenDrive)
}
```

* ドライブの権限ごとのセルにメンバーをまとめて出力するパターン

```js:getDriveUser.gs

var SheetName = "getDriveUser";
activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SheetName)

function getDriveUser() {

  firstStep();
  adminListAllTeamDrives();
  
}

function firstStep(sheetName) {

  //初期化する 
  
  activeSheet.clear();

  activeSheet.getRange(1, 1).setValue("ドライブ名")
  activeSheet.getRange(1, 2).setValue("管理者")
  activeSheet.getRange(1, 3).setValue("コンテンツ管理者")
  activeSheet.getRange(1, 4).setValue("投稿者")  
  activeSheet.getRange(1, 5).setValue("閲覧者(コメント可)")
  activeSheet.getRange(1, 6).setValue("閲覧者")
  activeSheet.getRange("A1:F1").setBackground("#7169e5");
  activeSheet.getRange("A1:F1").setFontColor("#ffffff");
  
}  

function adminListAllTeamDrives(){

  //変数の宣言
  var pageTokenDrive;
  var pageTokenMember;
  var teamDrives;
  var memberPermissions;
  //権限ごとのアドレスを格納
  var organizerData = '';
  var fileOrganizerData = '';
  var writerData = '';
  var commenterData = '';
  var readerData = '';
  
  //ドライブ名の一覧を取得
  do{
    teamDrives = Drive.Drives.list({pageToken:pageTokenDrive,maxResults:100,useDomainAdminAccess:true})
    if(teamDrives.items && teamDrives.items.length > 0){
      for (var i = 0; i < teamDrives.items.length; i++) {
        
        var teamDrive = teamDrives.items[i];
        
        //ドライブ名の一覧情報を転記
        activeSheet.getRange(i+2, 1).setValue(teamDrive.name)
        
          //ドライブごとのメンバーの権限を取得
          do{
            memberPermissions = Drive.Permissions.list(teamDrive.id, {maxResults:40,pageToken:pageTokenMember,supportsAllDrives:true}) ;
            if(memberPermissions.items && memberPermissions.items.length > 0){
              for (var j = 0; j < memberPermissions.items.length; j++) {
              
              var permission = memberPermissions.items[j];
              //権限ごとに場合分けして変数に格納
              switch(permission.role){
              case "organizer":
                organizerData += permission.emailAddress + ',' + String.fromCharCode(10) ;
                break;
              case "fileOrganizer":
                fileOrganizerData += permission.emailAddress + ',' + String.fromCharCode(10) ;  
                break;
              case "writer":
                writerData += permission.emailAddress + ',' + String.fromCharCode(10) ;
                break;
              case "commenter":
                commenterData += permission.emailAddress + ',' + String.fromCharCode(10) ; 
                break;
              case "reader":
                readerData += permission.emailAddress + ',' + String.fromCharCode(10) ;  
                break;
              }
              
            }
            
            //権限ごとに格納した内容を転記  
            activeSheet.getRange(i+2,2).setValue(organizerData);
            organizerData = '';
              
            activeSheet.getRange(i+2,3).setValue(fileOrganizerData);
            fileOrganizerData = '';
              
            activeSheet.getRange(i+2,4).setValue(writerData);
            writerData = '';
              
            activeSheet.getRange(i+2,5).setValue(commenterData);
            commenterData = '';
              
            activeSheet.getRange(i+2,6).setValue(readerData);
            readerData = '';
              
            activeSheet.getRange(i+2,1,i+2,5).setWrap(true);
            activeSheet.getRange(i+2,1,i+2,5).setVerticalAlignment('top');
            activeSheet.getRange(i+2,1,i+2,5).setHorizontalAlignment('left');
            
            }else{
              Logger.log("メンバー/権限が見つかりませんでした。");
            }
    
          //次のメンバーのpageTokenを取得する
          pageTokenMember = memberPermissions.nextPageTokens
          
         }while(pageTokenMember)
    }
      
    }else{
     Logger.log("共有ドライブが見つかりませんでした。");
    }
    
    //次のドライブのpageTokenを取得する
    pageTokenDrive = teamDrives.nextPageToken
    }while(pageTokenDrive)
 
}
```

### スケジュールの設定
常に最新の内容に更新したいので、GASのトリガー設定にて毎日実行するスケジュールを設定します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/c4a040ae-e620-f378-9304-6e5a08641383.png" width=60%>

## 結果
毎日指定時刻に実行されて、最新の共有ドライブ管理状況を可視化出来るようになりました。
棚卸にも有効です。

## 参考

[Google Apps Scriptで共有ドライブをコントロールする](https://officeforest.org/wp/2019/12/11/google-apps-scriptで共有ドライブをコントロールする/)