appscript.dev
Automation Intermediate Drive Sheets

Enforce file naming and tagging governance

Flag Northwind files that don't match required naming or tagging conventions.

Published Oct 16, 2025

Northwind agreed on a file-naming convention months ago: every file starts with an ISO date, then a space, then a descriptive name — 2025-10-16 Client proposal. Conventions only hold if someone checks them, though, and nobody wants to click through a deep folder tree comparing names against a rule.

This script does the checking. It walks a Drive folder and every folder beneath it, tests each file name against the naming pattern, and writes every file that fails into a Sheet — with its folder path and a direct link. The result is an audit list someone can work through and fix, refreshed whenever the script runs.

What you’ll need

  • The ID of the root Drive folder you want to audit. The script descends into every sub-folder from there.
  • A Google Sheet for the report. The script writes to its first tab and clears it on every run, so use a sheet dedicated to this audit.
  • Edit access to both — DriveApp needs to read the folder tree and SpreadsheetApp needs to write the report.

The script

// Files must start with an ISO date, a space, then a name:
// "2025-10-16 Client proposal". Tighten or relax this to suit.
const NAMING_RULE = /^\d{4}-\d{2}-\d{2}\s.+/;

/**
 * Walks a Drive folder tree and writes every file whose name breaks
 * NAMING_RULE into the report sheet.
 *
 * @param {string} rootFolderId  Folder to audit, including sub-folders.
 * @param {string} sheetId       Spreadsheet to write the report into.
 */
function auditNaming(rootFolderId, sheetId) {
  // 1. Collect every offending file by walking the tree recursively.
  const issues = [];
  walk(DriveApp.getFolderById(rootFolderId), '', issues);

  // 2. Rebuild the report sheet from scratch.
  const sheet = SpreadsheetApp.openById(sheetId).getSheets()[0];
  sheet.clear();
  sheet.getRange(1, 1, 1, 3).setValues([['Path', 'Name', 'Link']]);

  // 3. Write one row per offending file, if there are any.
  if (issues.length) {
    sheet.getRange(2, 1, issues.length, 3).setValues(issues);
  }
  Logger.log('Found ' + issues.length + ' files breaking the naming rule.');
}

/**
 * Recursively visits a folder and its sub-folders, pushing a
 * [path, name, url] row for every file that fails NAMING_RULE.
 *
 * @param {Folder} folder  The folder to scan.
 * @param {string} path    Path of the parent folder, '' at the root.
 * @param {Array}  out     Accumulator of offending rows.
 */
function walk(folder, path, out) {
  // Build the human-readable path for this folder.
  const full = path ? `${path}/${folder.getName()}` : folder.getName();

  // Check every file in this folder against the naming rule.
  const files = folder.getFiles();
  while (files.hasNext()) {
    const f = files.next();
    if (!NAMING_RULE.test(f.getName())) {
      out.push([full, f.getName(), f.getUrl()]);
    }
  }

  // Recurse into every sub-folder.
  const subs = folder.getFolders();
  while (subs.hasNext()) {
    walk(subs.next(), full, out);
  }
}

How it works

  1. auditNaming starts an empty issues array and calls walk on the root folder. The empty string is the starting path — the root folder has no parent.
  2. walk builds the readable path for the current folder by joining it onto the path passed in from its parent.
  3. It iterates every file in the folder and tests the name with NAMING_RULE. The regex requires four digits, a dash, two digits, a dash, two digits, a space, then at least one more character — an ISO date followed by a name.
  4. Any file that fails the test is pushed to the accumulator as a row of [path, name, url].
  5. walk then calls itself on every sub-folder, so the whole tree is covered no matter how deep it goes.
  6. Back in auditNaming, the report sheet is cleared, given a header row, and filled with one row per offending file.

Example run

Suppose the audited folder tree looks like this:

Northwind/
  Proposals/
    2025-10-01 Acme proposal.pdf      ✓ matches
    final proposal v2.pdf             ✗ no date prefix
  Contracts/
    2025-09-12 Acme contract.docx     ✓ matches
    contract-draft.docx               ✗ no date prefix

After a run, the report sheet’s first tab holds:

PathNameLink
Northwind/Proposalsfinal proposal v2.pdfhttps://drive.google.com/
Northwind/Contractscontract-draft.docxhttps://drive.google.com/

The two compliant files are not listed — the report is a worklist of what needs renaming, not an inventory of everything.

Run it

auditNaming takes two arguments, so call it from a small wrapper rather than running it directly:

function runAudit() {
  auditNaming('1abcRootFolderId', '1abcReportSheetId');
}

Select runAudit in the editor and click Run, or attach it to a Time-driven trigger to re-run the audit on a schedule — weekly works well for keeping a shared drive tidy.

Watch out for

  • A huge folder tree can hit the Apps Script six-minute execution limit. If the audit times out, run it per top-level folder instead of from one shared root.
  • The rule only checks file names, not folders. Files inside a badly named folder still pass as long as their own names match. Extend walk to test folder.getName() too if folder naming matters.
  • getFiles() returns shortcuts and shared files as well as native ones. A shortcut to a well-named file may itself be named differently and show up as an issue — filter on f.getMimeType() if you want to skip shortcuts.
  • The sheet is rebuilt with clear() every run, so any notes you add about a flagged file are lost on the next pass. Fix the file names instead of annotating the report.
  • The regex is strict about the ISO date but says nothing about tags. If your governance also covers tags or labels, widen NAMING_RULE or add a second check inside walk.

Related