or Connect
AVS › AVS Forum › Video Components › Home Theater Computers › Powershell script to move files when space is low
New Posts  All Forums:Forum Nav:

Powershell script to move files when space is low

post #1 of 5
Thread Starter 
I'm sure that many people here have setups where an HTPC box records TV files on a local drive, and eventually some of those files might be moved to a server or NAS with more storage. I have a 1TB drive on my primary recording machine with 4 HD tuners, so it can fill up pretty fast. I tried the MCE addin for WHS, but it just wasn't what I wanted. I needed an efficient way to move files to my WHS machine without having to constantly monitor it, or respond to MCE's warnings that it was about to delete recordings. I'd get hell if Dancing With the Stars started disappearing!

I searched but could not find a script to check the hard drive space, and move files as needed to the server, so I made the following script through trial and error. I have zero previous knowledge of powershell. I'm sure that this code is terribly written, but it seems to work for me.

If you can use something like this, give it a try, but test it out first on dummy folders. If you can improve the code, please do!

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 (see comment on the code below)
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)})
}
DISCLAIMER - please don't break anything and blame me! Test the code on dummy folders!
post #2 of 5
Thread Starter 
I've updated my (Rube Goldberg) script. Sure, it's overly complicated and probably horribly inefficient code, but it works perfectly for me. Since nobody replied to my original topic, I'm assuming that I'm the only one using it! eek.gif

Usage scenario: You have an HTPC with a small-ish hard drive (500gb-1TB) where you record and store the latest recordings via 7MC, and you use DTB and showanalyzer to mark commercials. You also have a server machine where you store other TV shows. You prefer to keep TV shows on the local D drive, up to some preset free space minimum (default = 150gb). You are tired of manually moving shows around and the only solution (that I found) is to automatically move ALL TV shows once they are recorded (and you don't want this). With this script scheduled to run every night via a batch file, you don't have to do anything manually. biggrin.gif

If you don't want exactly this usage scenario, it should be very easy to adapt the existing code.

Old/existing features:
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 (see comment on the code below)
Logs what was moved and deleted to a text file on D drive

NEW features:
Cleans up orphaned showanalyzer files (*.vih and *.xml)
Cleans up orphaned log files from both TV locations
Manually processes any unprocessed TV shows by showanlayzer (can't remember why I added this...maybe I turned off auto processing...?)
Logs any log/vih/xml deletions to a text file on D drive

To use, you need to configure the variables at the top. Also, search for EMAIL and replace as necessary.
Code:
Add-Type -AssemblyName Microsoft.VisualBasic
Get-Date | Out-File $File -append

#************************Change these variables************************
$drive_need = 150  #target D space minimum in GB 
$server_need = 200  #target Server space minimum in GB 
$tv_folder1 = "D:\Recorded TV"  #Source TV folder
$tv_folder2 = "\\server\Recorded TV"  #Desination/server TV folder
$xml_folder = "C:\Users\Public\DvrmsToolbox\CommercialsXml" #Location of showanalyzer XML files
$File ="D:\TVmovelog.txt"  #log file
$drive_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='D:'"| ForEach-Object {[math]::round($_.freespace / 1GB)})  # change the D: to refer to your local drive
$server_free = (get-WMIObject win32_LogicalDisk -filter "DeviceID='Y:'"| ForEach-Object {[math]::round($_.freespace / 1GB)}) # change the Y: to refer to your server drive
# Two lines identical to the above are at the end of the script. Change the D and Y as needed there too.
# I had to map the server drive to get this space test working - if anybody knows how to make this happen without the map, let me know!
$cmd = 'C:\Program Files (x86)\DVRMSToolbox\DVRMStoMPEG.exe'


#************************Get a list of all the files in the various folders************************
$list = Get-ChildItem -Path $tv_folder1 -Filter *.wtv
$list += Get-ChildItem -Path $tv_folder2 -Filter *.wtv
$log_files1 = Get-ChildItem -Path $tv_folder1 -Filter *.log
$log_files2 = Get-ChildItem -Path $tv_folder2 -Filter *.log
$vih_files = Get-ChildItem -Path $xml_folder -Filter *.vih
$xml_files = Get-ChildItem -Path $xml_folder -Filter *.xml

#************************cleanup orphaned log files, TV folder #1************************
write-output ("Processing log files")
foreach ($i in $log_files1)
    {
    $log_filename = $i.FullName 
    $log_filename_wtv = split-path $log_filename -leaf
    $log_filename_wtv = $log_filename_wtv.replace(".log", ".wtv")
    
    $files = $list | Where {$_.Name -match $log_filename_wtv} 
    if(!$files) 
    {
    [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($log_filename,'OnlyErrorDialogs','SendToRecycleBin')
    write-output ("$log_filename has been deleted to the recylce bin") | out-file $file -append
    }
    }

#************************cleanup orphaned log files, TV folder #2************************
foreach ($i in $log_files2)
    {
    $log_filename = $i.FullName 
    $log_filename_wtv = split-path $log_filename -leaf
    $log_filename_wtv = $log_filename_wtv.replace(".log", ".wtv")
     
    $files = $list | Where {$_.Name -match $log_filename_wtv} 
    if(!$files) 
    {
    [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($log_filename,'OnlyErrorDialogs','SendToRecycleBin')
    write-output ("$log_filename has been deleted to the recylce bin") | out-file $file -append
    }
    }

#************************cleanup orphaned vih (showanalyzer) files************************
write-output ("Processing vih files")
foreach ($i in $vih_files)
    {
    $log_filename = $i.FullName 
    $log_filename_wtv = split-path $log_filename -leaf
    $log_filename_wtv = $log_filename_wtv.replace(".vih", ".wtv")
    
    $files = $list | Where {$_.Name -match $log_filename_wtv} 
    if(!$files)
    {
    [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($log_filename,'OnlyErrorDialogs','SendToRecycleBin')
    write-output ("$log_filename has been deleted to the recylce bin") | out-file $file -append
    }
    }

#************************cleanup orphaned xml (showanalyzer) files************************
write-output ("Processing xml files")
foreach ($i in $xml_files)
    {
    $log_filename = $i.FullName 
    $log_filename_wtv = split-path $log_filename -leaf
    $log_filename_wtv = $log_filename_wtv.replace(".xml", ".wtv")
    
    $files = $list | Where {$_.Name -match $log_filename_wtv} 
    if(!$files)
    {
    [Microsoft.VisualBasic.FileIO.Filesystem]::DeleteFile($log_filename,'OnlyErrorDialogs','SendToRecycleBin')
    write-output ("$log_filename has been deleted to the recylce bin") | out-file $file -append
    }
    }

# ************************Test for WTV files that need to be processed by showanalyzer******************************    
write-output ("Processing missing xml files")
foreach ($i in $list)
    {
    $log_filename = $i.FullName 
        $name=$i.fullname
    $log_filename_wtv = split-path $log_filename -leaf
    $log_filename_xml = $log_filename_wtv.replace(".wtv", ".xml")
    
    $files = $xml_files | Where {$_.Name -match $log_filename_xml} 
    if(!$files)
    {
    write-output ("Running commerical detect on $name")
    write-output ("Running commerical detect on $name") | out-file $file -append
    $switches1 = '/if='+$name
    $switches2 = '/of='+$name
    $switches3 = '/act=nativecommdetect'
    &$cmd "$switches1" "$switches2" "$switches3"  
    }
    }
    
# ************************Test drives for free space, move files to server if needed******************************     
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 = "EMAILADDY@gmail.com"
    $EmailTo = "EMAILADDY@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("EMAIL_LOGIN", "EMAIL_PASSOWRD"); 
    $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" 
    $move_log = dir $tv_folder1 $move_log  # Get the name of the 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
    {
    write-output ("Could not copy file - aborted") | out-file $file -append
      exit
    }
    remove-item $move_file  #Not necessary for to remove the log too, it gets cleaned up separately 
    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)})
    }
    
$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)})
write-output ("Free space is now $drive_free and the server has $server_free of space") | out-file $file -append

Edited by pohh-bah - 7/7/12 at 10:10pm
post #3 of 5
Kudos to you for creating a script for your needs. I assume that you have some programming experience, just not with Powershell, right?

Personally, I don't have a need for this script because I don't accumulate that many recordings because from my experience, I'll just never watch them.
post #4 of 5
Does this work with copy protected content?

Having a subroutine to do that and not move the file if it is copy protected would be nice.
post #5 of 5
Thread Starter 
I have minimal programming experience with VB for Excel. That's about it.

Copy protected content - I have no idea.
New Posts  All Forums:Forum Nav:
  Return Home
  Back to Forum: Home Theater Computers
AVS › AVS Forum › Video Components › Home Theater Computers › Powershell script to move files when space is low