Free Google Sheets scripts
Copy, paste, use. Free for any use. Want one customized? Ask for a Fix or Automate.
Send an email when a cell changes
Emails you when someone sets a status column to "Done". In your sheet: Extensions → Apps Script, paste this, change the settings at the top, save, then add an installable "On edit" trigger for notifyOnEdit (Triggers → Add trigger). Simple triggers can't send email.
// SheetHand free script: email on status change
const SHEET_NAME = 'Sheet1'; // tab to watch
const STATUS_COL = 5; // column E
const TRIGGER_VALUE = 'Done';
const NOTIFY = 'you@example.com';
function notifyOnEdit(e) {
const range = e.range;
const sheet = range.getSheet();
if (sheet.getName() !== SHEET_NAME || range.getColumn() !== STATUS_COL) return;
if (String(range.getValue()).trim() !== TRIGGER_VALUE) return;
const row = range.getRow();
const values = sheet.getRange(row, 1, 1, sheet.getLastColumn()).getDisplayValues()[0];
MailApp.sendEmail(NOTIFY,
`Row ${row} marked ${TRIGGER_VALUE}`,
`Sheet: ${sheet.getName()}
Row ${row}: ${values.join(' | ')}
${e.source.getUrl()}`);
}
Back up a sheet to Drive every night
Makes a dated copy of the whole spreadsheet in a Drive folder. Paste, set the folder ID, then add a time-driven trigger for nightlyBackup (Day timer).
// SheetHand free script: nightly backup copy
const FOLDER_ID = 'PASTE_FOLDER_ID'; // from the folder URL
const KEEP_DAYS = 30;
function nightlyBackup() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const folder = DriveApp.getFolderById(FOLDER_ID);
const stamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd');
DriveApp.getFileById(ss.getId()).makeCopy(`${ss.getName()} backup ${stamp}`, folder);
const cutoff = Date.now() - KEEP_DAYS * 86400000;
const files = folder.getFiles();
while (files.hasNext()) {
const f = files.next();
if (f.getName().startsWith(`${ss.getName()} backup`) && f.getDateCreated().getTime() < cutoff) f.setTrashed(true);
}
}
Remove duplicate rows with one click
Adds a SheetHand menu with "Remove duplicates" that keeps the first row of each duplicate set, based on the columns you choose.
// SheetHand free script: dedupe menu
const KEY_COLS = [1, 2]; // dedupe on columns A and B
function onOpen() {
SpreadsheetApp.getUi().createMenu('SheetHand').addItem('Remove duplicates', 'removeDuplicates').addToUi();
}
function removeDuplicates() {
const sheet = SpreadsheetApp.getActiveSheet();
const last = sheet.getLastRow();
if (last < 3) return;
const range = sheet.getRange(2, 1, last - 1, sheet.getLastColumn());
const seen = new Set(), keep = [];
range.getValues().forEach(r => {
const key = KEY_COLS.map(c => String(r[c - 1]).trim().toLowerCase()).join('||');
if (!seen.has(key)) { seen.add(key); keep.push(r); }
});
const removed = last - 1 - keep.length;
range.clearContent();
sheet.getRange(2, 1, keep.length, keep[0].length).setValues(keep);
SpreadsheetApp.getUi().alert(`Removed ${removed} duplicate row(s).`);
}
Test on a copy first. Provided as-is, without warranty.