Script to move files based on drive free space

Binky

Diamond Member
Oct 9, 1999
4,046
4
81
I'm looking for a script/batch file to move files to another location when the free disk space on the drive reaches a defined level. Has anybody ever written something like this?

Example of a script that might run every night:
Code:
if D: free space is less than 50GB
then move the oldest files in FOLDER1 to FOLDER2, until D: free space is 100GB

It seems like powershell is well suited to this but I can't quite find a script to do this. Sadly, my scripting skills are also not good enough.
 

Binky

Diamond Member
Oct 9, 1999
4,046
4
81
I've got something mostly working in powershell...

Code:
$drive_need = 100
$tv_folder1 = "D:\Recorded TV"
$tv_folder2 = "\\Server\Recorded TV"
$drive_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='D:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})

While ($drive_need -gt $drive_free)
{
$drive_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='D:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})
$move_file = dir $tv_folder1 | sort lastwritetime | select -first 1
copy-item $move_file $tv_folder2
remove-item $move_file
}

The flaw here is that this file is written so it has to be in the folder its testing, and eventually the script itself will be the oldest file, and it will try to move itself. I guess I'll fix that tomorrow.
 
Last edited:

MerlinRML

Senior member
Sep 9, 2005
207
0
71
I have done very little with powershell, which is why I'm looking to see what you're doing here. Please excuse my ignorance if this is all handled somehow.

Hope you don't mind if I bug you with a few questions and observations...

Why did you chose to do a copy-item followed by remove-item instead of just a move-item? The only thing I could think of was that you wanted to verify that data copied properly, but you have no checks or error handling. Is this something you intend to add later?

Do you plan to add error-handling around the copy-item? I'd be concerned about doing a copy that fails because the disk is full, network is down, etc followed by an immediate remove. Without error checking, you could delete your only copy of data.

Edit:
Also, I noticed that you're recalculating free space first in your loop, wouldn't you want to move that to the end of the loop after you've deleted the data?
 
Last edited:

Binky

Diamond Member
Oct 9, 1999
4,046
4
81
I ended up using copy and remove because I started out doing this in an entirely different way, and move didn't support the way I was doing it with powershell pipelining. I have to look at whether this will work with the simpler (and maybe safer) move command. I have no idea what I'm doing, so I'm just hacking together pieces of code I find, and seeing what the result is.

Good point on the recalculating free space at the end of the loop. That's easy enough to change. I can also easily add a freespace check on the target drive, and this might also serve as an error test.
 

Binky

Diamond Member
Oct 9, 1999
4,046
4
81
Here's the (hopefully) final script. I have very little idea of what I'm doing, so this code is guaranteed to be poorly written, and it might break things, so be careful if you choose to use it in any way.

What it does:
Checks the D drive for 150GB of space - stops if there is > 150GB
Check the server for 200Gb of space - stops and emails a warning if < 200GB
Move (copy then delete) the oldest WTV file in the recorded TV folder
Move (copy then delete) the related log file for showanalyzer in the recorded TV folder
Logs what was moved and deleted to a text file on D drive

Code:
#Windows powershell script to move files based on free space
$drive_need = 150  #target D space minimum in GB 
$server_need = 200  #target Server space minimum in GB 
$tv_folder1 = "D:\Recorded TV"
$tv_folder2 = "\\Server\Recorded TV"
$File ="D:\TVmovelog.txt"  #log file
$drive_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='D:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})
$server_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='Y:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})

Get-Date | Out-File $File -append

if ($drive_free -gt $drive_need)  # If there is enough space, do nothing
    {
    write-output ("D: has $drive_free GB of free space - aborted file moving") | out-file $file -append
    exit
    }
if ($server_free -lt $server_need)  # If the sever doesn't have enough room, just send a warning email, then stop
    {
    write-output ("Not enough free space - aborted file moving") | out-file $file -append
    $EmailFrom = "EMAILADDYHERE@gmail.com"
    $EmailTo = "EMAILADDYHERE@gmail.com" 
    $Subject = "Notification from HTPC" 
    $Body = "The server has less than $server_need GB of disk space" 
    $SMTPServer = "smtp.gmail.com" 
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587) 
    $SMTPClient.EnableSsl = $true 
    $SMTPClient.Credentials = New-Object System.Net.NetworkCredential("GMAILUSRNAME", "GMAILPASS"); 
    $SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
    exit
    }

While ($drive_need -gt $drive_free)  # As long as D: space is less than needed, move the oldest WTV file and its associated log file
    {
    try
    {
    $move_file = dir $tv_folder1 *.wtv | sort lastwritetime | select -first 1  # Get the name of the oldest WTV file
    copy-item $move_file $tv_folder2
    $move_log = $move_file -replace ".wtv$", ".log" # convert to log file name
    $move_log = dir $tv_folder1 $move_log  # Get the name of the oldest log file
    copy-item $move_log $tv_folder2
    write-output ("Successfully copied $move_file") | out-file $file -append
    }
    catch  # watch for error, don't delete file(s) is there is an error (I have no idea if this trapping works)
    {
    write-output ("Could not copy file - aborted") | out-file $file -append
      exit
    }
    remove-item $move_file  #Not necessary for ME to remove the log too, since it's disapearing on its own. Could be showanalzer cleaning up. 
    #remove-item $move_log
    write-output ("Successfully deleted $move_file and $move_log") | out-file $file -append
    $drive_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='D:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})
}