Batch mode and scripting
batch works on several images at once. It takes any number of image files and folders; folders are searched in depth for disk images.
Listing
Without further options, batch only analyses: one line per image with what a trim would free, and a total. This needs no licence.
D:\VMs\Debian 13.qcow2: 1.0 GB, a trim would free 246.4 MB D:\VMs\Fedora Cloud.qcow2: declined: Cluster 0 is compressed; convert the image with qemu-img convert first D:\VMs\Home Assistant.vdi: 944.1 MB, a trim would free 0 B D:\VMs\Kali Linux.vhdx: 16.7 GB, a trim would free 971.0 MB D:\VMs\openSUSE Tumbleweed.vmdk: 747.6 MB, a trim would free 19.0 MB D:\VMs\Ubuntu Server 24.04.vhd: 30.0 GB, a trim would free 1.3 GB D:\VMs\Windows 10.vhdx: 18.3 GB, a trim would free 2.6 GB D:\VMs\Windows Server 2022.vhd: 9.5 GB, a trim would free 20.0 MB 8 images, 77.2 GB, a trim would free 5.1 GB
Trimming
vdtrim batch --replace D:\VMs
:: write trimmed copies to another folder, originals untouched
vdtrim batch --output-dir E:\Trimmed D:\VMs
:: a scheduled task that keeps a folder of templates lean
vdtrim batch --replace --discard all --json C:\Logs\vdtrim.json D:\Templates
The images are trimmed one after another. An image that is declined or fails does not stop the run: its reason is printed and the next image follows, so a machine that happens to be running is simply skipped as in use and picked up the next time. With --output-dir each copy keeps the name and format of its original. The options --discard, --zero-free, --no-verify, --json and --progress work as for trim.
Before trimming, batch compares the space the results need with what is free. Images for which there is clearly no room are declined and the rest are trimmed; when space is merely tight, a warning is printed.
Recovering after an interruption
If a --replace run was killed or the computer lost power in the middle of it, files may be left beside the image. vdtrim recover image puts the disk back in order: depending on how far the trim had got, the original comes back or the verified trimmed disk is put in place. The command says which, and needs no licence.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success. |
| 1 | Declined: an image could not be trimmed safely, or there was nothing to gain. The image is unchanged. Batch returns the highest code among its images. |
| 2 | Error, such as a file that cannot be read or written. |
| 3 | The command line was not understood. |
| 4 | Trimming was asked for and no licence is installed. |
| 5 | The installed licence is no longer valid. |
JSON report
--json file on analyse, trim and batch writes everything the command found as a JSON document; --json - prints it to standard output in place of the text. File → Save Report in the application window saves the same document for the images in its list. All sizes are in bytes, and the values are fixed identifiers that do not change with the language of the window.
{
"schema" : 1,
"product" : "SoftPerfect Virtual Disk Trim",
"version" : "1.0",
"generated" : "2026-10-08T02:45:53Z",
"images" : [
{
"file" : "D:\\VMs\\openSUSE Tumbleweed.vmdk",
"outcome" : "ok",
"status" : "ready",
"leftover" : "none",
"analysis" : {
"fileSize" : 783941632,
"sizeOnDisk" : 783941632,
"format" : "vmdk",
"layout" : "single",
"files" : [ "D:\\VMs\\openSUSE Tumbleweed.vmdk" ],
"virtualSize" : 25769803776,
"partitioning" : "gpt",
"volumes" : [ ... ],
"reclaimable" : { ... }
},
"trim" : {
"status" : "saved",
"output" : "E:\\Trimmed\\openSUSE Tumbleweed.vhdx",
"outputFormat" : "vhdx",
"outputSize" : 774897664,
"sourceSize" : 783941632,
"saved" : 9043968,
"verified" : true
}
}
]
}
The example is shortened. The fields a script most often needs:
| Field | Content |
|---|---|
images[].outcome |
ok, declined or failed. |
images[].reason, reasonKind |
For an image declined or failed at analysis (a trim that was declined or failed carries the same two fields under trim): the explanation as an English sentence, and its kind as an identifier such as inUse, unclean, snapshot or unsupported. |
images[].leftover |
none, or what an interrupted trim left beside the image. |
analysis.volumes[] |
Each partition and volume: type, position, file system, label, total, used and free bytes, and any page, swap or hibernation files found. A volume that is not trimmed carries its own reason and reasonKind. |
analysis.reclaimable |
What a trim would free, at the image’s own block size and at 1 MB blocks, with and without discarding page, swap and hibernation files. |
trim.output, outputFiles |
The output and, for a disk of several files, every file it consists of. |
trim.saved |
How many bytes smaller the output is than the source, by the room each takes on the disk. |
trim.verified |
Whether the output was compared with the source. |