Skip to content

Instantly share code, notes, and snippets.

@NikiforovAll
Created November 20, 2025 12:53
Show Gist options
  • Select an option

  • Save NikiforovAll/64a5fbe2e1ae48d771fdd36537fab8af to your computer and use it in GitHub Desktop.

Select an option

Save NikiforovAll/64a5fbe2e1ae48d771fdd36537fab8af to your computer and use it in GitHub Desktop.
Measure-ProcessMemory.ps1
#!/usr/bin/env pwsh
<#
.SYNOPSIS
Measures the peak working set memory of a process.
.DESCRIPTION
Starts a process and reports its peak working set memory usage after completion.
Similar to the 'time' command but focuses on memory metrics.
.PARAMETER ProcessPath
The path to the executable to run.
.PARAMETER Arguments
Optional arguments to pass to the process.
.PARAMETER Unit
Memory unit for output: 'MB' (default), 'GB', or 'KB'.
.EXAMPLE
.\Measure-ProcessMemory.ps1 -ProcessPath ".\test.exe"
.\Measure-ProcessMemory.ps1 ".\test.exe" arg1 arg2
.\Measure-ProcessMemory.ps1 ".\app.exe" -verbose --config settings.json
.\Measure-ProcessMemory.ps1 ".\app.exe" arg1 arg2 -Unit GB
.NOTES
The script displays memory metrics after the process exits.
Arguments can be passed directly without the -Arguments flag.
#>
param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="Path to the executable")]
[string]$ProcessPath,
[Parameter(Mandatory=$false, Position=1, ValueFromRemainingArguments=$true, HelpMessage="Arguments to pass to the process")]
[string[]]$Arguments,
[Parameter(Mandatory=$false, HelpMessage="Memory unit: MB, GB, or KB")]
[ValidateSet("MB", "GB", "KB")]
[string]$Unit = "MB"
)
# Validate that the process exists (check PATH and local files)
$resolvedPath = $null
if (Test-Path $ProcessPath) {
$resolvedPath = $ProcessPath
} else {
$resolvedPath = (Get-Command $ProcessPath -ErrorAction SilentlyContinue).Source
}
if (-not $resolvedPath) {
Write-Error "Process not found: $ProcessPath"
exit 1
}
Write-Host "Starting process: $ProcessPath"
if ($Arguments) {
Write-Host "Arguments: $Arguments"
}
Write-Host ""
# Track execution time
$startTime = Get-Date
# Start the process
try {
if ($Arguments -and $Arguments.Count -gt 0) {
$process = Start-Process -FilePath $resolvedPath -ArgumentList $Arguments -PassThru -NoNewWindow
} else {
$process = Start-Process -FilePath $resolvedPath -PassThru -NoNewWindow
}
} catch {
Write-Error "Failed to start process: $_"
exit 1
}
$processId = $process.Id
Write-Host "Process ID: $processId"
# Monitor memory usage while the process is running
$peakWorkingSet = 0
$peakVirtualMemory = 0
# Immediate first reading to catch short-lived processes
try {
$currentProcess = Get-Process -Id $processId -ErrorAction Stop
$peakWorkingSet = $currentProcess.WorkingSet64
$peakVirtualMemory = $currentProcess.VirtualMemorySize64
} catch {
# Process already exited
}
# Continue monitoring
while (-not $process.HasExited) {
try {
$currentProcess = Get-Process -Id $processId -ErrorAction Stop
$currentWorkingSet = $currentProcess.WorkingSet64
$currentVirtualMemory = $currentProcess.VirtualMemorySize64
if ($currentWorkingSet -gt $peakWorkingSet) {
$peakWorkingSet = $currentWorkingSet
}
if ($currentVirtualMemory -gt $peakVirtualMemory) {
$peakVirtualMemory = $currentVirtualMemory
}
Start-Sleep -Milliseconds 10
} catch {
# Process might have exited
break
}
}
# Final check for peak values from the process object
try {
$process.Refresh()
if ($process.PeakWorkingSet64 -gt $peakWorkingSet) {
$peakWorkingSet = $process.PeakWorkingSet64
}
if ($process.PeakVirtualMemorySize64 -gt $peakVirtualMemory) {
$peakVirtualMemory = $process.PeakVirtualMemorySize64
}
} catch {
# Use the values we monitored
}
# Calculate execution time
$endTime = Get-Date
$executionTime = $endTime - $startTime
# Convert to requested unit
$divisor = switch ($Unit) {
"MB" { 1MB }
"GB" { 1GB }
"KB" { 1KB }
}
$peakWorkingSetConverted = [math]::Round($peakWorkingSet / $divisor, 2)
$peakVirtualMemoryConverted = [math]::Round($peakVirtualMemory / $divisor, 2)
# Display results
Write-Host ""
Write-Host "=== Memory Statistics ==="
Write-Host "Peak Working Set: $peakWorkingSetConverted $Unit"
Write-Host " * Physical RAM used by the process at its peak"
Write-Host ""
Write-Host "Peak Virtual Memory: $peakVirtualMemoryConverted $Unit"
Write-Host " * Total address space reserved (physical + virtual/paged memory)"
Write-Host ""
Write-Host "=== Execution Statistics ==="
Write-Host "Execution Time: $($executionTime.TotalSeconds) seconds"
Write-Host "Exit Code: $($process.ExitCode)"
Write-Host ""
Write-Host "* Hint: Working Set shows actual RAM usage, while Virtual Memory includes"
Write-Host " memory that may be paged to disk. Working Set is typically the more"
Write-Host " relevant metric for understanding real memory consumption."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment