Shore Up
A janitor sweeping a pile of dusty, date-stamped paper folders into a bin while leaving the fresh, recent folders neatly on a shelf.
Windows

Automate Temp and Log Cleanup with a Batch File

Ketan Aagja9 min read
No ratings yet

Before you run this

This guide builds a Windows batch file that deletes old log files from a folder you name and temporary files from a temp folder, based on how many days ago each file was last modified. Its purpose is to reclaim disk space on a schedule without you having to remember to do it.

A few things you need to know before you touch it:

  • del and forfiles do not use the Recycle Bin. Command-line deletions are permanent. There is no "restore from Recycle Bin" afterward. Treat every deletion this script makes as gone for good.
  • Privileges depend on where you point it. Cleaning your own user's %TEMP% needs no elevation. Cleaning a shared log directory, C:\Windows\Temp, or another user's files needs an elevated (Administrator) command prompt, and when you schedule it you will typically run it as SYSTEM or an admin account.
  • Test first, and I mean it. The script ships with DRYRUN=1, which only logs what it would delete and deletes nothing. Read the script, run it in dry-run mode, and inspect the run log before you ever set DRYRUN=0. Do this on a test VM or a throwaway copy of a folder first, not on a production server.
  • Point it at a folder you actually own the contents of. Never aim this at C:\, a whole profile, or a program's data directory. It selects by file mask and age, but a wrong path plus a broad mask is exactly how people delete things they needed.

I'm assuming Windows 10/11 or Windows Server 2016+, the built-in cmd.exe and forfiles.exe (present on all of these), and Task Scheduler for automation.

What the script does, in plain terms

forfiles walks a folder, filters by file mask and last-modified age, and runs a command for each match. That's the whole engine here. The /D -30 argument selects files whose last modified date is 30 or more days in the past — note it's modified date, not created date.

The script

Save this as cleanup.bat. Every value you need to change is in the configuration block at the top, marked with obvious placeholders.

@echo off
setlocal enableextensions

REM ===== Configuration - edit these =====

REM 1 = only log what WOULD be deleted (safe). 0 = actually delete.
set "DRYRUN=1"

REM Files last modified this many or more days ago are targeted.
set "MAXAGE=30"

REM Folder to clean of old log files. Replace with your real path.
set "LOGDIR=C:\path\to\logs"

REM Which files count as logs.
set "LOGMASK=*.log"

REM Temp folder to clean. %TEMP% is the temp of the account that RUNS this.
set "TEMPDIR=%TEMP%"

REM This script's own run log - so you can see what happened.
set "RUNLOG=C:\path\to\cleanup-run.log"

REM ======================================

echo ==== Cleanup %DATE% %TIME% (DRYRUN=%DRYRUN%, MAXAGE=%MAXAGE%) ==== >> "%RUNLOG%"

REM --- Old log files ---
if exist "%LOGDIR%" (
  if "%DRYRUN%"=="1" (
    REM /S recurses subfolders; /D -%MAXAGE% picks files older than the threshold
    forfiles /P "%LOGDIR%" /S /M %LOGMASK% /D -%MAXAGE% /C "cmd /c echo WOULD DELETE @path" >> "%RUNLOG%" 2>&1
  ) else (
    forfiles /P "%LOGDIR%" /S /M %LOGMASK% /D -%MAXAGE% /C "cmd /c del /q @path && echo DELETED @path" >> "%RUNLOG%" 2>&1
  )
) else (
  echo SKIP: log folder not found: %LOGDIR% >> "%RUNLOG%"
)

REM --- Temp files ---
if exist "%TEMPDIR%" (
  if "%DRYRUN%"=="1" (
    forfiles /P "%TEMPDIR%" /S /M *.* /D -%MAXAGE% /C "cmd /c if @isdir==FALSE echo WOULD DELETE @path" >> "%RUNLOG%" 2>&1
  ) else (
    forfiles /P "%TEMPDIR%" /S /M *.* /D -%MAXAGE% /C "cmd /c if @isdir==FALSE del /q @path && echo DELETED @path" >> "%RUNLOG%" 2>&1
  )
) else (
  echo SKIP: temp folder not found: %TEMPDIR% >> "%RUNLOG%"
)

echo ==== Done %DATE% %TIME% ==== >> "%RUNLOG%"
endlocal

A few notes on the non-obvious parts:

  • @isdir==FALSE — when I clean temp with a *.* mask, forfiles also matches subfolders. The if @isdir==FALSE test makes sure del only ever runs on files, never on directories. del can't delete a folder anyway, but this keeps the log clean and the intent clear.
  • Empty subfolders are left behind. This script deletes files, not directories. That's deliberate — removing folders is riskier and rarely worth it. If you truly need to prune empty temp subfolders, do that as a separate, carefully reviewed step; I'm not folding it in here.
  • Locked files are skipped. If a file is in use, del reports it can't delete it and moves on. That message lands in your run log, which is fine and expected.
  • "ERROR: No files found…" — if nothing matches the age filter, forfiles prints this to stderr. It's harmless; 2>&1 just routes it into your run log so you can see it.

Run it in dry-run mode first

Open a command prompt (elevated only if your target folders need it), then:

C:\path\to\cleanup.bat

Nothing is deleted while DRYRUN=1. Open the run log and read every WOULD DELETE line:

notepad C:\path\to\cleanup-run.log

Confirm the paths are all files you genuinely want gone. If anything on that list surprises you, fix your LOGDIR, LOGMASK, or MAXAGE and run the dry run again. Only when the list is clean do you change set "DRYRUN=1" to set "DRYRUN=0" and run it for real.

Schedule it with Task Scheduler

The mainstream way to automate this is Task Scheduler. You can build the task in the GUI (taskschd.msc), or create it from an elevated prompt with schtasks:

schtasks /Create /TN "Temp and Log Cleanup" /TR "C:\path\to\cleanup.bat" /SC DAILY /ST 02:00 /RU SYSTEM /RL HIGHEST
  • /RU SYSTEM runs the task as the local system account (no password needed) with the rights to clean shared folders. If you'd rather run as a specific admin, use /RU DOMAIN\user and you'll be prompted for a password.
  • Watch the %TEMP% caveat: %TEMP% resolves to the running account's temp folder. Under SYSTEM that's not your interactive user's temp. If you want to clean a specific temp location regardless of account, set TEMPDIR to an explicit path instead of %TEMP%.
  • /RL HIGHEST runs elevated. Confirm the exact schtasks options against Microsoft Learn's schtasks reference before relying on the command in production.

Verify it worked

After a real run, check three things.

Read the run log for DELETED lines and any errors:

notepad C:\path\to\cleanup-run.log

Confirm no old files remain past the threshold. This lists any log files still older than MAXAGE — you want it to print nothing but the "No files found" message:

forfiles /P "C:\path\to\logs" /S /M *.log /D -30 /C "cmd /c echo STILL OLD: @path @fdate"

Check that the scheduled task exists and see its last result:

schtasks /Query /TN "Temp and Log Cleanup" /V /FO LIST

Undo and rollback

The file deletions themselves cannot be undone — that's the nature of del. Your only real safeguards are the ones baked in above: the dry-run pass and the run log. If you need to recover something a real run removed, you're into file-recovery tooling or your backups, so make sure old logs you might still want are backed up before you switch off dry-run.

Removing the automation is reversible. Delete the scheduled task with:

schtasks /Delete /TN "Temp and Log Cleanup" /F

That stops future runs and leaves the batch file and its run log in place for review.

Written by
Ketan Aagja

Runs enterprise networks and security for a living, and writes Shore Up to turn two decades of hands-on Linux, Windows and mail-server work into guides you can actually use.

More about the author →

Was this article helpful?

Tap a star — no sign-in needed.

Be the first to rate this article.