How to automate a weekly Excel report with Power Query and one button
To automate a weekly Excel report, save each export into one folder and let Power Query combine and clean them: skip title lines, drop the total row, fix types and keep one copy of each order. Build the pivot report on that table, then add a one-button VBA macro that refreshes everything, stamps the time and saves a PDF. The code is free below. Botlery builds Excel automations for a free fixed-price quote.
The weekly report that takes a morning usually follows the same steps every time: export from the system, paste under last week’s data, delete the title rows and the total line, fix the dates that came in as text, spot the orders that appear in two exports, refresh the pivot, save a PDF. Every one of those steps can be written down once. The result is a report that is the same every week, including in the weeks someone else runs it.
What you need
- Desktop Excel for Windows with Power Query, which is built in from Excel 2016 onwards and in Microsoft 365 (Data › Get Data). The macro step does not run in Excel for the web.
- A system that can export orders, invoices or sales as CSV, with the same columns each week.
- One folder that holds every weekly export and nothing else.
To follow along with the same numbers shown below, download the sample files:
- orders-2026-09-21.csvFirst weekly export: two title lines, four orders, a Total line.
- orders-2026-09-28.csvThe next export. It overlaps the first and corrects the amount on order SO-1044.
- weekly-report-query.txtThe Power Query below, as text.
- weekly-report-macro.basThe macro below, ready for File › Import File in the VBA editor.
Step 1: give the exports one home
Save every export into the same folder, for example C:\Reports\Weekly exports\, and keep the date in the file name in year-month-day order (orders-2026-09-28.csv). The query uses the name to decide which export is newest. Never edit the exports themselves: if a figure is wrong, it gets fixed in the query or at the source, so next week’s run does not undo it.
Step 2: the Power Query that combines and cleans
In a new workbook choose Data › Get Data › From Other Sources › Blank Query, open Advanced Editor, replace everything with the query below and change FolderPath. Name the query Orders.
Power Query (M) · Advanced Editor
// Weekly report: every export in one folder -> one clean, de-duplicated table.
// From botlery.com/blog/automate-weekly-excel-report.html
let
FolderPath = "C:\Reports\Weekly exports\",
LinesAboveHeader = 2, // title lines your system writes above the header row
Files = Folder.Files(FolderPath),
CsvFiles = Table.SelectRows(Files, each Text.Lower([Extension]) = ".csv"),
// Newest export first. Works when file names carry the date (orders-2026-09-28.csv);
// otherwise sort on "Date modified" instead of "Name".
NewestFirst = Table.Sort(CsvFiles, {{"Name", Order.Descending}}),
ReadExport = (content as binary, fileName as text) as table =>
let
// Drop the title lines BEFORE parsing: Csv.Document takes its column count from the
// first line it reads, so a one-field title line would squeeze every row into one column.
AllLines = Lines.FromBinary(content, QuoteStyle.Csv, false, 65001),
DataLines = List.Skip(AllLines, LinesAboveHeader),
Raw = Csv.Document(Text.Combine(DataLines, "#(cr,lf)"), [Delimiter = ",", QuoteStyle = QuoteStyle.Csv]),
Promoted = Table.PromoteHeaders(Raw, [PromoteAllScalars = true]),
Trimmed = Table.TransformColumnNames(Promoted, Text.Trim),
Tagged = Table.AddColumn(Trimmed, "Source File", each fileName, type text)
in
Tagged,
AllRows = Table.Combine(Table.AddColumn(NewestFirst, "Data", each ReadExport([Content], [Name]))[Data]),
// Real orders only: no blank lines and no "Total" line at the bottom.
OrdersOnly = Table.SelectRows(AllRows, each [Order ID] <> null and [Order ID] <> ""
and not Text.StartsWith(Text.Lower([Order ID]), "total")),
Typed = Table.TransformColumnTypes(
OrdersOnly,
{{"Order ID", type text}, {"Order Date", type date}, {"Customer", type text},
{"Region", type text}, {"Amount", type number}},
"en-US"
),
Tidy = Table.TransformColumns(Typed, {
{"Customer", each Text.Trim(Text.Clean(_)), type text},
{"Region", each Text.Trim(Text.Clean(_)), type text}}),
// Exports overlap, so one order can appear in two files: keep the newest copy.
// Table.Buffer holds the newest-first order so Table.Distinct keeps the right row.
Latest = Table.Distinct(Table.Buffer(Tidy), {"Order ID"}),
WithWeek = Table.AddColumn(Latest, "Week Starting",
each Date.StartOfWeek([Order Date], Day.Monday), type date),
Sorted = Table.Sort(WithWeek, {{"Order Date", Order.Ascending}, {"Order ID", Order.Ascending}})
in
Sorted
What each step fixes
Lines.FromBinaryandList.Skipremove the title lines many systems write above the header row, before the file is parsed. That order matters:Csv.Documenttakes its column count from the first line it reads, so parsing first and skipping afterwards would squeeze every row into one column. SetLinesAboveHeaderto 0 if your export starts with the headers.- The
OrdersOnlyfilter drops blank lines and the “Total” row at the bottom. If that row stayed in, the pivot would count every week twice. Table.TransformColumnTypeswith"en-US"reads dates and numbers the way the file writes them, whatever your own Windows settings are. If your system writes dates as 28/09/2026, change it to your locale, for example"en-GB".Table.Distincton Order ID keeps one copy of an order that appears in two exports, and because the files are read newest first, it keeps the newest version.Table.Bufferis there because Power Query does not otherwise promise to keep the sort order when it removes duplicates.- Week Starting gives every order the Monday of its week, which is what the pivot groups by.
- Source File stays as a column, so any number in the report can be traced to the export it came from.
Step 3: load it and build the report once
Choose Close & Load To › Table on a new sheet. Then build the report the usual way: Insert › PivotTable from the Orders table, on a sheet called Report, with Week Starting in Rows, Region in Columns and Sum of Amount in Values. Add a chart if you like. With the two sample files the report should show:
| Week starting | East | North | South | Total |
|---|---|---|---|---|
| 14 Sep 2026 | 730.25 | 96.50 | 826.75 | |
| 21 Sep 2026 | 58.40 | 132.00 | 190.40 | |
| Grand total | 58.40 | 730.25 | 228.50 | 1,017.15 |
Six orders, not eight: SO-1043 and SO-1044 are in both exports and are counted once, and SO-1044 shows the corrected 80.25 from the newer file rather than 75.25. Adding the two exports’ own Total lines (821.75 + 680.65) would have overstated the fortnight by 485.25, the double-counted orders. That is the “always slightly wrong” that hand-built reports suffer from.
Step 4: the one-button macro
Next week, the only manual step left is saving the new export into the folder. The macro does the rest in the right order: refresh the query, then the pivots, then write the time on the report and save it as a PDF.
- Press Alt+F11, choose Insert › Module and paste the code below (or use File › Import File with the downloaded .bas file).
- Check the two settings at the top: the report sheet’s name and the cell for the time stamp.
- Save the workbook as Excel Macro-Enabled Workbook (.xlsm). Saved as a normal .xlsx, the macro is dropped; Excel warns you, but the warning is easy to click past.
- Add the button: Developer › Insert › Button (Form Control), draw it on the Report sheet and pick
RefreshWeeklyReport. (No Developer tab? File › Options › Customize Ribbon, tick Developer.)
VBA · module WeeklyReport
Option Explicit
' One button: refresh the queries, then the pivots, stamp the time, save a PDF.
' From botlery.com/blog/automate-weekly-excel-report.html
' Excel for Windows. Save the workbook as .xlsm.
Private Const REPORT_SHEET As String = "Report" ' the sheet with your pivots and charts
Private Const STAMP_CELL As String = "B2" ' where "Refreshed ..." is written
Public Sub RefreshWeeklyReport()
Dim cn As WorkbookConnection
Dim pc As PivotCache
Dim pdfPath As String
On Error GoTo Failed
Application.ScreenUpdating = False
Application.StatusBar = "Refreshing the weekly report..."
' Make each query finish before the next step. With background refresh on,
' RefreshAll returns at once and the pivots would refresh on last week's data.
For Each cn In ThisWorkbook.Connections
If cn.Type = xlConnectionTypeOLEDB Then cn.OLEDBConnection.BackgroundQuery = False
Next cn
ThisWorkbook.RefreshAll
For Each pc In ThisWorkbook.PivotCaches
pc.Refresh
Next pc
With ThisWorkbook.Worksheets(REPORT_SHEET)
.Range(STAMP_CELL).Value = "Refreshed " & Format(Now, "yyyy-mm-dd hh:nn")
pdfPath = OutputFolder() & "Weekly report " & Format(Date, "yyyy-mm-dd") & ".pdf"
.ExportAsFixedFormat Type:=xlTypePDF, Filename:=pdfPath, _
Quality:=xlQualityStandard, OpenAfterPublish:=False
End With
Application.StatusBar = False
Application.ScreenUpdating = True
MsgBox "Report refreshed and saved as:" & vbNewLine & pdfPath, vbInformation, "Weekly report"
Exit Sub
Failed:
Application.StatusBar = False
Application.ScreenUpdating = True
MsgBox "The refresh stopped: " & Err.Description, vbExclamation, "Weekly report"
End Sub
' The workbook's own folder, or Documents when the workbook is opened from
' OneDrive or SharePoint (its Path is then a web address, not a folder).
Private Function OutputFolder() As String
Dim p As String
p = ThisWorkbook.Path
If p = "" Or LCase$(Left$(p, 4)) = "http" Then p = Environ$("USERPROFILE") & "\Documents"
OutputFolder = p & Application.PathSeparator
End Function
The line that matters most is BackgroundQuery = False. With background refresh on, which is Excel’s default for queries, RefreshAll returns straight away and the pivot refreshes on last week’s data while the query is still running. Turning it off makes each step wait for the one before.
Do you need the macro at all?
Not always. If all you want is fresh numbers when the file opens, skip the code: in Data › Queries & Connections, right-click the query, choose Properties and tick Refresh data when opening the file (the pivot table has the same option under PivotTable Options › Data). The macro earns its place when you also want the refresh order guaranteed, the time stamp and the PDF, from one click that anyone can press.
Macros in downloaded files are blocked
Since 2022, Office for Windows blocks VBA macros in files that came from the internet, including email attachments and browser downloads. Windows marks those files (the “Mark of the Web”), and Excel then shows a red SECURITY RISK banner with no Enable Content button. Microsoft’s documented ways to run macros you trust are (Microsoft Learn: Macros from the internet are blocked by default in Office, last updated 17 July 2026, checked 7 October 2026):
- Unblock the file: right-click it in File Explorer, choose Properties, tick Unblock on the General tab.
- Keep it in a Trusted Location: files saved there open with macros enabled (File › Options › Trust Center › Trust Center Settings › Trusted Locations). Use a folder only your team writes to.
- For files on OneDrive or SharePoint: open them with Open in Desktop App rather than downloading a copy, or have your IT admin mark the site as trusted.
This is why this guide gives you the macro as text and not as a ready-made .xlsm: code you paste into your own workbook is not a file from the internet. The block will apply to your colleagues, though. When you email them the finished .xlsm, they will need to unblock it or open it from a shared trusted location.
Pitfalls
- The export changes its headers. A renamed column breaks the type step with an error naming the column. If it happens often, map the headers first, as in our guide to combining files with different headers.
- An export is open in Excel while you refresh. Power Query cannot read a file Excel has locked; close it first.
- Files without dates in their names. Sort on
Date modifiedinstead ofName, and do not re-save old exports, or an old file becomes the “newest”. - Workbooks opened from OneDrive or SharePoint have a web address as their path, where a PDF cannot be saved. The macro then saves the PDF to your Documents folder instead.
- Excel for the web does not run VBA. A report that must refresh without anyone opening desktop Excel needs Office Scripts with Power Automate instead.
When to hire instead
This pattern covers one export and one report. It is worth having it built when the data comes from several systems that do not share an ID, when the report has to reach different people in different cuts, when it should run on a schedule without anyone opening Excel, or when the numbers feed a dashboard or a management pack.
Botlery builds Excel automations with Power Query, VBA and Office Scripts for a free fixed-price quote, on copies of your files, and you pay once it works on this month’s real exports.
Frequently asked questions
Can Power Query combine every weekly export automatically?
Yes. Point Power Query at the folder rather than at a single file, with Folder.Files, and it reads every CSV in that folder each time you refresh. Save next week's export into the same folder and the next refresh includes it, with the same cleaning steps applied. The query on this page also removes title lines and total rows, fixes the data types and keeps only the newest copy of an order that appears in two exports, so overlapping export dates do not double count.
Why does my pivot table show old numbers after Refresh All?
Because the query was still refreshing in the background when the pivot table refreshed. Excel's queries refresh in the background by default, so Refresh All starts them and moves straight on to the pivot tables, which then read the previous data. Either untick Enable background refresh in the query's properties, or use a macro that sets BackgroundQuery to False on each connection, runs RefreshAll and then refreshes the pivot caches, as the macro on this page does.
Why are the macros blocked in a workbook I downloaded or received by email?
Since 2022 Office for Windows blocks VBA macros in files that carry the Mark of the Web, which Windows adds to downloads and email attachments. Excel shows a SECURITY RISK banner without an Enable Content button. Microsoft's documented fixes are to right-click the file, choose Properties and tick Unblock on the General tab, or to keep the file in a Trusted Location, or to open files stored on OneDrive or SharePoint with Open in Desktop App. Only do this for files you trust.
Does this weekly report automation work in Excel for Mac or Excel for the web?
This guide is written for desktop Excel for Windows. Excel for the web cannot run VBA macros, so a report that must update without anyone opening desktop Excel is built with Office Scripts and Power Automate instead. Excel for Mac runs VBA, but Mac paths and some Power Query sources differ from Windows, so test both the folder import and the PDF step on a Mac before relying on them.
How much does it cost to have Botlery automate an Excel report?
Botlery quotes each Excel automation as one fixed price, and the quote is free. A single export turned into one refreshed report is a small job; several systems, different outputs for different people, or a scheduled run without desktop Excel make it larger. You send sample files and the steps you do today, you get a written scope with one price in USD, Botlery builds it on copies of your files, and you pay once it works on your real data. You can hire Botlery directly or through Upwork.
Want the report built for you?
Send us a sample export and the report you make from it. You get a free fixed-price quote and pay once it works.
Get a free quote Hire on Upwork