Reliable form of checking last login date / or account activity?

820 views
Skip to first unread message

Simon Lee

unread,
Mar 1, 2021, 2:54:43 PM3/1/21
to GAM for Google Workspace
Just wondering if this is possible via GAM or GAMADV-XTD?

The reason I'm asking is that the 'last login date' doesn't appear to be a reliable metric to use when performing analysis on accounts. If a user is logged into a mail client, and only ever use that, then their last login date would show when they logged in to set up, but not any more recently.

So is it possible to retrieve the last sent / received mail date?
And/or the last account activity? (Google Current post?)

Stumped as I need to perform an account reclamation exercise, but have hit some hiccups due to the last login date apparently not being accurate.

Any ideas or advice would be greatly appreciated!

Brian Kim

unread,
Mar 1, 2021, 7:35:20 PM3/1/21
to GAM for Google Workspace

Aston Wooller

unread,
Mar 2, 2021, 3:53:44 PM3/2/21
to GAM for Google Workspace
Expanding on the metrics listed above

This page lists out the syntax used to report these metrics
So as an example in Powershell I would write the following:

$Date = Get-Date
$Date = $Date.ToString('yyyy-MM-dd_hh-mm')

$csvGAMReport = "Z:\outputlocationhere\$Date-GmailLastAccess.csv"

Z:\gamlocationhere\gam report users parameters accounts:timestamp_last_login,gmail:timestamp_last_access,gmail:timestamp_last_imap |
Out-File $csvGAMReport -encoding ascii

Simon Lee

unread,
Mar 4, 2021, 6:51:55 AM3/4/21
to GAM for Google Workspace
Thanks all, I ended up writing some Apps Script within a Sheet to pull the data.
For anyone who is curious, here it is:

  1. //Set to true if developing/testing - if running a live version, set to false
  2. let testState = false;

  3. function generateUserReport() {
  4.   let target; 
  5.   
  6.   //Check if dev or prod and change values as required
  7.   if (testState == true) {
  8.     target = "Frodo....@domain.com";
  9.   } else if (testState == false) {
  10.     target = "all";
  11.   } else {
  12.     throw "State not defined";
  13.   }

  14.   Logger.log("Test State: " + testState);

  15.   const daysToCheck = 14;
  16.   const now = new Date();
  17.   const daysAgo = new Date(now.getTime() - daysToCheck * 24 * 60 * 60 * 1000);
  18.   const timezone = Session.getScriptTimeZone();
  19.   const date = Utilities.formatDate(daysAgo, timezone, "yyyy-MM-dd");
  20.   const parameters = [
  21.     "accounts:first_name",
  22.     "accounts:last_name",
  23.     "accounts:last_login_time",
  24.     "gmail:timestamp_last_access",
  25.     "gmail:timestamp_last_interaction",
  26.     "gmail:timestamp_last_imap",
  27.     "gmail:timestamp_last_pop",
  28.     "gmail:timestamp_last_webmail",
  29.     "drive:timestamp_last_active_usage"
  30.   ];
  31.   const rows = [];
  32.   let pageToken;
  33.   let page;

  34.   Logger.log("Target for API call: " + target);

  35.   do {
  36.     page = AdminReports.UserUsageReport.get(target, date, {
  37.       parameters: parameters.join(","),
  38.       maxResults: 500,
  39.       pageToken
  40.     });

  41.     if (page.warnings) {
  42.       for (var i = 0; i < page.warnings.length; i++) {
  43.         const warning = page.warnings[i];
  44.         Logger.log(warning.message);
  45.       }
  46.     }

  47.     const reports = page.usageReports;

  48.     if (reports) {
  49.       for (var i = 0; i < reports.length; i++) {
  50.         const report = reports[i];
  51.         const parameterValues = getParameterValues(report.parameters);
  52.         const row = [
  53.           report.date,
  54.           report.entity.userEmail,
  55.           parameterValues["accounts:first_name"],
  56.           parameterValues["accounts:last_name"],
  57.           parameterValues["accounts:last_login_time"],
  58.           parameterValues["gmail:last_access_time"],
  59.           parameterValues["gmail:last_interaction_time"],
  60.           parameterValues["gmail:last_imap_time"],
  61.           parameterValues["gmail:last_pop_time"],
  62.           parameterValues["gmail:last_webmail_time"],
  63.           parameterValues["drive:last_active_usage_time"]
  64.         ];

  65.         //If testing, log row
  66.         if (testState == true) {
  67.           Logger.log("Logging row: \n" + row);
  68.         } else {
  69.         }

  70.         rows.push(row);

  71.         //If testing, log rows
  72.         if (testState == true) {
  73.           Logger.log("Logging rows after push: \n" + rows);
  74.         } else {
  75.         }
  76.       }
  77.     }

  78.     pageToken = page.nextPageToken;
  79.   } while (pageToken);

  80.   if (rows.length > 0) {
  81.     const spreadsheet = SpreadsheetApp.getActive();
  82.     const sheet = spreadsheet.getSheetByName("User Access Report");
  83.     sheet.clear(); // Append the headers.

  84.     const headers = [
  85.       "Date",
  86.       "User",
  87.       "First Name",
  88.       "Last Name",
  89.       "Account Last Login",
  90.       "Email Last Access",
  91.       "Email Interaction",
  92.       "IMAP",
  93.       "POP",
  94.       "WEBMAIL",
  95.       "DRIVE"
  96.     ];
  97.     sheet.appendRow(headers);
  98.     
  99.     // Append the results.
  100.     sheet.getRange(2, 1, rows.length, rows[0].length).setValues(rows);
  101.     Logger.log("Report spreadsheet completed");
  102.     
  103.     // Send notification email on completion
  104.     MailApp.sendEmail({
  105.       to: "my.e...@domain.com",
  106.       subject: "The account Usage Report has completed",
  107.       htmlBody: `The script to get user account usage has completed.<br><br>Please click here view view it:<br>${spreadsheet.getUrl()}`,
  108.       name: "Script Helper"
  109.     });
  110.   } else {
  111.     Logger.log("No results returned.");
  112.   }
  113. }
  114. /**
  115.  * Gets a map of parameter names to values from an array of parameter objects.
  116.  * @param {Array} parameters An array of parameter objects.
  117.  * @return {Object} A map from parameter names to their values.
  118.  */

  119. function getParameterValues(parameters) {
  120.   return parameters.reduce((result, parameter) => {
  121.     const name = parameter.name;
  122.     let value;

  123.     if (parameter.intValue !== undefined) {
  124.       value = parameter.intValue;
  125.     } else if (parameter.stringValue !== undefined) {
  126.       value = parameter.stringValue;
  127.     } else if (parameter.datetimeValue !== undefined) {
  128.       value = new Date(parameter.datetimeValue);
  129.     } else if (parameter.boolValue !== undefined) {
  130.       value = parameter.boolValue;
  131.     }

  132.     result[name] = value;

  133.     //If testing, logout the results
  134.     if (testState == true) {
  135.       Logger.log(`${name} Result: ${result[name]}`);
  136.     } else {
  137.     }

  138.     return result;
  139.   }, {});
  140. }

Reply all
Reply to author
Forward
0 new messages