Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How To: Move Files Preserving Directory Structure and Rename Existing Files? (Script Debug)

Trying to debug a file-transfer operation. Basically, I want PowerShell to merge two folders ($sourceDir and $targetDir), and rename any files in $sourceDir that already exist in $targetDir. It sort of does that, but instead of preserving the directory structure of the source folder, it’s moving all the files from the source directory into the root of the target.

I know that adding the -Container flag on a standard Move-Item will force it to reconstruct the directory structure, but I’ve tried adding that here and I get errors.

This is what I have:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

$sourceDir = "E:\Folder1"
$targetDir = "W:\Folder1"

Get-ChildItem -Path $sourceDir -Recurse | ForEach-Object {
    $num=1
    $nextName = Join-Path -Path $targetDir -ChildPath $_.name

    while(Test-Path -Path $nextName)
    {
       $nextName = Join-Path $targetDir ($_.BaseName + "_$num" + $_.Extension)    
       $num+=1   
    }

    $_ | Move-Item -Destination $nextName -Verbose
}

I’ve inserted write-host lines into it right above the Move-Item command and I can confirm it’s targeting the root directory of the destination instead of maintaining the directory structure from the source. I’ve tried changing Get-ChildItem -Path to -LiteralPath, I’ve tried adding | % { $_.FullName } | after the GCI, but no matter what I do the result I get is something different than what I’m looking for.

>Solution :

All files are being relocated to the root of the target directory because the script only uses the file name to create the destination path. You must include the subdirectory path in the destination path in order to maintain the directory structure of the source folder.

The script has been changed, and it should still maintain the directory structure, as follows:

$sourceDir = "E:\Folder1"
$targetDir = "W:\Folder1"

Get-ChildItem -Path $sourceDir -Recurse | ForEach-Object {
    $relativePath = $_.FullName.Substring($sourceDir.Length)
    $nextName = Join-Path -Path $targetDir -ChildPath $relativePath

    $num = 1
    while(Test-Path -Path $nextName)
    {
       $nextName = Join-Path $targetDir ($relativePath + "_$num" + $_.Extension)    
       $num += 1   
    }

    $_ | Move-Item -Destination $nextName -Verbose
}

By deducting the length of the source directory path from the complete path of the file, the script first determines the relative path of each file. The target path is then built using the relative path.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading