Scripting and Macros
This scripts gets the workbook properties
function main(workbook: ExcelScript.Workbook) {
const _properties = workbook.getProperties();
const _title = properties.getTitle();
const _subject = properties.getSubject();
const _author = properties.getAuthor();
const _comments = properties.getComments();
const _dataProperties : i_WorkbookMetaData = {
title : _title || "(Not Set)"
sibject : _subject || "(Not Set)"
author : _author || "(Not Set)"
comments : _comments || "(Not Set)"
};
displayPropertiesInSheet(workbook, _dataProperties);
}
interface i_WorkbookMetaData{
title : string;
subject : string;
author : string;
comments : string;
}
function displayPropertiesInSheet(
workbook: ExcelScript.Workbook,
properties: i_WorkbookMetaData) {
const _sheet = workbook.getActiveWorksheet();
const _headerRange = _sheet.getRange("A1:B1");
_headerRange.setValues([["Property","Value"]]);
const _dataRange = _sheet.getRange("A2:B5");
const _propertiesArray = [
["Title", properties.title],
["Title", properties.title],
["Title", properties.title],
["Title", properties.title],
];
_dataRange.setValues(_propertiesArray);
}
This script can generate monthly worksheets from a template
function main(
workbook: ExcelScript.Workbook,
templateSheetName: string = "Template_Month",
startMonth: string = "2026-01", // format: YYYY-MM
endMonth: string = "2026-12", // format: YYYY-MM
nameFormat: "YYYY-MM" | "MMM YYYY" | "MMMM YYYY" = "YYYY-MM",
overwriteExisting: boolean = false,
monthDateCellAddress: string = "" // e.g., "B2" (optional)
) {
const templateSheet = workbook.getWorksheet(templateSheetName);
if (!templateSheet) {
throw new Error(`Template sheet not found: "${templateSheetName}"`);
}
const start = parseYearMonth(startMonth);
const end = parseYearMonth(endMonth);
if (start.year > end.year || (start.year === end.year && start.month > end.month)) {
throw new Error(`Invalid range: startMonth (${startMonth}) must be <= endMonth (${endMonth}).`);
}
let currentYear = start.year;
let currentMonth = start.month;
while (currentYear < end.year || (currentYear === end.year && currentMonth <= end.month)) {
const sheetName = formatMonthSheetName(currentYear, currentMonth, nameFormat);
const existing = workbook.getWorksheet(sheetName);
if (existing) {
if (!overwriteExisting) {
// Skip existing
incrementMonth();
continue;
}
// Delete existing to recreate
existing.delete();
}
const newSheet = templateSheet.copy(ExcelScript.WorksheetPositionType.after, templateSheet);
newSheet.setName(sheetName);
if (monthDateCellAddress && monthDateCellAddress.trim()) {
const firstOfMonth = new Date(Date.UTC(currentYear, currentMonth - 1, 1));
// Excel stores dates as serials; Office Scripts accepts JS Date objects in setValue.
newSheet.getRange(monthDateCellAddress).setValue(firstOfMonth);
}
incrementMonth();
}
function incrementMonth() {
currentMonth++;
if (currentMonth > 12) {
currentMonth = 1;
currentYear++;
}
}
}
function parseYearMonth(input: string): { year: number; month: number } {
const m = input.trim().match(/^(\d{4})-(\d{2})$/);
if (!m) throw new Error(`Invalid YYYY-MM format: "${input}". Example: "2026-03"`);
const year = Number(m[1]);
const month = Number(m[2]);
if (!Number.isFinite(year) || !Number.isFinite(month) || month < 1 || month > 12) {
throw new Error(`Invalid month/year: "${input}"`);
}
return { year, month };
}
function formatMonthSheetName(
year: number,
month: number,
nameFormat: "YYYY-MM" | "MMM YYYY" | "MMMM YYYY"
): string {
if (nameFormat === "YYYY-MM") {
return `${year}-${String(month).padStart(2, "0")}`;
}
const monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const monthNamesLong = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
if (nameFormat === "MMM YYYY") {
return `${monthNamesShort[month - 1]} ${year}`;
}
return `${monthNamesLong[month - 1]} ${year}`;
}
© 2026 Better Solutions Limited. All Rights Reserved. © 2026 Better Solutions Limited TopPrevNext