FileSelection/FileSelection.psm1

#region Variables
$maxsize = -1
$items
$bins
#endregion

#region Helper functions
function GetItems()
{
    Param(
        [String]$Path
        )

    $script:items = @()

    $its = Get-ChildItem -Path $Path
    foreach($it in $its)
    {
        $newItem = New-Object PSObject
        $newItem | Add-Member -MemberType NoteProperty -Name Name -Value $it.Name
        $newItem | Add-Member -MemberType NoteProperty -Name FullName -Value $it.FullName
        $size = (Get-Size $it.FullName ).MB
        $newItem | Add-Member -MemberType NoteProperty -Name Size -Value $size
        $script:items += $newItem
    }
}

# Function to add new bin
function addBin()
{
    $bin = New-Object PSObject
    $bin | Add-Member -MemberType NoteProperty -Name Items -value (New-object System.Collections.Arraylist)
    $bin | Add-Member -MemberType NoteProperty -Name Size -Value 0
    $script:bins += $bin
}

function NextFit()
{
    $script:bins = @()

    $binIndex = 0;

    addBin

    foreach($i in $script:items)
    {
        $freeBinSpace = $script:maxsize - $script:bins[$binIndex].size
        if( $freeBinSpace -ge $i.Size)
        {
            $script:bins[$binIndex].Items.Add($i.FullName) > $null
            $script:bins[$binIndex].size += $i.size
        }
        else
        {
            addBin
            $binIndex ++

            $script:bins[$binIndex].Items.Add($i.FullName) > $null
            $script:bins[$binIndex].size += $i.size
        }
    }

}

function FirstFit()
{
    $script:bins = @()
    
    $binIndex = 0;

    addBin

    $added = 0

    foreach($i in $script:items)
    {
        for( $b=0; $b -lt $script:bins.Count; $b++)
        {
            $freeBinSpace = $script:maxsize - $script:bins[$b].size
            if( $freeBinSpace -ge $i.Size)
            {
                $script:bins[$b].Items.Add($i.FullName) > $null
                $script:bins[$b].size += $i.size
                $added = 1
                break
            }
        }

        if( $added -ne 0)
        {
            addbin
            $script:bins[$script:bins.Count-1].Items.Add($i.FullName) > $null
            $script:bins[$script:bins.Count-1].size += $i.size
        }
    }

}

function BestFit()
{
    $script:bins = @()

    # Add the first bin
    addBin

    # Variables to hold the best fit bin
    $binwithminimumemptyspace = -1
    $minimumemptyspace = $maxsize

    # Loop through files/folders
    foreach($i in $script:items)
    {
        # Loop through bins for specific file/folder
        $binwithminimumemptyspace = -1
        $minimumemptyspace = $maxsize

        for( $b=0; $b -lt $script:bins.Count; $b++)
        {
            # Get bin's free space
            $freeBinSpace = $script:maxsize - $script:bins[$b].size

            # Reject bin if free space is less than needed
            if( ($freeBinSpace -lt $i.size) -or ($freeBinSpace -lt 0) )
            {
                continue
            }

            # Compare to the bin where the item fits best
            if( ($freeBinSpace - $i.size) -lt $minimumemptyspace )
            {
                $binwithminimumemptyspace = $b
                $minimumemptyspace = ($freeBinSpace - $i.size)
            }
        }


        # Check if bin is found or we need to add new bin
        if( $binwithminimumemptyspace -lt 0 )
        {
            addBin
            $binwithminimumemptyspace = ($script:bins.Count - 1)
        }

        # Add item to the bin
        $script:bins[$binwithminimumemptyspace].Items.Add($i.FullName) > $null
        $script:bins[$binwithminimumemptyspace].size += $i.size
    }
}
#endregion

#region FileSelection
Function FileSelection()
{
    Param(
        [Parameter(Mandatory=$true,Position=1)]
        [String]$Path,
        [ValidateSet("BestFit","FirstFit","NextFit","All")] 
        [String]$Method = "BestFit",
        [Parameter(Mandatory=$true,Position=2)]
        [Int]$MaximumSize,
        [switch]$Seperate
    )

    if( -Not(Test-Path $Path))
    {
        Write-Error "Could not locate source directory."
        return
    }

    $script:maxsize = $MaximumSize

    GetItems -Path $Path

    if( $Method -eq "BestFit" )
    {
        BestFit
    }
    if( $Method -eq "NextFit")
    {
        NextFit
    }
    if( $Method -eq "FirstFit")
    {
        FirstFit
    }

    if( $Method -eq "All")
    {
        NextFit
        $nextfitbins = $Script:bins

        BestFit
        $bestfitbins = $Script:bins

        FirstFit
        $firstfitbins = $Script:bins

        $bestsolution = $bestfitbins

        if( $nextfitbins.Count -lt $bestsolution.Count )
        {
            $bestsolution = $nextfitbins
        }

        if( $firstfitbins.Count -lt $bestsolution.Count )
        {
            $bestsolution = $firstfitbins
        }
    }

    if( $Seperate )
    {
        $bincounter = 0
        $fullpath = (Resolve-Path $Path).Path + "\"

        for($j=0; $j -lt $Script:bins.Count; $j++)
        {
            $bincounter ++
            $directoryname = ($fullpath + "Folder " + $bincounter)

            New-Item -ItemType directory -Path $Path -Name ("Folder " + $bincounter)

            foreach($i in $bins[$j].items)
            {
                Move-Item -Path $i -Destination $directoryname -Force
            }
        }
    }
    else
    {
        $bins | Select-Object -Property Items, Size
    }
}
#endregion

#region Exports
Export-ModuleMember -Function FileSelection
#endregion