The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Use a two-threshold policy: start moving files only when the source volume drops below a trigger level, then stop after it recovers to a higher target. The script below selects old files, checks both drives before every transfer, preserves folders, skips collisions, verifies cross-volume copies, supports -WhatIf, and logs each result.
What “based on free space” should mean
There are two separate decisions:
- Source trigger: for example, begin when
C:has less than 20 GB available. - Source target: stop when it reaches 50 GB available.
- Destination floor: never let
D:fall below a reserve such as 100 GB.
Using different trigger and target values prevents constant start/stop cycles. The script measures System.IO.DriveInfo.AvailableFreeSpace, which represents space available to the current user. Microsoft also documents Get-PSDrive and its .Free property, but that command can include PowerShell and mapped drives in addition to file-system volumes. See Microsoft’s Get-PSDrive documentation.
PowerShell’s 1GB constant is 1,073,741,824 bytes (binary gigabytes), not the decimal units used on drive packaging.
Ready-to-run PowerShell script
Save this as Move-FilesByFreeSpace.ps1. It moves files older than the configured age, oldest first, and keeps each source directory’s relative path in the archive.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →#1 Best Overall
- Easily store and access 2TB to content on the go with the Seagate Portable Drive, a USB external hard drive
- Designed to work with Windows or Mac computers, this external hard drive makes backup a snap just drag and drop
- To get set up, connect the portable hard drive to a computer for automatic recognition no software required
- This USB drive provides plug and play simplicity with the included 18 inch USB 3.0 cable
- The available storage capacity may vary.
[CmdletBinding(SupportsShouldProcess)]
param(
[string]$SourceRoot = 'C:Recordings',
[string]$DestinationRoot = 'D:Archive',
[string]$SourceDrive = 'C',
[string]$DestinationDrive = 'D',
[double]$TriggerFreeGB = 20,
[double]$TargetFreeGB = 50,
[double]$DestinationFloorGB = 100,
[int]$MinimumAgeHours = 24,
[string[]]$Extensions = @('.mp4', '.mkv', '.avi', '.zip'),
[string]$LogPath = 'C:LogsMoveFilesByFreeSpace.log',
[switch]$VerifyHash
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Write-Log {
param([string]$Message, [ValidateSet('INFO','WARN','ERROR')][string]$Level='INFO')
$line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') [$Level] $Message"
$dir = Split-Path -Parent $LogPath
if ($dir -and -not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
Add-Content -LiteralPath $LogPath -Value $line
Write-Output $line
}
function Get-AvailableFreeBytes {
param([string]$DriveLetter)
$root = "$($DriveLetter.TrimEnd(':')):"
$drive = [System.IO.DriveInfo]::new($root)
if (-not $drive.IsReady) { throw "Drive $root is not ready." }
[int64]$drive.AvailableFreeSpace
}
function Get-RelativeDestinationPath {
param([string]$FilePath, [string]$RootPath)
$root = (Resolve-Path -LiteralPath $RootPath).Path.TrimEnd('')
$full = (Resolve-Path -LiteralPath $FilePath).Path
if (-not $full.StartsWith($root, [StringComparison]::OrdinalIgnoreCase)) { throw "File is outside source root." }
$full.Substring($root.Length).TrimStart('')
}
try {
if (-not (Test-Path -LiteralPath $SourceRoot -PathType Container)) { throw "Source folder does not exist: $SourceRoot" }
if (-not (Test-Path -LiteralPath $DestinationRoot -PathType Container)) { New-Item -ItemType Directory -Path $DestinationRoot -Force | Out-Null }
if ($TargetFreeGB -le $TriggerFreeGB) { throw 'TargetFreeGB must be greater than TriggerFreeGB.' }
$trigger = [int64]($TriggerFreeGB * 1GB)
$target = [int64]($TargetFreeGB * 1GB)
$floor = [int64]($DestinationFloorGB * 1GB)
$sourceFree = Get-AvailableFreeBytes $SourceDrive
$destinationFree = Get-AvailableFreeBytes $DestinationDrive
Write-Log "Source free: $([math]::Round($sourceFree/1GB,2)) GB; destination free: $([math]::Round($destinationFree/1GB,2)) GB"
if ($sourceFree -ge $trigger) { Write-Log 'Source is above trigger; nothing to move.'; return }
$cutoff = (Get-Date).AddHours(-$MinimumAgeHours)
$files = Get-ChildItem -LiteralPath $SourceRoot -File -Recurse |
Where-Object { $_.LastWriteTime -lt $cutoff -and ($Extensions.Count -eq 0 -or $Extensions -contains $_.Extension.ToLowerInvariant()) } |
Sort-Object LastWriteTime, Length
if (-not $files) { Write-Log 'No eligible files found.' 'WARN'; return }
foreach ($file in $files) {
if ((Get-AvailableFreeBytes $SourceDrive) -ge $target) { Write-Log 'Target free space reached.'; break }
$destinationFree = Get-AvailableFreeBytes $DestinationDrive
if (($destinationFree - $file.Length) -lt $floor) { Write-Log "Skipping $($file.FullName): destination floor would be breached." 'WARN'; continue }
$relative = Get-RelativeDestinationPath $file.FullName $SourceRoot
$destinationPath = Join-Path $DestinationRoot $relative
if (Test-Path -LiteralPath $destinationPath) { Write-Log "Skipping $($file.FullName): destination exists." 'WARN'; continue }
if (-not $PSCmdlet.ShouldProcess($file.FullName, "Move to $destinationPath")) { Write-Log "WhatIf: would move $($file.FullName) to $destinationPath."; continue }
try {
$destinationDirectory = Split-Path -Parent $destinationPath
if (-not (Test-Path -LiteralPath $destinationDirectory)) { New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null }
Copy-Item -LiteralPath $file.FullName -Destination $destinationPath
$copied = Get-Item -LiteralPath $destinationPath
if ($copied.Length -ne $file.Length) { throw 'Destination size does not match source.' }
if ($VerifyHash) {
if ((Get-FileHash $file.FullName -Algorithm SHA256).Hash -ne (Get-FileHash $destinationPath -Algorithm SHA256).Hash) { throw 'SHA-256 hashes do not match.' }
}
Remove-Item -LiteralPath $file.FullName
Write-Log "Moved $($file.FullName) to $destinationPath."
} catch {
Write-Log "Failed to move $($file.FullName): $($_.Exception.Message)" 'ERROR'
if (Test-Path -LiteralPath $destinationPath) { Remove-Item -LiteralPath $destinationPath -Force -ErrorAction SilentlyContinue }
}
}
Write-Log "Final source free: $([math]::Round((Get-AvailableFreeBytes $SourceDrive)/1GB,2)) GB"
} catch { Write-Log $_.Exception.Message 'ERROR'; exit 1 }
Customize the policy
Run a safe dry run first
.[0mMove-FilesByFreeSpace.ps1 -WhatIf
Use disposable test files and confirm the log before allowing deletion.
Change age and extensions
.[0mMove-FilesByFreeSpace.ps1 -MinimumAgeHours (7 * 24)
.[0mMove-FilesByFreeSpace.ps1 -Extensions @()
An empty extension array allows every file. Age is a safety filter, not proof that a file is complete; recordings and downloads can remain open while appearing old.
Rank #2
- Easily store and access 5TB of content on the go with the Seagate portable drive, a USB external hard Drive
- Designed to work with Windows or Mac computers, this external hard drive makes backup a snap just drag and drop
- To get set up, connect the portable hard drive to a computer for automatic recognition software required
- This USB drive provides plug and play simplicity with the included 18 inch USB 3.0 cable
- The available storage capacity may vary.
Verify content
.[0mMove-FilesByFreeSpace.ps1 -VerifyHash
Every copied file is checked for length, and SHA-256 when requested. Hashing adds read time but gives stronger assurance before source deletion.
Use percentages
$drive = [System.IO.DriveInfo]::new('C:')
$freePercent = ($drive.AvailableFreeSpace / $drive.TotalSize) * 100
Percent thresholds adapt to different volume sizes; absolute GB thresholds are easier to predict on a known machine.
Rank #3
- Easily store and access 1TB to content on the go with the Seagate Portable Drive, a USB external hard drive.Specific uses: Personal
- Designed to work with Windows or Mac computers, this external hard drive makes backup a snap just drag and drop. Reformatting may be required for Mac
- To get set up, connect the portable hard drive to a computer for automatic recognition no software required
- This USB drive provides plug and play simplicity with the included 18 inch USB 3.0 cable
- The available storage capacity may vary.
Why copy, verify, then delete?
Within one volume, a file-system move can simply rename directory metadata. Across volumes, the operation is effectively a copy followed by deletion. The script therefore does not remove the source until the destination exists and its size matches; optional hashes provide an additional check. This reduces risk but cannot protect against hardware failure, interruption, or filesystem corruption. A move is not a backup because the source copy is removed.
The script skips existing destination paths rather than overwriting them. Microsoft documents that Move-Item does not overwrite same-name files by default and that -Force changes that behavior; do not add -Force unless replacement is intentional. See Move-Item documentation.
Rank #4
- Easily store and access 4TB of content on the go with the Seagate Portable Drive, a USB external hard drive.Specific uses: Personal
- Designed to work with Windows or Mac computers, this external hard drive makes backup a snap just drag and drop
- To get set up, connect the portable hard drive to a computer for automatic recognition no software required
- This USB drive provides plug and play simplicity with the included 18 inch USB 3.0 cable
- The available storage capacity may vary.
Scheduling with Task Scheduler
- Create a task set to run whether the user is logged on or not, under an account that can read the source, write the destination, delete source files, and write the log.
- Set the action to the executable installed on that machine: Windows PowerShell 5.1 commonly uses
C:WindowsSystem32WindowsPowerShellv1.0powershell.exe; PowerShell 7 usespwsh.exewhen installed. - Use arguments such as
-NoProfile -ExecutionPolicy Bypass -File "C:ScriptsMove-FilesByFreeSpace.ps1", and set a single-instance policy so overlapping runs are not started. - Prefer UNC paths such as
\servershareArchivefor network destinations. Mapped letters can be unavailable to another account or session; Microsoft describes this limitation in Get-PSDrive.
Robocopy alternative
For large transfers, retries, or network paths, Robocopy is often more resilient:
robocopy C:Recordings D:Archive /S /MOV /MINAGE:1 /LFSM:100G /R:2 /W:5 /LOG:C:Logsrecordings.log
/Sincludes non-empty subdirectories./MOVdeletes source files only after successful copying./MINAGE:1selects files at least one day old./LFSM:100Gpauses to preserve 100 GB on the destination volume./R:2and/W:5limit retries and wait time;/LOG:records output.
/LFSM protects the destination floor, not the source trigger/target policy, so wrap Robocopy in a PowerShell check or schedule it conditionally. Microsoft notes that the default LFSM floor is 10% when no value is supplied and that LFSM cannot be combined with /MT or /EFSRAW. Robocopy exit codes below 8 can indicate successful copying with differences; codes 8 and higher indicate at least one failure. See Microsoft’s Robocopy reference. Avoid /MIR unless you explicitly want destination deletions.
Best Value
- [Upgraded Version] - This external hard drive features a mirrored logo stripe combined with a striped anti-slip design, and the rounded corners of the casing make it easier to grip. The stripes also have a heat dissipation function, ensuring stable and fast data transfer.
- 【Ultra-thin and quiet】 - The motherboard adopts JMicron 578 noise-free solution, giving you a quiet working environment. Lightweight and portable size designed to fit in your pocket for easy portability.
- 【Ultra-Fast Data Transfers】 - Pairing this external hard drive with JMicron 578 solution USB 3.0 and USB 2.0 interfaces enables blazing-fast data transfer. It boasts theoretical read speeds of up to 125MB/s and write speeds of up to 103MB/s.
- 【Plug and Play】 - With no software to install, just plug it in and the drive is ready to use.The hard disk chip is wrapped with an aluminum anti-interference layer to increase heat dissipation and protect data.
- 【What You Get】 - 1 x Portable Hard Drive, 1 x USB 3.0 Cable, 1 x User Manual, Gift-type shell packaging ,Three-year manufacturer's warranty and free technical support services.
Troubleshooting and operational safeguards
- Locked or growing files: the script logs the error and continues. Increase
MinimumAgeHours, require stable size/time across two scans, or stop the producing application. - Destination unavailable: check
Test-Path -LiteralPath $DestinationRootand verify removable-drive identity before restarting. - Access denied: grant the task account source read/delete, destination write, share, and log permissions; administrator elevation does not automatically solve network authentication.
- Junctions and links: recursive scans can reach unexpected trees. Restrict the source or filter reparse points, for example
Where-Object { -not ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) }. Robocopy users can consider/XJ. - Insufficient room for one file: the script skips files that would breach the destination reserve and continues with later candidates.
- Same physical disk: moving from one partition letter to another frees the source volume but does not add physical capacity, redundancy, or backup protection.
When another Windows feature fits better
Storage Sense automatically removes supported cleanup categories such as temporary files and Recycle Bin contents. It is not a customizable archive mover for selected files and a chosen destination. See Microsoft’s Storage Sense guide.
Frequently Asked Questions
Can I use one threshold instead of two?
You can, but separate trigger and target values provide hysteresis and prevent repeated short runs.
Does this script guarantee no data loss?
No. Copy verification and logging reduce operational risk; maintain independent backups and test recovery.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

