繁体   English   中英

如何获取使用 Google Apps 脚本的 G Suite 用户列表?

[英]How to get a list of G Suite users which are using Google Apps Script?

我想知道,是否有机会获得使用 Google Apps 脚本的 G Suite 用户(一个域的)列表?

从用户的 Google Drives 检索脚本项目列表后,您必须首先从Apps Script API请求项目元数据。 目前,获得项目的唯一方法是 go 一个一个,提供带有scriptId的请求。

诀窍是脚本项目文件的 Id 恰好与脚本 Id相同(如果您查看 CLASP 项目的list命令的源代码,您会发现他们利用这一事实来显示项目 Id)。

要获取Project资源,我们需要调用get 方法

GET https://script.googleapis.com/v1/projects/{scriptId}

下面是一个简单的实用程序,用于从 API 中检索单个Project资源。 请注意,您的清单文件必须至少包含https://www.googleapis.com/auth/script.projects.readonly scope,否则403将返回响应代码

/**
 * @typedef {{
 *  domain : string,
 *  email : string,
 *  name : string
 * }} GSuiteUser
 * 
 * @typedef {{
 *  scriptId : string,
 *  title : string,
 *  createTime : string,
 *  updateTime : string,
 *  creator : GSuiteUser,
 *  lastModifyUser : GSuiteUser
 * }} ScriptProject
 * 
 * @summary gets script project metadata
 * @param {{
 *  id : string,
 *  token : string
 * }}
 * @returns {ScriptProject}
 */
const getProject = ({
  id = ScriptApp.getScriptId(),
  token = ScriptApp.getOAuthToken()
}) => {

  const uri = `https://script.googleapis.com/v1/projects/${id}`;

  /** @type {GoogleAppsScript.URL_Fetch.URLFetchRequestOptions} */
  const params = {
    contentType : "application/json",
    headers : {
      Authorization: `Bearer ${token}`
    },
    muteHttpExceptions : true,
    method : "get"
  };

  const response = UrlFetchApp.fetch(uri, params);

  const successChecker = getSuccessChecker();

  const success = successChecker(response);

  if(!success) {
    return {};
  }

  return JSON.parse(response.getContentText());
};

Map 在您使用 ziganotschka 方法获得的脚本文件列表上,您将获得有关项目的详细信息。 接下来,如果您意思是运行项目,您可以调用processes.list API 方法

GET https://script.googleapis.com/v1/processes

必需的 OAuth scope 是https://www.googleapis.com/auth/script.processes

/**
 * @typedef {{
 *  projectName : string,
 *  functionName : string,
 *  processType : string,
 *  processStatus : string,
 *  userAccessLevel : string,
 *  startTime : string,
 *  duration : string
 * }} ScriptProcess
 * 
 * @summary lists script processes for a user
 * @param {{
 *  id : (string|"any"),
 *  pageSize : (number|50),
 *  token : string,
 *  start : (Date|undefined),
 *  end : (Date|undefined),
 *  statuses : string[],
 *  types : string[]
 * }} 
 * @returns {ScriptProcess[]}
 */
const listScriptProcesses = ({
  id = ScriptApp.getScriptId(),
  token = ScriptApp.getOAuthToken(),
  pageSize = 50,
  start, end,
  statuses = [],
  types = []
} = {}) => {

  const query = [
    `pageSize=${pageSize}`,
    `userProcessFilter.startTime=${toZuluTimestamp(start)}`,
    `userProcessFilter.endTime=${toZuluTimestamp(end)}`
  ];

  id !== "any" && query.push(`userProcessFilter.scriptId=${id}`);
  types.length && query.push(`userProcessFilter.types=${types.join(",")}`);
  statuses.length && query.push(`userProcessFilter.statuses=${statuses.join(",")}`);

  const uri = `https://script.googleapis.com/v1/processes?${query.join("&")}`;

  /** @type {GoogleAppsScript.URL_Fetch.URLFetchRequestOptions} */
  const params = {
    contentType: "application/json",
    headers: {
      Authorization: `Bearer ${token}`
    },
    muteHttpExceptions: true,
    method: "get"
  };

  const response = UrlFetchApp.fetch(uri, params);
  const content = response.getContentText();

  const successChecker = getSuccessChecker();
  const success = successChecker(response);

  if (!success) {
    console.warn(response.getResponseCode(), content);
    return [];
  }

  const { processes = [] } = JSON.parse(content);

  return processes;
};

作为响应,您将代表用户获取有关脚本执行的元数据,其凭据与不记名令牌一起传递(您将需要每个用户的服务帐户)。

rest 很简单:如果响应不为空,则用户在某个时间点运行脚本项目(请注意,上面的实用程序将startend时间戳参数都默认为now )。 如果您提供any作为脚本 ID,则请求将返回代表用户执行的每次执行。

该方法的另一个好处是返回每种类型的脚本项目执行,包括 Web 应用程序、附加组件和绑定项目(有关详细信息,请参阅ProcessType枚举)。

这种方法的唯一困难是 Web 部署为“像我一样执行”的应用程序,该应用程序将始终在脚本项目所有者的权限下运行,因此您必须单独跟踪 Web 应用程序的用户。


上面的片段使用以下实用程序脚本:

/**
 * @summary checks HTTPResponse for being successful
 * @param {GoogleAppsScript.URL_Fetch.HTTPResponse} resp 
 * @returns {boolean}
 */
const getSuccessChecker = ({ successOn = [200] } = {}) => (resp) => {
    const code = resp.getResponseCode();
    return successOn.some(c => c === code);
}; 
/**
 * @summary converts input into RFC3339 UTC "Zulu" format
 * @param {Date|number|string} [date] 
 * @returns {string}
 */
const toZuluTimestamp = (date = Date.now()) => new Date(date).toISOString().replace('Z','000000Z');

您需要启用V8 运行时才能使上面的代码片段正常工作(或将它们转换为 ES5 语法)。

如何验证任一域用户在其 Google 云端硬盘上是否拥有独立应用程序脚本项目

  1. 要以管理员身份访问用户的云端硬盘,您需要在GCP Console中设置服务帐号
  2. 确保启用域范围的委派- 这允许 oyu 以域用户身份进行身份验证并列出他的云端硬盘文件
  3. Go 到您的管理控制台并进入Main menu menu> Security > API controls并为新创建的服务帐户添加必要的范围 - 如此所述
  4. 下载带有服务帐户凭据的 .json 文件 - 它应包含"private_key"字段
  5. 在您的情况下,必要的 scope 是https://www.googleapis.com/auth/drive.readonly
  6. 要在 Apps 脚本中使用服务帐户,您需要安装 OAuth2 for Apps 脚本库,如此处所述
  7. 为此,go 到您的应用程序脚本编辑器, "Resources > Libraries... > Find a library"并输入代码1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
  8. 选择一个版本(目前最新的是38)
  9. 现在,您需要以编程方式执行的第一件事是启用adminSDK列出所有域用户 - 正如@TheMaster 所建议的那样
  10. 第二步是遍历所有用户,并代表他们创建一个服务帐户令牌(将他们设置为主题
  11. 使用访问令牌,您可以使用查询参数q: 'mimeType="application/vnd.google-apps.script"'每个用户的文件,以找出用户在他的驱动器上是否有独立的应用程序脚本文件

代码示例:

function myFunction() {
  var users = AdminDirectory.Users.list({"domain":"PASTE HERE YOUR DOMAIN NAME"}).users;
  users.forEach(function(user){  
    user = user.primaryEmail;
    getService(user).reset();
    var service = getService(user);
    
    if (service.hasAccess()) {
      Logger.log("service has access");
      var url = "https://www.googleapis.com/drive/v3/files";
      var query = '?q=mimeType%3D%22application%2Fvnd.google-apps.script%22';
      var headers ={
        "Authorization": 'Bearer ' + service.getAccessToken()
      };       
      var options = {
        'headers': headers,
        'method' : 'get',
        'muteHttpExceptions': true    
      };      
      var response=UrlFetchApp.fetch(url+query, options).getContentText();
      if(JSON.parse(response).files.length==0){
        Logger.log("User " + user + " does not have any Standalone Apps Script projects on his Drive");
      }else{
        Logger.log("User " + user + " has Standalone Apps Script projects on his Drive");
      }
      
    }
    else {
      Logger.log(service.getLastError());
    }
  }
 )
}

var PRIVATE_KEY ="-----BEGIN PRIVATE KEY-----PASTE HERE YOUR PRIVATE KEY FROM THE JSON FILE-----END PRIVATE KEY-----\n";
var CLIENT_EMAIL = 'PASTE HERE THE EMAIL OF THE SERVICE ACCOUNT';

function getService(user) {
  return OAuth2.createService('List users')
  .setTokenUrl('https://accounts.google.com/o/oauth2/token')
  .setPrivateKey(PRIVATE_KEY)
  .setIssuer(CLIENT_EMAIL)
  .setSubject(user)
  .setPropertyStore(PropertiesService.getScriptProperties())
  .setParam('access_type', 'offline')
  .setScope("https://www.googleapis.com/auth/drive.readonly");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM