Copy plots to various destination disks based on input files

Hopefully this is helpful… Its mostly helpful when copying to a destination over a network. Here’s a script that I use to move plots after creation to various destination disks based on how many plots the disk already has and can support. It’s rough around the edges as I’m not really a PowerShell scripty person but it works well nonetheless. It uses RoboCopy and will just keep running every minute. I should have done the check for local plots at the beginning of the script - nvm. Not that important.

The following inputfiles must exist in the path specified in the script or just change the script to your desired location.

Inputfile: TargetDisks.txt (See in the script) Contains a list of disks used for final storage of plots (where your Farmer is pointing at) and must contain like:

\\server\plot1
\\server\plot2
Z:\plots
etc

Inputfile: (See in the script) _PlotCapacity.txt
This file just needs a number on the first line. I have 89 in mine as I have 10TB disks and having max 89 plots will leave a little space in case its needed.

Variables in script:
$PlotFolder - Change this to the source location (where you directly plot your files to locally)
$MinPlots - Change this to the minimum no of plots there must be locally before the script will copy them to destination disks.

#Porkopops - June 2021
while ($true) 
{
    $ServerList = get-content C:\_data\_Scripts\Move_Plots\TargetDisks.txt
    $PlotDestination=""
    
    #--------------------------------Starting PLOT copier-------------------------------
    write-host "------------------------------" -BackgroundColor Gray -ForegroundColor Black; 
    write-host "Starting PLOT copier----------" -BackgroundColor Gray -ForegroundColor Black; 
    write-host "------------------------------" -BackgroundColor Gray -ForegroundColor Black; 
    #-----------------------------------------------------------------------------------
    

    #--------------------------------REPORT ON ALL DISKS-------------------------------
    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    write-host "CHECKING-DISK-CAPACITY--------" -BackgroundColor Cyan -ForegroundColor Black; 
    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    
   $GetServer = ForEach ($Server in $ServerList)
       {
        $maxplots = Get-Content ($Server + '\_PlotCapacity.txt')
        $CurrentPlots =  (dir -Recurse $Server *.plot | measure).Count
        If ($CurrentPlots -ge $maxplots) 
            {
             write-host "NO MORE CAPACITY ON DISK $Server" -BackgroundColor Yellow -ForegroundColor Black ;
            }
        If ($CurrentPlots -lt $maxplots) 
            {
             write-host "AVAILABLE SPACE ON DISK $Server" -BackgroundColor Green -ForegroundColor Black;
            }
        }
    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    write-host "CAPACITY-CHECK-COMPLETE-------" -BackgroundColor Cyan -ForegroundColor Black; 
    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    #--------------------------------REPORT ON ALL DISKS-------------------------------

    #-----------------------------------FUNCTIONS-----------------------------------
    function finddisk
    {ForEach ($Server in $ServerList)
        {
        $maxplots = Get-Content ($Server + '\_PlotCapacity.txt')
        $CurrentPlots =  (dir -Recurse $Server *.plot | measure).Count

        If ($CurrentPlots -lt $maxplots) 
            {
            return $Server
            }
        }
    }
    #------------------------------------FUNCTIONS-----------------------------------

    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    write-host "CHECKING FOR LOCAL PLOTS------" -BackgroundColor Cyan -ForegroundColor Black
    write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
    
    $PlotFolder = "D:\Plots\Chia"

    If (!(dir -Recurse $PlotFolder *.plot))
        {write-host "No Plots in $PlotFolder" -BackgroundColor Yellow -ForegroundColor Black}

        $dest = finddisk
        $MinPlots = 1
    
        if (!$dest)
            {write-host "NO MORE SPACE TO COPY PLOTS! Exiting.." -BackgroundColor RED -ForegroundColor Yellow; exit}

        $PlotQty =  (dir -Recurse $PlotFolder *.plot | measure).Count
        If ($PlotQty -ge $MinPlots) # If x or more plots, then copy them
            {
            write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
            write-host "--COPYING-PLOTS---------------" -BackgroundColor Cyan -ForegroundColor Black; 
            write-host "------------------------------" -BackgroundColor Cyan -ForegroundColor Black; 
            write-host "Copying Plots to:" $dest "-" "Current Plots:" $CurrentPlots "Max Plots:" $MaxPlots -BackgroundColor Green -ForegroundColor Black
            robocopy $PlotFolder $dest *.plot /mov /compress; 
            }

        write-host "------------------------------" -BackgroundColor Gray -ForegroundColor Black; 
        write-host "-Script will re-run in 1 min-" -BackgroundColor Gray -ForegroundColor Black;
        write-host "------------------------------" -BackgroundColor Gray -ForegroundColor Black; 
        $date = Get-date -format yyyy-MM-dd-HH-mm
        write-host $date
        sleep 60
}

Edit: To be clear, this script is designed to migrate from OG solo farming to pool farming.

Here’s an update: (Don’t forget the input files TargetDisks.txt and _PlotCapacity.txt described in the above post)

I’m no coder and there’s no warranty so use at your own risk. It works for me :slight_smile:
Edit: I’ve added the check for local plots that need moving at the beginning now, so it monitors a local folder waiting for plots to be created. It expects your OG plots to be in a ‘Chia’ folder, but you can change this in the script if you need to

    # Plot Mover script
    # v1.0 updated to remove OG plots and copy Pool plots
    # Run on a Harvester during harvesting, to move completed plots to a final destination disk and delete an OG plot 
    # 
    # Requirements:
    #  - A local plot folder to monitor
    #  - A populated _TargetDisks.txt
    #  - The target disks have correct folder structure, e.g. \\sm1\Disk1\Chia (OG plots) - These will gradually be deleted, 1 by 1 as new pool compatible plots are copied over to the PoolPlots folder
    #  - The target disks have correct folder structure, e.g. \\sm1\Disk1\PoolPlots (Pool-compatible Plots)
    #  - _Plotcapacity.txt exists and populated e.g. \\sm1\Disk1\_Plotcapacity.txt (e.g. entry 89 in file  = 89 plot capacity for that disk)



    $ServerList = get-content .\TargetDisks.txt
    #Note: Ensure that TargetDisks.txt includes entries for just the root folder (not including the folder where the plots are/should be located) e.g. \\sm1\Disk1

    # Source location of completed plots
    #$PlotFolder = "F:\Plots\PoolPlots"   # Harvey the Harvester
    $PlotFolder = "D:\Plots\PoolPlots"   # Hector the Harvester

    #-----------------------------------FUNCTIONS-----------------------------------
    function finddisk
    {ForEach ($Server in $ServerList)
        {
        $maxplots = Get-Content ($Server + '\_PlotCapacity.txt')
        $CurrentPlots =  (dir -Recurse $Server"\PoolPlots" *.plot | measure).Count

        If ($CurrentPlots -lt $maxplots) 
            {
            return $Server
            }
        }
    }
    #------------------------------------FUNCTIONS END-----------------------------------

#--------------------------------Starting PLOT copier-------------------------------
write-host (Get-date) "Starting PLOT copier" -BackgroundColor Gray -ForegroundColor Black; 

while ($true) 
{


    write-host (Get-date)  "Monitoring Folder:" $PlotFolder -BackgroundColor Gray -ForegroundColor Black; 
    while (!(dir $PlotFolder *.plot))
            {
            write-host (Get-date) "No Plots found in " $PlotFolder -BackgroundColor Yellow -ForegroundColor Black
            sleep 60 
            }  
    
    write-host (Get-date) "Found plot(s) in " $PlotFolder -BackgroundColor Gray -ForegroundColor Black; 

    #--------------------------------CHECK TARGET DISKS-------------------------------
    write-host (Get-date) "Checking Target Disk Capacity" -BackgroundColor Gray -ForegroundColor Black;  # Reads the _PlotCapacity file so we can do a count of plot files (This relates to the PoolPlots folder)
        
   $GetServer = ForEach ($Server in $ServerList)
       {
        $maxplots = Get-Content $Server"\_PlotCapacity.txt"
        $CurrentPlots =  (dir -Recurse $Server"\PoolPlots" *.plot | measure).Count
        If ($CurrentPlots -ge $maxplots) 
            {
             write-host (Get-date) "NO CAPACITY ON DISK $Server" -BackgroundColor Yellow -ForegroundColor Black ;
            }
        If ($CurrentPlots -lt $maxplots) 
            {
             write-host (Get-date) "AVAILABLE SPACE ON DISK $Server" -BackgroundColor Green -ForegroundColor Black;
            }
        }
    #--------------------------------CHECK TARGET DISKS-------------------------------

    If (!(dir -Recurse $PlotFolder *.plot))
        {write-host (Get-date) "NO PLOTS FOUND IN $PlotFolder" -BackgroundColor Yellow -ForegroundColor Black }

        $dest = finddisk
        $MinPlots = 1 # If this value is greater than 1 Robocopy will still only copy 1 file at a time. 1 plot will be copied on each run of the script regardless of this value. In here as I used to copy more than 1 at a time, but that became problematic when I updated this script to move Pool Plots and delete OG Plots

        if (!$dest)
            {write-host (Get-date) "NO MORE SPACE TO COPY PLOTS!" -BackgroundColor RED -ForegroundColor Yellow; 
            Write-Host "Press any key to exit....."
            $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown"); exit}

        $PlotQty =  (dir -Recurse $PlotFolder *.plot | measure).Count
        If ($PlotQty -ge $MinPlots) 
            {
            write-host (Get-date) "Making space on target - Removing 1 OG plot from:" $dest"\Chia" -BackgroundColor Green -ForegroundColor Black
            $OGPlotToDelete = Get-ChildItem $dest"\Chia" *.plot | Sort CreationTime | Select -First 1 
            Get-ChildItem $dest"\Chia" *.plot | Sort CreationTime | Select -First 1 | Remove-Item
            write-host (Get-Date) "Deleted OG Plot: $OGPlotToDelete" -BackgroundColor Yellow -ForegroundColor Black
            $OldestPlotFile = Get-ChildItem $Plotfolder *.plot | Sort CreationTime | Select -First 1
            write-host (Get-date) "Copying 1 new Plot to:" $dest "-" "Current Plots:" $CurrentPlots "Max Plots:" $MaxPlots -BackgroundColor Green -ForegroundColor Black
            robocopy $PlotFolder $dest"\PoolPlots" $OldestPlotFile /mov /compress /mt:4 /NJS /NJH; 
            }

        write-host (Get-date) "Script will re-run in 1 min" -BackgroundColor Gray -ForegroundColor Black;
        sleep 60
}
2 Likes

I’m using this since I haven’t found a better way of moving plots with some form of capacity check. Unfortunately, It isn’t actually counting the number of old plots so you aren’t filling the drives first before removing old plots. it deletes old plots when moving a new plot to that drive regardless of capacity. I set my drive list to where my full drives are last so it should work ok until I find a better solution.

Thanks for posting. There is a shocking lack of solutions posted for moving plots.

Yes it assumes that you’re at full capacity of OG plots, hence needing to delete one every time a Pool plot is copied. I should have been clearer.
Glad it’s of, at least, some use for you. But you could use the script in the first post to copy pool plots to destination until your disks are.full, then revert to the v1.0 script to start clearing space as required. You’d need to update the destination folder name in the script and move the _plotcopy.txt into that folder too.

I think this is what i’m looking for, thanks @GIGATOR for pointing me here!

Not quite sure what i need to do for the input files, could you confirm for a smooth brain like myself?

Do i need an individual .txt. file populated only with the number of plots sat in each final dest drive? So for a 14tb drive, i’ll have a file called “_Plotcapacity.txt”, sat on that specific drive, and the only entry in the text file will be the plot count, eg “128”.

Target disks text. So this will be a list all tgt disks, eg:

E:
F:
G:\

etc etc. And i’ll need to ensure folder structure on each disk contains 2xdir, “Chia” & “PoolPlots”.

Where do i save the “TargetDisks.txt”…? I gather i can just drop ths on my main win drive and specify the path, eg, C:\TargetDisks.txt?

@DougieC
For the v1.0 script, which removes OG plots as new Pool plots are moved:
The _PlotCapacity.txt needs to be located in the root of wherever the plot folders are located (e.g. “\\sm1\disk1” (these folders should also exist: \\sm1\disk1\chia & \\sm1\disk\PoolPlots, but you can rename them in the script should you have different folder names.

The _targetdisks.txt should be located in the same folder as the script. Please remove any leading 's, like:

E:
F:
G:

The _targetdisks.txt needs just a single line with a number on it, which indicates the maximum number of plots that you want on that disk. This is useful if the disk contains other data or you want to limit the number of plots to reserve space for other later uses.

Seeing as it looks like this is actually being used (I did wonder if it would be helpful or not LOL), I’ll do an update to the script to variablise the folder names (Chia and PoolPlots) and to offer an option on whether to remove OG plots or not.

Cool. In win “_TargetDisks.txt” doesn’t require the underscore, i gather the same for the “_Plotcapacity.txt”? eg, “Plotcapacity.txt” instead?

Thanks for pointing that out. Apologies. There was a typo in my last post. The input file names are:
TargetDisks.txt
_PlotCapacity.txt

I’ll remove the ‘_’ in the new version.

1 Like

Working well although i’ve ironically found out that using a 240gb SSD as a staging drive is slower than copying direct to final usb for some reason!

Query on the plotcap text, so i’ve moved my 1st file which was to E:, plotcap txt for that drive is 128. When it deleted the OG plot and copied the new, it stated “E:\ - Current Plots: 0 Max Plots: 73”. 73 happens to be the plot size for my 8TB drives. Any reason why it’s reading E: as 73 and not 128 as saved in the plot cap txt for that drive? Last drv in tgtdrv txt happens to be an 8tb with 73.

@DougieC - Cheers. I’ll have a look at that too.

Superb. If that can be sorted then this script as a massive win for replotting, kudos!

Thinking outside of the box for now, could run the script per drive size…should work…(?)

I have updated the script to v1.1, which replaces the scripts in earlier posts. Please see comments in script for changelog and help. Don’t forget to change the variables as you need.

TargetDisks.txt should be formatted:

\\server\plot1
\\server\plot2

or

D:
E:
F:

PlotCapacity.txt should just have 1 line/row with a number specifying the maximum plots you want on the target: e.g.

89

Note: Should get around ~89/90 plots per 10TB formatted disk. Your results may vary.

    # Plot Mover script
    # v1.1 updates:
    #   - '_PlotCapacity.txt' has been renamed to 'PlotCapacity.txt'
    #   - An option to remove OG plots and then copy Pool plots, or just to copy pool plots leaving OG plots in place
    #   - Usability update: Variabalised the folder names for OG plots and PoolPlots
    #   - Now creates the $PoolPlotFolder if it doesnt already exist
    #   - Fixed a defect that was reporting incorrect existing and maximum plots on a target disk
    #   - Added some logic to provide feedback if/when all OG plots have been deleted. 
    # 
    # Run this script on a Harvester during harvesting to move completed pool plots to a final destination disk and delete OG plots (if you want/need to 
    #  using the variable $DeleteOGPlots).
    # 
    # If you do opt to delete OG plots when replacing them with a Pool plot, it will only delete one OG plot every time the script runs (default 60 seconds, 
    #  but you can change the time period with $SleepPeriod)
    #   
    # Requirements:
    #  - A local plot folder to monitor $PlotFolder
    #  - A populated TargetDisks.txt, which should be located in the same folder as this script, entries like: \\sm1\Disk1 or E: (omit any trailling backslash)
    #     and each entry must be on a new row.
    #  - The target disks themselves have the correct folder structure, e.g. \\sm1\Disk1\PoolPlots & \\sm1\Disk1\Chia (you can change these folder names in  
    #     the script using the variables below ($OGPlotFolder & $PoolPlotFolder). Exception: the script will create the PoolPlots folder if needed
    #  - Plotcapacity.txt must exist and is populated. It must be located in the correct location (e.g. \\sm1\Disk1\Plotcapacity.txt) and has a single number 
    #     entry on the top row (e.g. 89 in file  = 89 plot capacity for that disk). This file is used so you can opt to store a specific qty of plots on a disk 
    #     which may be shared with other data. Calculate: Take current disk space in GB's and divide by 101GB and that'll give you roughly the qty of plot files 
    #     that you can store using the current free space on the disk

    $ServerList = get-content .\TargetDisks.txt
    # Note: Ensure that TargetDisks.txt includes just the root folder and no trailling backslash (Don't include the folder where the plots are/should be located
    #  as that's defined with the $OGPlotFolder & $PoolPlotFolder variables)

    #--Update these to your specific setup---
    $PlotFolder = "D:\Plots\PoolPlots"   # Source location of completed plots
    $OGPlotFolder = "Chia"               # Folder name where OG plots are stored on the target (Can ignore if you're not deleting them)
    $PoolPlotFolder =  "PoolPlots"       # Folder name where Pool plots are stored on target, or where you want them to be
    $DeleteOGPlots = $true               # $true or $false - Use $true if you want to delete 1 OG plot on each loop of the script in order to make space for each Pool plot. 
    $SleepPeriod = 60                    # Pauses inbetween loops of this script (seconds)
    #-----------------------------------FUNCTIONS-----------------------------------
    function finddisk
    {ForEach ($Server in $ServerList)
        {
        $maxplots = Get-Content ("$Server\PlotCapacity.txt")
        $CurrentPlots =  (dir -Recurse "$Server\$PoolPlotFolder" *.plot | measure).Count
        If ($CurrentPlots -lt $maxplots) 
            {
            return $Server
            }
        }
    }
    #------------------------------------FUNCTIONS END-----------------------------------

#--------------------------------Starting PLOT copier-------------------------------
write-host (Get-date) "Starting PLOT copier" -BackgroundColor Gray -ForegroundColor Black; 


while ($true) 
{


    write-host (Get-date)  "Monitoring Folder:" $PlotFolder -BackgroundColor Gray -ForegroundColor Black; 
    while (!(dir $PlotFolder *.plot))
            {
            write-host (Get-date) "No Plots found in $PlotFolder, sleeping for $SleepPeriod seconds" -BackgroundColor Yellow -ForegroundColor Black
            sleep $SleepPeriod
            }  
    
    write-host (Get-date) "Found plot(s) in " $PlotFolder -BackgroundColor Gray -ForegroundColor Black; 

    #--------------------------------CHECK TARGET DISKS-------------------------------
    write-host (Get-date) "Checking Target Disk Capacity" -BackgroundColor Gray -ForegroundColor Black; # Reads the _PlotCapacity file so we can do a count of plot files (This relates to the PoolPlots folder)
        
   $GetServer = ForEach ($Server in $ServerList)
       {
        $maxplots = Get-Content $Server"\PlotCapacity.txt"
        $CurrentPlots =  (dir -Recurse $Server"\$PoolPlotFolder" *.plot | measure).Count
        If ($CurrentPlots -ge $maxplots) 
            {
             write-host (Get-date) "NO CAPACITY ON DISK $Server" -BackgroundColor Yellow -ForegroundColor Black ;
            }
        
        If ($CurrentPlots -lt $maxplots) 
            {
             write-host (Get-date) "AVAILABLE SPACE ON DISK $Server - (Max Plots:$maxplots Current PoolPlots:$CurrentPlots)" -BackgroundColor Green -ForegroundColor Black;
            } #Note: The above on-screen feedback relates to the max plots found on a target disk and the Current plots in the $PlotFolder (i.e. NOT the OG folder. As I expect that 
              # the usual motive behind using this script is to move from OG plots to Pool plots).
        }
    #--------------------------------CHECK TARGET DISKS-------------------------------

    If (!(dir -Recurse $PlotFolder *.plot))
        {write-host (Get-date) "NO PLOTS FOUND IN $PlotFolder" -BackgroundColor Yellow -ForegroundColor Black }

        $dest = finddisk

        if (!$dest)
            {write-host (Get-date) "NO MORE SPACE TO COPY PLOTS!" -BackgroundColor RED -ForegroundColor Yellow; 
            Write-Host "Press any key to exit....."
            $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown"); exit}

        $PlotQty =  (dir -Recurse $PlotFolder *.plot | measure).Count

        If ($DeleteOGPlots) # If $DeleteOGPlots is $True this will delete OG plots to make way for Pool Plots 
                {
                write-host (Get-date) "Making space on target - Removing 1 OG plot from:" $dest"\$OGPlotFolder" -BackgroundColor Green -ForegroundColor Black
                $OGPlotToDelete = Get-ChildItem $dest"\$OGPlotFolder" *.plot | Sort CreationTime | Select -First 1 
                
                If (!($OGPlotToDelete)) 
                    {
                    write-host (Get-Date) "No OG Plots exist. Skipping deletion." -BackgroundColor Yellow -ForegroundColor Black
                    }
                If ($OGPlotToDelete)
                    { Get-ChildItem $dest"\$OGPlotFolder" *.plot | Sort CreationTime | Select -First 1 | Remove-Item
                    write-host (Get-Date) "Deleted OG Plot: $OGPlotToDelete" -BackgroundColor Yellow -ForegroundColor Black
                    }
                }

        $OldestPlotFile = Get-ChildItem $Plotfolder *.plot | Sort CreationTime | Select -First 1 # Get oldest local plot file that's been created ready for moving
        write-host (Get-date) "Moving 1 new Plot to:"$dest"\$PoolPlotFolder" -BackgroundColor Green -ForegroundColor Black
        
        if (!($dest+"\"+ $PoolPlotFolder))
            {New-Item -Path $dest"\$PoolPlotFolder" -ItemType directory} # Create Poolplot folder if it doesnt exist
        
        robocopy $PlotFolder $dest"\$PoolPlotFolder" $OldestPlotFile /mov /compress /mt:4 /NJS /NJH; # Move oldest pool plot file
        
        write-host (Get-date) "Script will re-run in $SleepPeriod seconds" -BackgroundColor Gray -ForegroundColor Black;
        sleep $SleepPeriod
}
2 Likes

Something weird going on here, eventually picked it up and started move. Not sure why it’s searching C: as that’s not a tgt disk in tgtdsktxt.

That looks weird… I’m just in the middle of something. I’ll take a look in a few hours for you.

Are you running that from the ISE? If so, run the script from Explorer instead

Saved as a .ps1 on desktop. Just tried moving the folder to another drive (existing plot drive) and it seems to be happy now. Not sure why it was trying to search C:…

It looks like the script was executed when the current directory was c:. Maybe you are running it from a shortcut? If so, make sure that the working directory of the shortcut is the same as the location of the script .ps1 file.

To create a shortcut, I tend to use Windows Explorer to browse to the .ps1 file, then right click the .ps1 file and drag it into the same folder it’s already located in. It’ll give you an option to create a shortcut. Select that option and then change the ‘properties’ of the shortcut itself. Update the ‘target’ line so to prefix it with "powershell.exe -file " then preserve the full of the path to your .ps1 file. Now you have a shortcut that will work from wherever you copy/place it. Personally, I put the shortcut into the following folder so that it starts up upon login:
C:\Users%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

I also put the madmax.cmd file into the above folder to that starts on login too.
I then use AutoLogon ( Autologon - Windows Sysinternals | Microsoft Docs) so that the correct user logs in on power on or reboot of the PC.

Just figured it out, had a space in notepad after my last drive. User error! :sweat_smile:

Nice tip for startup! Cheers!

1 Like

Glad to hear this helped. You wouldn’t want to write to an extra staging drive as that is more copy time. Using a staging folder on the plotting drive removes copy time from the plotter since it’s just moving a file on the same drive(changing the location it’s indexed to).

Nice addition of folder name variables and folder checks. I think the way to do the OGplot check would be to count the plots in both the OG and poolplots folders then only delete OG plots if the capacity is full to make room for the new pool plot. Thanks for posting your solution it’s nice to have an option that works with a list of locations.

1 Like