Aug 24, 2012

Copy and Separate Files by Size

Playing around with Powershell again, and wrote a nifty little script to copy and separate files in a folder, limiting each new folder based on a user set size.
It requests input and output folders, size of output folders, and size type (ie. KB, MB, GB). Then copies from the input folder into the output folder, creating output folder if needed, and separating by numeric sub-folders. Before copying the objects are sorted by length(size) as it creates less total output folders, or should depending on your input. This sorting is entirely optional and could be removed if you wish.
We ran into a simple enough, issue initially when calculating total data to copy. We were checking if the division of moved size to total wanted  equaled the initial number given for total size. This caused the  total amount copied to be, wanted copied size times initial size number, resulting in quite an issue. Some debugging and head smacking fixed the issue by comparing to a total of 1. Enjoy the script and feel free to modify as needed!

Usage: CopyAndSeparate .\InputFolder .\OutputFolder 5 GB - Copies from .\InputFolder, moves to .\OutputFolder created sub-folders  to place files in every 5gb or so.

CopyAndSeparate.ps1

# Spenser Reinhardt
# 7-27-2012
# Modified 8-7-2012
# CopyandSeparate.ps1
# Finds files in a directory and separates them into new folders, creating a new folder each time a given folder size limit is reached
# Released under GPLv3 Licensing

Param (
    [parameter(Mandatory=$true)][string]$InputFolder,
    [parameter(Mandatory=$true)][string]$OutputFolder,
    [parameter(Mandatory=$true)][int]$FolderSize,
    [parameter(Mandatory=$true)][string]$SizeType
    )

#### Variables #####
$LoopCount = 0 #initializes loopcount for use later
[double]$LoopSize = 0 #initializes loopsize for use with loop lower on created as double to hold gb sized values
$LoopOutput = "" #initializes loopoutput for use with loop later on
$SizeDiv = "$FolderSize$SizeType"

#### Functions #####
Function NewFLCopy {

    Param ($FullName, [string]$Output)
   
    Write-host "Output: $Output`nFullName: $FullName"
    Try {
        New-Item -Path $Output -ItemType Directory # Creates new folder
    }
    Catch {
        Write-Error -message "Could not create $Output for destination files.`nStoping here." -RecommendedAction "stop"
    }
       
    Try {
        Copy-Item "$FullName" -Destination $Output
        }
    Catch {
        Write-Error -message "Could not copy file $FullName.`nStoping here." -RecommendedAction "stop"
    }
   
} # ends function

Function JustCopy {

    Param ($FullName, [string]$Output)
   
    Write-host "Output: $Output`nFullName: $FullName"
   
    Try {
        Copy-Item "$FullName" -Destination $Output
    }
    Catch {
        Write-Error -message "Could not copy file $FullName.`nStoping here." -RecommendedAction "stop"
    }

}

#### Logic ####

# tests if $input folder both exists and is only a folder not file
If ($(Test-Path $InputFolder -pathtype container) -eq $false) {
  
    Write-Error -message "Input folder is not a valid folder, please specify an existing folder and not individual files." -RecommendedAction "Stop"
    exit 1
}

# tests if $output folder exists
If ($(Test-Path $OutputFolder -pathtype container) -eq $false) {
  
    Write-Host Creating output folder: $Outputfolder
    Try {
        New-Item -Path $OutputFolder -ItemType Directory
    }
    Catch {
        Write-Error -message "Could not create $OutputFolder for destination files" -RecommendedAction "stop"
    }
      
}
Else {Write-Host Appears that the output folder already exists at: $OutputFolder`n Using this directory}

#tests sizetype for being valid
If (($SizeType -ne "B") -and ($SizeType -ne "KB") -and ($SizeType -ne "MB") -and ($SizeType -ne "GB") -and ($SizeType -ne "TB")) {

    Write-Error -message "Size type is incorrect, needs to be KB, MB, or GB.`nPlease try again"  -RecommendedAction "Stop"
    exit 2
    }

# If bytes, we don't need to add a modifier to sizediv to get the correct size, otherwise above it has already been concatenated correctly for other modifiers
If (($SizeType -eq "b") -or ($SizeType -eq "B")) {
    $SizeDiv = $FolderSize
    }

   
Get-ChildItem $InputFolder | sort Length | ForEach-Object {

    #checks if loopsize equals zero, indicating a new folder should be created for output and change of location to move files
    If ($LoopSize -eq 0) {
  
        $LoopSize = $_.Length # sets loopsize equal to first file of this folder
        $LoopOutput = "$OutputFolder\$LoopCount\" # sets name for new output folder
      
        Write-host "LoopOutput: $LoopOutput`nFullName: $_.FullName"
        NewFLCopy $_.FullName $LoopOutput
      
    } # ends if
  
    #checks if adding file will be less than or equal to alloted size and if so proceeds
    ElseIf ((($LoopSize + $_.Length)/$SizeDiv) -le 1) {
      
        $LoopSize = $_.Length + $LoopSize
      
        Write-host "LoopOutput: $LoopOutput`nFullName: "$_.FullName
        JustCopy $_.FullName $LoopOutput
     
    } # ends elseif
  
    #checking for adding current file would be greater than alloted space, if so resets for next itteration while copying current file into that new dir
    ElseIf ((($LoopSize + $_.Length)/$SizeDiv) -gt 1) {
   
        $LoopSize = $_.Length #resets loopsize
        $LoopCount++ # incriments loopcount
        $LoopOutput = "$OutputFolder\$LoopCount\" # sets name for new output folder
             
        Write-host "LoopOutput: $LoopOutput`nFullName: "$_.FullName
        NewFLCopy $_.FullName $LoopOutput
      
    } # ends elseif

} # ends foreach loop


CopyAndSeparate.psm1

# Spenser Reinhardt
# 7-27-2012
# Modified 8-7-2012
# CopyandSeparate.ps1
# Finds files in a directory and separates them into new folders, creating a new folder each time a given folder size limit is reached
# Released under GPLv3 Licensing

Param (
    [parameter(Mandatory=$true)][string]$InputFolder,
    [parameter(Mandatory=$true)][string]$OutputFolder,
    [parameter(Mandatory=$true)][int]$FolderSize,
    [parameter(Mandatory=$true)][string]$SizeType
    )

#### Variables #####
$LoopCount = 0 #initializes loopcount for use later
[double]$LoopSize = 0 #initializes loopsize for use with loop lower on created as double to hold gb sized values
$LoopOutput = "" #initializes loopoutput for use with loop later on
$SizeDiv = "$FolderSize$SizeType"

#### Functions #####
Function NewFLCopy {

    Param ($FullName, [string]$Output)
   
    Write-host "Output: $Output`nFullName: $FullName"
    Try {
        New-Item -Path $Output -ItemType Directory # Creates new folder
    }
    Catch {
        Write-Error -message "Could not create $Output for destination files.`nStoping here." -RecommendedAction "stop"
    }
       
    Try {
        Copy-Item "$FullName" -Destination $Output
        }
    Catch {
        Write-Error -message "Could not copy file $FullName.`nStoping here." -RecommendedAction "stop"
    }
   
} # ends function

Function JustCopy {

    Param ($FullName, [string]$Output)
   
    Write-host "Output: $Output`nFullName: $FullName"
   
    Try {
        Copy-Item "$FullName" -Destination $Output
    }
    Catch {
        Write-Error -message "Could not copy file $FullName.`nStoping here." -RecommendedAction "stop"
    }

}

Function CopyAndSeparate {
    # tests if $input folder both exists and is only a folder not file
    If ($(Test-Path $InputFolder -pathtype container) -eq $false) {
      
        Write-Error -message "Input folder is not a valid folder, please specify an existing folder and not individual files." -RecommendedAction "Stop"
        exit 1
    }

    # tests if $output folder exists
    If ($(Test-Path $OutputFolder -pathtype container) -eq $false) {
      
        Write-Host Creating output folder: $Outputfolder
        Try {
            New-Item -Path $OutputFolder -ItemType Directory
        }
        Catch {
            Write-Error -message "Could not create $OutputFolder for destination files" -RecommendedAction "stop"
        }
          
    }
    Else {Write-Host Appears that the output folder already exists at: $OutputFolder`n Using this directory}

    #tests sizetype for being valid
    If (($SizeType -ne "B") -and ($SizeType -ne "KB") -and ($SizeType -ne "MB") -and ($SizeType -ne "GB") -and ($SizeType -ne "TB")) {

        Write-Error -message "Size type is incorrect, needs to be KB, MB, or GB.`nPlease try again"  -RecommendedAction "Stop"
        exit 2
        }

    # If bytes, we don't need to add a modifier to sizediv to get the correct size, otherwise above it has already been concatenated correctly for other modifiers
    If (($SizeType -eq "b") -or ($SizeType -eq "B")) {
        $SizeDiv = $FolderSize
        }

       
    Get-ChildItem $InputFolder | sort Length | ForEach-Object {

        #checks if loopsize equals zero, indicating a new folder should be created for output and change of location to move files
        If ($LoopSize -eq 0) {
      
            $LoopSize = $_.Length # sets loopsize equal to first file of this folder
            $LoopOutput = "$OutputFolder\$LoopCount\" # sets name for new output folder
           
            Write-host "LoopOutput: $LoopOutput`nFullName: $_.FullName"
            NewFLCopy $_.FullName $LoopOutput
           
        } # ends if
      
        #checks if adding file will be less than or equal to alloted size and if so proceeds
        ElseIf ((($LoopSize + $_.Length)/$SizeDiv) -le 1) {
          
            $LoopSize = $_.Length + $LoopSize
          
            Write-host "LoopOutput: $LoopOutput`nFullName: "$_.FullName
            JustCopy $_.FullName $LoopOutput
          
        } # ends elseif
      
        #checking for adding current file would be greater than alloted space, if so resets for next itteration while copying current file into that new dir
        ElseIf ((($LoopSize + $_.Length)/$SizeDiv) -gt 1) {
       
            $LoopSize = $_.Length #resets loopsize
            $LoopCount++ # incriments loopcount
            $LoopOutput = "$OutputFolder\$LoopCount\" # sets name for new output folder
                  
            Write-host "LoopOutput: $LoopOutput`nFullName: "$_.FullName
            NewFLCopy $_.FullName $LoopOutput
           
        } # ends elseif

    } # ends foreach loop

} # ends function
 

No comments:

Post a Comment