Search code examples
powershellmenucopy-item

Powershell: Dynamic Menu-based program to copy file


The purpose of this was to copy one (or more) files from one user selected dynamic location to another user selected dynamic location.

Write-Host "Choose where to copy FROM"

$1MainFolder = (Get-ChildItem "C:\Users\$env:USERNAME\FROM" -Directory | Sort-Object)
$menu = @{}
for ($i=1;$i -le $1MainFolder.count; $i++) {
    Write-Host "$i. $($1MainFolder[$i-1].name)"
    $menu.Add($i,($1MainFolder[$i-1].name))
    }

[int]$ans = Read-Host 'Enter selection'
$selection = $menu.Item($ans)
# The directory after the selection is only one, however it's different for every user; this remains the same for "COPY TO"
$First = (Get-ChildItem "C:\Users\$env:USERNAME\FROM\$selection" -Directory)

# This directory is the same for every user; this remains the same for "COPY TO"
$DataFROM = (Set-Location $First\USERFILE) 

Clear-Host


Write-Host "Choose where to copy TO"

$2MainFolder = (Get-ChildItem "C:\Users\$env:USERNAME\TO" -Directory | Sort-Object)
$menu2 = @{}
for ($i=1;$i -le $2MainFolder.count; $i++) {
    Write-Host "$i. $($2MainFolder[$i-1].name)"
    $menu2.Add($i,($2MainFolder[$i-1].name))
    }

[int]$ans2 = Read-Host 'Enter selection'
$selection2 = $menu2.Item($ans2)
$Second = (Get-ChildItem "C:\Users\$env:USERNAME\TO\$selection2" -Directory)

$DataTO = (Set-Location $Second\USERFILE)

Clear-Host

That completes section one and two. The third section allows the user to then pick the file they want copied - this is a separate function which works well, however it errors in conjunction with this. I've since simplified the function to obtain the same error with:

# The Select-Object section being the simplified part...
Get-ChildItem $DataFROM | Select-Object "DATA.log*"  | Copy-Item -Destination $DataTO

What I expect to happen is for the data to be copied from the initial dynamic location to the final dynamic destination.

What happens is that I get an error stating that it "Cannot bind argument to parameter 'Path' because it is an empty string." to which it points at the $DataTO variable.

This then lead me to disregard the third section and test the variables to which I found that if I use the following after the first two sections:


Get-ChildItem $DataFROM

# or

Get-ChildItem $DataTO

it returns back information from the last selected menu, disregarding the variables entirely. So then are the dynamic menus not to be used in this manner or perhaps I am using the menus wrong?

Would someone please advise where I've gone astray?


Solution

  • Update: I've since re-worked it to the following that fits my requested needs: (hopefully this will aid someone else needing something similar)

    
    [array]$sMainFolder = Get-ChildItem "C:\Users\$env:USERNAME\DATA-TO_FROM" -Directory | ForEach-Object {
              Get-ChildItem $_.FullName | ForEach-Object {
                  $found = Get-ChildItem $_.FullName | Where-Object { $_.Name -eq 'USERFILE' } | Select-Object -First 1
                  if ($found) {
                      [PSCustomObject]@{
                          RootFolder = [string]$_.FullName
                          Path = $found.FullName
                      }
                  }
              }
          }
    
          [array]$dMainFolder = Get-ChildItem "C:\Users\$env:USERNAME\DATA-TO_FROM" -Directory | ForEach-Object {
            $subs = Get-ChildItem $_.FullName
            $found = $subs | ForEach-Object { Get-ChildItem $_.FullName } | Where-Object { $_.Name -eq 'USERFILE' } | Select-Object -First 1
                if ($found) {
                    [PSCustomObject]@{
                        RootFolder = [string]$_.FullName
                        Path = $found.FullName
                    }
                }
            }
    
    function ShowMenu ($Folders, $Message) {
        Write-Host $Message
        for ($i = 1; $i -le $Folders.count; $i++) {
            $name = $Folders[$i - 1].RootFolder
            Write-Host "$i. $name"
        }
        [int]$ans = Read-Host 'Enter Selection'
        Return $Folders[$ans -1].Path
    }
    
    $DataFROM = ShowMenu $sMainFolder "Choose where to copy FROM"
    $DataTO = ShowMenu $dMainFolder "Choose where to copy TO"
    
    Clear-Host
    
    Copy-Item "$DataFROM\*" $DataTO -Recurse -Force