Producfy

Small Business Stack

Find Same-Name Files in a Google Drive Folder Without Deleting Anything

How can I find files with the same name in a Google Drive folder without deleting or changing anything?

Use Google Apps Script with Google Drive and a bound Google Sheets spreadsheet to scan one folder's direct child files, group exact filenames, and report repeated names with file IDs and URLs. The script leaves source files unchanged and creates a new report tab for each successful run.

What you need

  • A Google spreadsheet with a bound Apps Script project
  • The source folder's raw ID saved as SOURCE_FOLDER_ID in Script Properties
  • An authorizing account that can read the folder and edit the spreadsheet
  • Manifest scopes for read-only Drive access and current-spreadsheet access

How this script runs

  1. You run the script on one folder
  2. It reads the folder's direct child files, skipping the trash
  3. It groups them by exact filename
  4. It writes repeated names, IDs and URLs to a report sheet
  5. No file is changed or deleted

How does this Google Drive filename report identify matches?

The Google Apps Script groups one folder’s direct child files by exact filename and reports every file in groups containing more than one entry.

Matching is case-sensitive and preserves spaces and extensions. Moon Otter brief.docx differs from moon otter brief.docx; a trailing space also prevents a match.

Repeated filenames do not prove identical content. The scan reads source files without renaming, moving, or deleting them, while writing results to a new tab in its bound spreadsheet. Existing tabs remain untouched.

Which sample files qualify as repeated filenames?

The sample folder Moon Otter Team Files contains two repeated direct-child filenames: Moon Otter brief.docx and Comet Badger logo.png.

IDs and URL tokens below are illustrative, not usable addresses. Each URL token represents the actual URL returned by Drive.

Location Filename File ID URL token
Direct child Moon Otter brief.docx FICTIONAL_A01 URL_A01
Direct child Moon Otter brief.docx FICTIONAL_A02 URL_A02
Direct child Comet Badger logo.png FICTIONAL_B01 URL_B01
Direct child Comet Badger logo.png FICTIONAL_B02 URL_B02
Direct child moon otter brief.docx FICTIONAL_C01 URL_C01
Direct child Nebula Llama notes.txt FICTIONAL_D01 URL_D01
Inside Archive subfolder Moon Otter brief.docx FICTIONAL_E01 URL_E01

The lowercase brief and notes have no exact-name companions. The archived brief is outside the scan boundary.

Folders and files in the trash are excluded. A shortcut counts as its own file entry using its name; the script neither follows its target nor compares target content.

How do you configure the spreadsheet and source folder?

Create a dedicated Google spreadsheet, add its bound Apps Script, and store the source folder’s raw ID in Script Properties.

Anyone viewing the report spreadsheet can read its filenames and IDs, so choose its sharing settings accordingly.

  1. Create a spreadsheet. Name it, for example, Moon Otter filename review. Open Extensions, then Apps Script.
  2. Add the script. Replace the starter code with the JavaScript below and save.
  3. Copy the folder ID. In the Drive folder address, copy only the ID after /folders/, excluding query parameters.
  4. Save the property. Open Apps Script Project Settings. Under Script Properties, add SOURCE_FOLDER_ID with the folder ID as its value. Save. No API key is required.
  5. Set authorization scopes. Apply the manifest configuration below before running.
  6. Run the report. Select reportRepeatedFilenames and click Run. Review authorization and authorize with an account that can read the folder and edit the spreadsheet.
  7. Open the report. After execution completes, return to the spreadsheet and open the new tab beginning with Same-name.

What Apps Script reports exact filename groups without changing source files?

The following bound Apps Script reads Google Drive file names, IDs, and URLs, then writes repeated-name entries to a new spreadsheet tab.

function reportRepeatedFilenames() {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  if (!spreadsheet) {
    throw new Error(
      'Open this script through Extensions > Apps Script in a spreadsheet.'
    );
  }

  const folderId = (
    PropertiesService.getScriptProperties()
      .getProperty('SOURCE_FOLDER_ID') || ''
  ).trim();

  if (!folderId) {
    throw new Error('Set SOURCE_FOLDER_ID in Script Properties.');
  }

  const folder = DriveApp.getFolderById(folderId);
  const files = folder.getFiles();
  const groups = new Map();

  while (files.hasNext()) {
    const file = files.next();
    if (file.isTrashed()) continue;
    const name = file.getName();

    if (!groups.has(name)) {
      groups.set(name, []);
    }

    groups.get(name).push([
      name,
      file.getId(),
      file.getUrl()
    ]);
  }

  const rows = [];
  const names = Array.from(groups.keys()).sort();

  for (const name of names) {
    const matches = groups.get(name);
    if (matches.length > 1) {
      for (const match of matches) {
        rows.push(match);
      }
    }
  }

  // Rich text preserves filenames literally, including leading "=".
  const values = [['Filename', 'File ID', 'URL']]
    .concat(rows)
    .map(row => row.map(text =>
      SpreadsheetApp.newRichTextValue()
        .setText(text)
        .build()
    ));

  const baseName = 'Same-name ' + Date.now();
  let reportName = baseName;
  let suffix = 2;

  while (spreadsheet.getSheetByName(reportName)) {
    reportName = baseName + '-' + suffix;
    suffix += 1;
  }

  const report = spreadsheet.insertSheet(reportName);
  const requiredRows = values.length;

  if (requiredRows > report.getMaxRows()) {
    report.insertRowsAfter(
      report.getMaxRows(),
      requiredRows - report.getMaxRows()
    );
  }

  report.getRange(1, 1, requiredRows, 3)
    .setRichTextValues(values);
  report.setFrozenRows(1);

  spreadsheet.toast(
    rows.length + ' file rows written to ' + reportName,
    'Filename report',
    8
  );
}

The Map preserves exact filename keys. Only the configured folder ID is trimmed. Rich-text output prevents leading = characters from becoming formulas, and the report adds rows when necessary.

How do you restrict the script to read-only Drive authorization?

Set explicit manifest scopes to allow Drive reads and writes only to the current spreadsheet.

In Project Settings, enable showing appsscript.json in the editor. Replace that file’s contents in this dedicated project with:

{
  "timeZone": "America/New_York",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/drive.readonly",
    "https://www.googleapis.com/auth/spreadsheets.currentonly"
  ]
}

These URLs identify permissions, not pages to open. Drive authorization covers files accessible to the account, not just the configured folder; the code limits the scan boundary.

The script is not entirely read-only because reporting changes the spreadsheet. Avoid replacing an unrelated project’s manifest: other automation may require different permissions.

What output should the sample folder produce?

The sample folder produces four data rows representing the two repeated filenames.

Filename File ID URL
Comet Badger logo.png FICTIONAL_B01 URL_B01
Comet Badger logo.png FICTIONAL_B02 URL_B02
Moon Otter brief.docx FICTIONAL_A01 URL_A01
Moon Otter brief.docx FICTIONAL_A02 URL_A02

Actual reports contain real IDs and full URLs. Groups use JavaScript’s default string ordering; entries within each group follow Drive’s iteration order and may appear reversed from this example.

Unique names produce no rows. A successful scan finding no repeats creates headers only. Results reflect files encountered during execution, not a transactional snapshot; concurrent changes can affect results.

Why does Map grouping in reportRepeatedFilenames identify exact repeated filenames?

reportRepeatedFilenames identifies exact repeated filenames because its Map stores every entry under its unchanged filename and reports only groups containing multiple entries.

First, getActiveSpreadsheet() selects the bound spreadsheet, and getProperty() retrieves SOURCE_FOLDER_ID; trim() cleans that configuration value rather than filenames. getFolderById() opens the folder, and getFiles() iterates its direct files instead of traversing subfolders. After skipping trashed entries, getName() supplies each key, while getId() and getUrl() preserve references to individual files. Arrays retain every matching entry rather than replacing earlier entries with the same name.

Next, sort() orders the filename keys, and matches.length > 1 selects repeated-name groups. Appending every member produces four sample data rows, not merely two group summaries.

The script prepends column headers and uses newRichTextValue() to represent cell text literally rather than as formulas. A timestamp-based tab name, checked with getSheetByName() and adjusted with a suffix, supports creating a separate report instead of overwriting an existing tab. After insertSheet(), additional rows are allocated if needed. Finally, setRichTextValues() writes the entire three-column grid in one operation rather than cell by cell, setFrozenRows(1) keeps headers visible, and toast() announces the data-row count and destination tab.

How do you fix missing-folder errors, absent matches, or incomplete reports?

Correct the folder property, account access, scan boundary, or execution workflow according to the specific failure.

“Set SOURCE_FOLDER_ID in Script Properties”

Exact fix: In the same bound project’s Project Settings, add or correct SOURCE_FOLDER_ID, enter the raw folder ID, save, and rerun. A variable in source code does not replace Script Properties.

The script cannot retrieve the folder

Exact fix: Replace a full address or incorrect property value with the raw folder ID. Open the folder using the authorizing account; obtain access or authorize with an account that already has access.

Administrator restrictions can also block authorization. Ask the Workspace administrator to review required permissions; changing the folder property cannot bypass restrictions.

A known same-name pair is absent

Exact fix: Confirm both files are direct children of the configured folder and compare complete names, including capitalization and whitespace. For files inside a subfolder, set SOURCE_FOLDER_ID to that subfolder’s ID and rerun. Do not rename files merely to force matches.

Execution ends without a complete report

Exact fix: Treat reports from failed executions as incomplete, including blank tabs created before write failures. Configure a narrower folder and rerun, or replace the single-run iterator with a paginated Drive API workflow that checkpoints progress and batches writes for large folders.

How should reviewers interpret repeated filenames and file URLs?

Reviewers should compare the files behind reported URLs rather than assume matching names indicate redundancy.

Different IDs identify different Drive entries, not necessarily different content. Sharing the report grants no source-file access; reviewers may still encounter access requests.

Keep review notes outside the three generated columns. Later runs create separate tabs, and older reports become stale after source files change.

When should you avoid this folder-only filename scan?

Avoid this filename scan when the task requires content deduplication, recursive traversal, or a shared-drive inventory with explicit controls.

  • Identical-content cleanup: Use content comparison, such as checksums for eligible binary files. Google-native documents require an appropriate comparison method.
  • Complete folder trees: Use a recursive scanner with explicit traversal rules; this script excludes nested folders.
  • Shared-drive inventories: Use the Advanced Drive service or Drive API with explicit shared-drive parameters. This folder report is not a complete organization-wide inventory.

Related questions

Does a repeated filename mean the files contain identical content?

A repeated filename does not establish identical content; separate drafts can share a name. This Google Apps Script compares exact filenames only, so identical content under different names is not reported.

Does the scan include subfolders or follow shortcuts?

The script scans only direct child files of the configured Google Drive folder, excluding files inside subfolders. A shortcut is treated as its own file entry using its name, without following its target.

What happens when no filenames repeat?

A successful scan with no repeated filenames creates a new Google Sheets tab containing only the Filename, File ID, and URL headers. A headers-only report is a valid empty result, provided execution completed successfully.

Can someone open the source files just because the report is shared with them?

Sharing the Google Sheets report does not grant access to the underlying Drive files. Report viewers can read the listed filenames and IDs but still need permission to open each source file.