Skip to content

Build a spreadsheet report of a folder

What it does. The script lists the files in a folder, adds their size, date and a field, puts a totals row at the bottom, and writes the lot to an Excel file in a Reports folder. Run it by hand, or from a schedule every Monday.

What you need.

  • The MaSH feature.
  • A source folder and a Reports folder, on shares the script’s owner can use.
  • Optionally a schedule: Settings > MaSH > Schedule, Weekly, with None: no input files. See Schedules.
  • Script settings: SHARE, FOLDER and REPORTS (folder for the output).

The report is a list of rows, the first being the headings. This block builds the rows from a list of simple records, so you can test it without a share:

block reportRows items
set rows to [["Name", "Size (KB)", "Modified", "Status"]]
set totalBytes to 0
each items as item
set kb to mash.math.round(item["size"] / 1024, 1)
rows[] = [item["name"], kb, item["modified"], item["status"] ?? ""]
set totalBytes to totalBytes + item["size"]
end
rows[] = ["Total", mash.math.round(totalBytes / 1024, 1), "", count(items) ~ " files"]
return rows
end
set sample to [
{"name": "a.pdf", "size": 2048, "modified": "2026-11-01", "status": "Approved"},
{"name": "b.pdf", "size": 1536, "modified": "2026-11-02"}
]
each reportRows(sample) as row
printline mash.collect(row).join(" | ")
end
Name | Size (KB) | Modified | Status
a.pdf | 2 | 2026-11-01 | Approved
b.pdf | 1.5 | 2026-11-02 |
Total | 3.5 | | 2 files
set errorblock to "onError"
block onError
printline "Error on line {{mash.error.line}}: {{mash.error.message}}"
end
set shareName to mash.config.get("SHARE")
set folderPath to mash.config.get("FOLDER") ?? ""
set reportsPath to mash.config.get("REPORTS") ?? "Reports"
if not shareName
fail "SHARE is not set on this automation."
end
set folder to mash.files.get(shareName, folderPath)
if not folder.is_dir
fail "{{folderPath}} is not a folder."
end
set items to []
each folder.contents as item
if not item.is_dir
items[] = {
"name": item.name,
"size": item.size,
"modified": item.modified.format("Y-m-d"),
"status": item.fields["Status"] ?? ""
}
end
end
if count(items) is 0
printline "No files in {{folderPath}}. No report written."
return
end
set rows to [["Name", "Size (KB)", "Modified", "Status"]]
set totalBytes to 0
each items as item
rows[] = [item["name"], mash.math.round(item["size"] / 1024, 1), item["modified"], item["status"]]
set totalBytes to totalBytes + item["size"]
end
rows[] = ["Total", mash.math.round(totalBytes / 1024, 1), "", count(items) ~ " files"]
set book to mash.xlsx.create(rows, "Folder report")
set reports to mash.files.get(shareName, reportsPath)
set fileName to "report-" ~ mash.date.now().format("Y-m-d") ~ ".xlsx"
reports.write(fileName, book)
printline "Wrote {{fileName}} with {{count(items)}} files."
  1. folder.contents is the list of what’s directly inside. The script keeps only files, not folders. To include subfolders, call contents again on each folder in a loop, or use mash.files.search.
  2. Plain records first. The script turns each file into a small dictionary and builds rows from those. The row-building block is then the same one you tested above.
  3. item.fields["Status"] ?? "" reads a field and falls back to empty, so a file with no value doesn’t stop the run.
  4. mash.xlsx.create(rows, name) makes the workbook in memory. reports.write(fileName, book) saves it. A new name each day keeps old reports.
  5. A run has a time limit. A folder with thousands of files can take a while. See Limits. For big folders, report on one subfolder per run.
  • A CSV instead. Write rows with mash.csv.writer() and insertOne for each. See Log each document’s fields to a CSV.
  • Email it. Send the written file as an attachment: mash.mail.send("boss@example.com", "Weekly report", "Attached.", [written]), where written = reports.write(fileName, book).
  • Several shares. Loop over a list of share names from a setting and add a Share column.
  • Filter. Skip files that aren’t PDFs: if item.extension == "pdf".
  • Sums by field. mash.collect(items).sum("size") totals one key. Group rows with the collection methods on the Collection page.

Library pages used: XLSX, Files, Date.