ProcessCap starts a Windows executable with configurable CPU-affinity and memory restrictions.
The launcher uses a Windows Job Object to apply a hard memory limit to the launched process and its child processes. CPU access is restricted with a processor-affinity mask. Processor affinity controls which logical processors may run the application; it is not an exact CPU-percentage throttle.
The application is implemented in one C# source file. It can run as a .NET 10 file-based app, or Windows PowerShell 5.1 and later.
Unlike the Number of processors and Maximum memory options under System Configuration (msconfig) > Boot > Advanced options, which change resources available to the entire Windows system and require a computer restart, ProcessCap applies restrictions only to the selected application and its child processes. No restart is required, and limits can be changed between launches. This makes ProcessCap useful for quickly finding an application's practical lower CPU and memory boundaries before deciding whether to test corresponding system-level limitations.
ProcessCap.cs— complete file-based C# application.ProcessCap.ps1— PowerShell wrapper that compiles and invokesProcessCap.csdirectly.
- Windows 10 or later.
- Windows on x86, x64, or ARM64 hardware.
- For direct C# file-app execution: .NET 10 SDK or later available through the
dotnetcommand. - For PowerShell execution: Windows PowerShell 5.1 or later. The separate .NET SDK is not required.
Confirm that .NET is installed when using the direct C# version:
dotnet --versionConfirm that a supported PowerShell version is installed when using the PowerShell version:
$PSVersionTable.PSVersionProcessCap is available from the Windows Package Manager Community Repository. Install it with:
winget install --id tazayan.ProcessCap --exactUpgrade to the latest published version with:
winget upgrade --id tazayan.ProcessCap --exactUninstall ProcessCap with:
winget uninstall --id tazayan.ProcessCap --exactAfter installation, start the application from a terminal with:
processcapOpen PowerShell in this directory and run:
dotnet run --file .\ProcessCap.csYou can also provide the full path from another directory:
dotnet run --file "fullpath"From this directory, run:
.\ProcessCap.ps1The wrapper resolves ProcessCap.cs relative to its own location, compiles it into an in-memory assembly with Add-Type, and calls ProcessCap.Program.Main().
It can also be invoked from another working directory:
& "fullpath"If the local PowerShell execution policy prevents the script from running, use a process-scoped bypass:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\ProcessCap.ps1This bypass applies only to that PowerShell process and does not change the system execution policy.
The C# source intentionally uses syntax and framework APIs compatible with the compiler included in Windows PowerShell 5.1.
The launcher displays system information and requests the following values:
- Application executable path — path to an existing
.exefile. - Application arguments — optional arguments passed to the application.
- Working directory — press Enter to use the executable's directory.
- Logical processors to allow — press Enter to allow the displayed default.
- Total memory limit in MB — hard memory limit for the complete job.
After collecting the values, the launcher:
- Creates the target process in a suspended state.
- Assigns it to a Windows Job Object.
- Applies the job memory limit and CPU-affinity mask.
- Resumes the process and verifies the restrictions.
- Waits for the process to exit.
Keep the launcher open while the restricted application is running. Closing the launcher closes the Job Object and terminates processes assigned to it.
The source can be compiled without a project file:
dotnet build .\ProcessCap.cs -p:PublishAot=false -p:Nullable=disableNative AOT is disabled because the Windows version lookup uses runtime WinRT reflection. Nullable analysis is disabled for this build because the source intentionally remains compatible with the C# compiler included in Windows PowerShell 5.1.
To publish an executable for a specific Windows architecture, use its runtime identifier:
dotnet publish .\ProcessCap.cs -c Release -r win-x64 --self-contained true -p:PublishAot=false
dotnet publish .\ProcessCap.cs -c Release -r win-x86 --self-contained true -p:PublishAot=false
dotnet publish .\ProcessCap.cs -c Release -r win-arm64 --self-contained true -p:PublishAot=falseTo request a single-file executable:
dotnet publish .\ProcessCap.cs -c Release -r win-x64 --self-contained true -p:PublishAot=false -p:PublishSingleFile=trueThe dotnet publish output reports the generated publish directory.
To produce single-file builds for all three supported architectures in one operation:
.\Publish-All.ps1The builds are written to artifacts\win-x86, artifacts\win-x64, and artifacts\win-arm64.
- CPU affinity is limited to at most 32 logical processors in an x86 launcher and 64 in an x64 or ARM64 launcher because Windows affinity masks are pointer-sized.
- An x86 launcher can set a job-memory limit of at most 4095 MB because the native Windows structure uses a pointer-sized value. x64 and ARM64 builds do not have that restriction.
- The memory value is a total Job Object memory limit shared by the launched application and its child processes.
- Selecting a limit above currently available memory may cause the application to reach the limit sooner.
- Raw application arguments are passed to the target executable exactly as entered.
- The launcher is Windows-specific because it depends on native Windows Job Object APIs.