Skip to main content

How to Monitor Page File Usage in Batch Script

The Page File (or Swap File) is space on your hard drive that Windows uses as an overflow when physical RAM is full. While the Page File prevents crashes when you run out of memory, it is significantly slower than actual RAM. If Page File usage is consistently high or growing, it signals that your system needs more RAM or that a process is leaking memory. Monitoring the current usage, peak usage, and trends of the Page File helps you assess the true memory pressure on your system.

This guide will explain how to check Page File utilization using PowerShell from a Batch script.

Why PowerShell for Page File Monitoring

Page File monitoring in pure Batch has the same problems as other WMI-based monitoring:

  1. wmic is deprecated since Windows 10 21H1, and its output contains invisible \r characters that corrupt Batch variables, causing set /a calculations and if %pct% GTR 50 comparisons to fail with syntax errors.
  2. Percentage calculations require reliable arithmetic: A set /a "pct=(%used% * 100) / %total%" fails when the \r-corrupted values are used, and Batch's integer-only math truncates rather than rounds.
  3. Combined reporting (Page File + physical RAM) requires values in different units (KB vs. MB) from different WMI classes, which PowerShell can normalize in a single query.

All methods in this guide use PowerShell for queries, calculations, and comparisons.

Method 1: Page File Status Check

This method provides a comprehensive snapshot of Page File usage, including current usage, peak usage (the highest point since last reboot), and the percentage utilized, along with physical RAM context.

@echo off
setlocal

echo [INFO] Querying Page File and memory status...

powershell -NoProfile -Command ^
"try {" ^
" $pf = Get-CimInstance Win32_PageFileUsage -ErrorAction Stop;" ^
" $os = Get-CimInstance Win32_OperatingSystem;" ^
" if (-not $pf) { Write-Host 'No page file configured.'; exit 2 };" ^
" foreach ($p in $pf) {" ^
" $pctUsed = if ($p.AllocatedBaseSize -gt 0) {" ^
" [math]::Round(($p.CurrentUsage / $p.AllocatedBaseSize) * 100, 1)" ^
" } else { 0 };" ^
" $pctPeak = if ($p.AllocatedBaseSize -gt 0) {" ^
" [math]::Round(($p.PeakUsage / $p.AllocatedBaseSize) * 100, 1)" ^
" } else { 0 };" ^
" Write-Host '';" ^
" Write-Host ' --- Page File ---';" ^
" Write-Host \" Location: $($p.Name)\";" ^
" Write-Host \" Allocated: $($p.AllocatedBaseSize) MB\";" ^
" Write-Host \" Current Usage: $($p.CurrentUsage) MB ($pctUsed%%)\";" ^
" Write-Host \" Peak Usage: $($p.PeakUsage) MB ($pctPeak%%)\"" ^
" };" ^
" $totalRAM_MB = [math]::Round($os.TotalVisibleMemorySize / 1024);" ^
" $freeRAM_MB = [math]::Round($os.FreePhysicalMemory / 1024);" ^
" $usedRAM_pct = [math]::Round((1 - $os.FreePhysicalMemory / $os.TotalVisibleMemorySize) * 100, 1);" ^
" Write-Host '';" ^
" Write-Host ' --- Physical RAM ---';" ^
" Write-Host \" Total: $totalRAM_MB MB\";" ^
" Write-Host \" Free: $freeRAM_MB MB\";" ^
" Write-Host \" Used: $usedRAM_pct%%\";" ^
" Write-Host '';" ^
" $warn = $false;" ^
" foreach ($p in $pf) {" ^
" $pctUsed = if ($p.AllocatedBaseSize -gt 0) {" ^
" [math]::Round(($p.CurrentUsage / $p.AllocatedBaseSize) * 100, 1)" ^
" } else { 0 };" ^
" if ($pctUsed -gt 70) { $warn = $true }" ^
" };" ^
" if ($warn -and $usedRAM_pct -gt 85) {" ^
" Write-Host ' [WARNING] High page file AND physical RAM usage.' -ForegroundColor Yellow;" ^
" Write-Host ' The system is under significant memory pressure.' -ForegroundColor Yellow;" ^
" exit 1" ^
" } elseif ($warn) {" ^
" Write-Host ' [INFO] Page file usage is elevated but RAM has headroom.';" ^
" Write-Host ' Windows may be proactively paging idle data.';" ^
" exit 0" ^
" } else {" ^
" Write-Host ' [OK] Memory pressure is normal.';" ^
" exit 0" ^
" }" ^
"} catch {" ^
" Write-Error $_.Exception.Message;" ^
" exit 2" ^
"}"

set "PSResult=%errorlevel%"

if %PSResult% equ 2 (
echo [ERROR] Could not query page file status. >&2
)

endlocal
exit /b %PSResult%

Example of output:

[INFO] Querying Page File and memory status...

--- Page File ---
Location: C:\pagefile.sys
Allocated: 8192 MB
Current Usage: 2847 MB (34.7%)
Peak Usage: 5123 MB (62.5%)

--- Physical RAM ---
Total: 16384 MB
Free: 3241 MB
Used: 80.2%

[INFO] Page file usage is elevated but RAM has headroom.
Windows may be proactively paging idle data.

Why Peak Usage matters:

Current usage shows the state right now. Peak usage shows the highest point since the last reboot. If Peak is near 100% but current usage is low, the system experienced severe memory pressure at some point, possibly during a nightly backup, a scheduled scan, or a traffic spike. This historical high water mark reveals problems that have already passed and would otherwise be invisible.

Why the warning logic considers both metrics:

Windows proactively moves idle memory pages to the Page File to keep physical RAM available for active applications. This means some Page File usage is normal and healthy even when RAM is not full. The warning only triggers when both Page File usage is above 70% and physical RAM usage is above 85%, indicating genuine memory pressure rather than routine paging.

Method 2: Continuous Page File Monitoring with CSV Logging

For diagnosing memory issues that develop over time (leaks, gradual pressure increases, overnight peaks), log Page File and RAM metrics at regular intervals.

@echo off
setlocal EnableDelayedExpansion

set "LogFile=%~dp0pagefile_history.csv"
set "Interval=60"
set "WarnPct=70"

title Page File Monitor - Logging every %Interval%s

if not exist "%LogFile%" (
echo "Timestamp","PF_AllocatedMB","PF_UsedMB","PF_UsedPct","PF_PeakMB","RAM_TotalMB","RAM_FreeMB","RAM_UsedPct","Status" > "%LogFile%"
)

echo [MONITOR] Logging page file and RAM usage every %Interval% seconds.
echo [MONITOR] Log file: %LogFile%
echo [MONITOR] Press Ctrl+C to stop.
echo --------------------------------------------------

:PFLoop
for /f "tokens=1-8 delims=;" %%a in (
'powershell -NoProfile -Command "$pf=Get-CimInstance Win32_PageFileUsage -EA SilentlyContinue|Select -First 1;$os=Get-CimInstance Win32_OperatingSystem;if(-not $pf){Write-Output 'ERROR;0;0;0;0;0;0;0';exit 1};$ts=Get-Date -Format 'yyyy-MM-dd HH:mm:ss';$pfA=$pf.AllocatedBaseSize;$pfU=$pf.CurrentUsage;$pfP=$pf.PeakUsage;$pfPct=if($pfA-gt 0){[math]::Round(($pfU/$pfA)*100,1)}else{0};$ramT=[math]::Round($os.TotalVisibleMemorySize/1024);$ramF=[math]::Round($os.FreePhysicalMemory/1024);$ramPct=[math]::Round((1-$os.FreePhysicalMemory/$os.TotalVisibleMemorySize)*100,1);Write-Output ($ts,$pfA,$pfU,$pfPct,$pfP,$ramT,$ramF,$ramPct -join [char]59)"'
) do (
set "TS=%%a"
set "PFAlloc=%%b"
set "PFUsed=%%c"
set "PFPct=%%d"
set "PFPeak=%%e"
set "RAMTotal=%%f"
set "RAMFree=%%g"
set "RAMPct=%%h"
)

if "%TS%"=="ERROR" (
echo [%date% %time%] Could not read page file data. >&2
goto :PFWait
)

:: Determine status safely
set "Status=OK"
if defined PFPct (
powershell -NoProfile -Command "if ([double]'!PFPct!' -gt %WarnPct%) { exit 1 } else { exit 0 }" >nul 2>&1
if not errorlevel 1 set "Status=HIGH"
)

:: Fixed: Uses !VAR!%% for reliable % printing, removed broken ^) escapes
echo [%TS%] PF: %PFUsed%/%PFAlloc% MB (!PFPct!%%) Peak: %PFPeak% MB RAM: %RAMFree%/%RAMTotal% MB (!RAMPct!%% used)
echo "%TS%","%PFAlloc%","%PFUsed%","%PFPct%","%PFPeak%","%RAMTotal%","%RAMFree%","%RAMPct%","%Status%" >> "%LogFile%"

:PFWait
timeout /t %Interval% >nul
goto :PFLoop

What to look for in the CSV:

  • PF_UsedPct climbing steadily over hours: A memory leak is consuming RAM and forcing more data to the Page File.
  • PF_PeakMB near PF_AllocatedMB: The system nearly exhausted its Page File at some point. If the peak equals the allocation, the system may have experienced out-of-memory errors.
  • RAM_FreeMB dropping while PF_UsedMB rises: Direct evidence of memory pressure, physical RAM is being exhausted and the system is compensating with the Page File.
  • PF_UsedPct fluctuating without pattern: Normal Windows paging behavior. Not a concern unless combined with high RAM usage.

Method 3: Page File Configuration Audit

Before monitoring usage, it's useful to know how the Page File is configured, its location, whether it's system-managed or manually sized, and whether it's on an SSD or HDD.

@echo off
setlocal

echo [INFO] Page File Configuration:
echo.

powershell -NoProfile -Command ^
"$pfSettings = Get-CimInstance Win32_PageFileSetting -ErrorAction SilentlyContinue;" ^
"$pfUsage = Get-CimInstance Win32_PageFileUsage -ErrorAction SilentlyContinue;" ^
"if (-not $pfUsage) {" ^
" Write-Host ' No page file is currently active.';" ^
" Write-Host ' The system has no memory overflow protection.';" ^
" exit 1" ^
"};" ^
"foreach ($p in $pfUsage) {" ^
" Write-Host \" File: $($p.Name)\";" ^
" Write-Host \" Allocated: $($p.AllocatedBaseSize) MB\";" ^
" Write-Host \" Current Use: $($p.CurrentUsage) MB\";" ^
" Write-Host \" Peak Use: $($p.PeakUsage) MB\"" ^
"};" ^
"Write-Host '';" ^
"if ($pfSettings) {" ^
" foreach ($s in $pfSettings) {" ^
" $mgmt = if ($s.InitialSize -eq 0 -and $s.MaximumSize -eq 0) { 'System Managed' }" ^
" else { \"Manual: $($s.InitialSize) MB initial, $($s.MaximumSize) MB max\" };" ^
" Write-Host \" Config: $mgmt\"" ^
" }" ^
"} else {" ^
" Write-Host ' Config: System Managed (default)'" ^
"};" ^
"Write-Host '';" ^
"$drive = ($pfUsage[0].Name).Substring(0,2);" ^
"$diskType = Get-CimInstance Win32_DiskDrive | Where-Object {" ^
" $_.DeviceID -in (Get-CimInstance -Query \"ASSOCIATORS OF {Win32_LogicalDisk.DeviceID='$drive'} WHERE AssocClass=Win32_LogicalDiskToPartition\" |" ^
" ForEach-Object { (Get-CimInstance -Query \"ASSOCIATORS OF {Win32_DiskPartition.DeviceID='$($_.DeviceID)'} WHERE AssocClass=Win32_DiskDriveToDiskPartition\").DeviceID })" ^
"} | Select-Object -First 1;" ^
"if ($diskType.MediaType -match 'SSD|Solid') {" ^
" Write-Host ' Disk Type: SSD (good for paging)'" ^
"} elseif ($diskType.MediaType -match 'HDD|Fixed') {" ^
" Write-Host ' Disk Type: HDD (paging will be slow)' -ForegroundColor Yellow" ^
"} else {" ^
" Write-Host \" Disk Type: $($diskType.MediaType)\"" ^
"}"

endlocal
exit /b 0

Why disk type matters:

If pagefile.sys is on a mechanical HDD while the OS runs on an SSD, any Page File activity will cause severe performance degradation because HDD random I/O speeds are 100x slower than SSD. This audit identifies the configuration so you can move the Page File to the fastest available drive.

How to Avoid Common Errors

Wrong Way: Using wmic Output in Batch Arithmetic

:: BROKEN: wmic output contains invisible \r characters
for /f "tokens=2 delims==" %%a in ('wmic path Win32_PageFileUsage get CurrentUsage /value') do set "used=%%a"
set /a "pct=(%used% * 100) / %total%"

The variables used and total contain \r characters that cause set /a to fail with "missing operator" or produce incorrect results silently.

Correct Way: Use Get-CimInstance in PowerShell, which returns clean typed data and performs the arithmetic internally.

Wrong Way: Assuming All Page File Usage Is Bad

A system might show 20–30% Page File usage even with plenty of free RAM. Windows proactively moves idle memory pages to the Page File (a process called "modified page writing") to keep physical RAM available for active applications. This is normal, healthy behavior.

Correct Way: Only be concerned when Page File usage is consistently high (above 70%) and physical RAM is also under pressure (above 85% used). Look for trends, steadily increasing Page File usage over hours indicates a real problem.

Problem: No Page File Configured

Some systems are configured without a Page File (common in certain VM templates or misguided "optimization" guides). Without a Page File, the system has no overflow protection and will crash or kill processes when RAM is exhausted.

Solution: Method 3 detects this configuration and warns. If your monitoring script queries Win32_PageFileUsage on a system with no Page File, the query returns no results. Always handle the empty-result case.

Problem: System-Managed vs. Fixed-Size Page Files

When the Page File is system-managed, Windows can grow it dynamically. The AllocatedBaseSize may change between readings, making percentage calculations inconsistent.

Solution: Log the AllocatedBaseSize alongside usage in every reading (as shown in Method 2) so you can see if the allocation changed.

Best Practices and Rules

A single reading of "35% Page File used" is not actionable. A trend showing it climbing from 10% to 60% over 4 hours points to a memory leak. Use Method 2 for trend data.

2. Always Show Physical RAM Alongside Page File

Page File usage without RAM context is misleading. High Page File with high RAM usage means memory pressure. High Page File with low RAM usage means normal proactive paging. All methods in this guide show both metrics.

3. Check Peak Usage After Incidents

After a reported slowdown or crash, check Peak Usage (Method 1). It reveals whether the system hit memory limits even if it has since recovered.

4. Verify Page File Is on the Fastest Drive

If the Page File is on a mechanical HDD, any paging activity will feel like a system freeze. Use Method 3 to audit the configuration and consider moving pagefile.sys to an SSD.

5. Don't Disable the Page File

Some "optimization" guides recommend disabling the Page File. This is dangerous, without a Page File, the system will crash or kill processes when RAM is exhausted. Even systems with 64 GB of RAM benefit from a Page File as a safety net.

Conclusions

Monitoring Page File usage is a vital part of deep system diagnostics. By combining current usage, peak usage, and physical RAM context, and tracking these over time, you can distinguish between normal Windows paging behavior and genuine memory pressure. This visibility provides the data needed to justify hardware upgrades, identify memory-leaking applications, and ensure Page File configuration matches your performance requirements.