powershellcopy-item

Powershell: Copy files from .txt file and keep subfolder structure the same


Let me first say I am very bad at everything that involves coding language. So I need some help.

The goal:

I have a source with million of files but they need to be copied in a sequential order from A to B.

\\shareA\Files

\\shareA\Files\file1.jpg

\\shareA\Files\file2.jpg

\\shareA\Files\1\file3.jpg

\\shareA\Files\1\file4.jpg

\\shareA\Files\1\412\file5.jpg

\\shareA\Files\1\412\file6.jpg

\\ShareB\Files

\\ShareB\Files\file1.jpg

\\ShareB\Files\file2.jpg

\\ShareB\Files\1\file3.jpg

\\ShareB\Files\1\file4.jpg

\\ShareB\Files\1\412\file5.jpg

\\ShareB\Files\1\412\file6.jpg

The .txt file looks like this:

file1.jpg

file2.jpg

1\file3.jpg

1\file4.jpg

1\412\file5.jpg

1\412\file6.jpg

Relative Paths are included in the .txt file.

This my PowerShell script:

`

# Enter the source folder
$Source = "c:\FileA\Files"

# Enter the archiving destination folder
$destination = "C:\FileB\Files"

# Enter the tape export txt file
$txtPath = "C:\Tools\Files.txt"

# Read the file paths from the text file
$filePaths = Get-Content $txtPath

# Copy the files from the text file to the destination folder
foreach ($file in $filePaths) {
   Copy-Item "$Source\$file" -Destination "$destination" -Recurse -Verbose -PassThru
}

`

    Directory: C:\FileB\Files


> Mode                 LastWriteTime         Length Name                                                                                                                                                                                                          
> 
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\file1.jpg Destination: C:\FileB\Files\file1.jpg".
> -a----        2022-12-09   6:16 PM              0 file1.jpg                                                                                                                                                                                                     
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\file2.jpg Destination: C:\FileB\Files\file2.jpg".
> -a----        2022-12-09   6:16 PM              0 file2.jpg                                                                                                                                                                                                     
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\1\file3.jpg Destination: C:\FileB\Files\file3.jpg".
> -a----        2022-12-09   6:16 PM              0 file3.jpg                                                                                                                                                                                                     
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\1\file4.jpg Destination: C:\FileB\Files\file4.jpg".
> -a----        2022-12-09   6:16 PM              0 file4.jpg                                                                                                                                                                                                     
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\1\412\file5.jpg Destination: C:\FileB\Files\file5.jpg".
> -a----        2022-12-09   6:16 PM              0 file5.jpg                                                                                                                                                                                                     
> VERBOSE: Performing the operation "Copy File" on target "Item: C:\FileA\Files\1\412\file6.jpg Destination: C:\FileB\Files\file6.jpg".
> ```
> 

As you can see, the files are all copied in the root folder "\\C:\FileB\Files" and not in the respective subfolders in the destination.

Thanks in advance for the help.


Solution

  • Make sure to create the parent directory for each destination file, if not already exists. Also specify the full file path for both the -Path and the -Destination argument of Copy-Item. The Copy-Item command knows nothing about the directory structure when copying single files, so you need to be explicit.

    foreach ($file in $filePaths) {
       # using Join-Path is more robust than "$Source\$file" as it appends "\" only if necessary
       $sourceFilePath = Join-Path $Source $file
    
       # create the full destination file path
       $destinationFilePath = Join-Path $Destination $file
       
       # get the parent directory of the destination file path...
       $destinationDirPath = Split-Path $destinationFilePath
       # ...and create it if it doesn't exist (-Force)
       $null = New-Item $destinationDirPath -ItemType Directory -Force
       
       # Copy file with full source and destination path
       Copy-Item $sourceFilePath -Destination $destinationFilePath -Verbose -PassThru
    }