简体   繁体   中英

Powershell copy a file from source to target but maintain folder structure

How can I come up with a powershell script that can copy a file from a location A to location B and create new folder and maintain the sub directory structure

Pseudo code

$newFolder = "PackageName"
$maintainFolderStructureFrom ="Website"
$FileToCopy = "File.ascx"

Copy-Item "C:\A\B\Website\SubFolder1\SubFolder2\SubFolder3\"+$FileToCopy "C:\Client\Packages\$newFolder" -Container -Recurse

Now it should create the target as such

C:\Client\Packages\PackageName\SubFolder1\SubFolder2\SubFolder3\File.ascx

Code based on @jisaak answer

$newFolder = "NewFolderName"
$FileToCopy="File.ascx"                                                                                                
$pathToCopy = Join-Path 'C:\A\B\Website\SubFolder1\SubFolder2\SubFolder3\' $FileToCopy     
$destination = Join-Path 'C:\Client\Packages\' $newFolder                                                        
mkdir $destination -ErrorAction SilentlyContinue                                                                                      
Copy-Item $pathToCopy $destination  

This code is not creating folder structure, I want the folder structure to be created user this param $maintainFolderStructureFrom ="Website"

First, you should use the Join-Path cmdlet to combine paths. You could create the directories using mkdir (use -ErrorAction SilentlyContinue to ignore errors if the directory already exists):

$pathToCopy = Join-Path 'C:\A\B\Website\SubFolder1\SubFolder2\SubFolder3' $FileToCopy
$destination = Join-Path 'C:\Client\Packages' $newFolder

# create the directory if necessary
mkdir $destination -ErrorAction SilentlyContinue 

Copy-Item $pathToCopy $destination

A few ideas here:

  • The New-Item cmdlet can create files and folders, including the necessary parent folder if they don't exist. Use the -Force switch. What's more, it will return a [System.IO.DirectoryInfo] type object for you to work with.
  • If you make the $pathToCopy variable a [System.IO.FileInfo] object you get a few useful properties and methods in common with other files that you may be used to after using the Get-Item cmdlet.
  • The Resolve-Path cmdlet can be useful to give a consistent format for your paths (eg '\\' rather than '/', etc.) but note that it needs to resolve to something that actually exists. Remember to pull out the Path property of what that cmdlet gives you.
  • There is a cool "Escape" method associated with the [Regex] class that can help stripping off parts of a file path.

The following shows off some of these things that you may or may not want to use:

$SourceRoot = "C:\A\B\Website"
$SourcePath = "\SubFolder1\SubFolder2\SubFolder3"
$SourceFile = "File.ascx"
$DestRoot = "C:\Client\Packages"
$NewFolder = "PackageName"

# Build a full path to your source file
$FileToCopy = Join-Path -Path $SourceRoot -ChildPath $SourcePath
$FileToCopy = Join-Path -Path $FileToCopy -ChildPath $SourceFile

# Make this a FileInfo object, just because we can :-)
$FileToCopy = $FileToCopy -as [System.IO.FileInfo]

# Or you could have used Get-ChildItem instead:
$FileToCopy = Resolve-Path ($SourceRoot+$SourcePath+$SourceFile)
$FileToCopy = Get-ChildItem -Path $FileToCopy.Path 

# Strip off the "root" folders so we're just left with the relative
# path to the source file from the source root folder
$RelativePath = $FileToCopy.Directory -replace [Regex]::Escape($SourceRoot),''

# Join up the destination path components
$DestFolder = Join-Path $DestRoot $NewFolder
$DestFolder = Join-Path $DestFolder $RelativePath

# Create the target folder if necessary & convert the $DestFolder
# variable into a [System.IO.DirectoryInfo] object!

$DestFolder = New-Item -ItemType Directory -Path $DestFolder -Force

# Copy the file
Copy-Item $FileToCopy $DestFolder

This is definitely a longer way to do this than you'll probably want to use, but I wanted the example to include a number of the ideas you could try.

Alternative answers to similar questions:

  • You could try using RoboCopy , as per an answer to a similar question here:

What's the proper way to copy files while preserving folder structure in powershell?

Or look at the answer here:

Copying files while preserving directory structure

I like some of the answers, but feel that they're overly verbose, so I'll offer a shorter take on the same thing.

The flow here is to recursively grab the source directory as $source . Next, iterate through it, pulling out all the directories, and for each of those, make a new folder in the target.

Finally, go back through $source one last time to get the files this time, and put them in the new location.

$source = DIR -Path C:\SomeOldPath -Recurse
$destination = 'C:\SomeNewPath'
$source | Where PSIsContainer | ForEach-Object {
    #If the folder doesn't exist in the target
    if(!(Test-Path $Destination\$_.Name -PathType Container)){
        New-Item -Path $Destination\$_.Name -ItemType directory -Force}
        }
        else {
        Copy-Item $_.FullName -Destination $Destination\$_.Name -Force}

$source | Where PSIsContainer -eq $false | ForEach-Object {
    Copy-Item $_.FullName -Destination $Destination\$_.Name -Force
    }

taking help of few answers from @jisaak & @FoxDeploy, I could accomplish what I need.

function CreatePackage($sourcePath, $fileSelectorToCopy, $packageName) {

$maintainStructionFrom = "Website"

$files = Get-ChildItem $sourcePath | Where-Object {$_.Name -match $fileSelectorToCopy}

$files | ForEach-Object { 
    $newFolder = $packageName
    $fileSelectorToCopy = $_.Name 
    $pathToCopy = Join-Path $sourcePath  $fileSelectorToCopy                                                                                         
    $newFolder = $newFolder+'\'+$pathToCopy.Substring($pathToCopy.IndexOf($maintainStructionFrom),$pathToCopy.Length - $pathToCopy.IndexOf($maintainStructionFrom)).Replace($fileSelectorToCopy,'') 
    $destination = Join-Path 'C:\Client\Packages\' $newFolder  
    mkdir $destination -ErrorAction SilentlyContinue                                                                                      
    Copy-Item $pathToCopy ($destination+$FileToCopy)
}
}

Then call it as

CreatePackage -packageName 'MyNewPackage' -fileSelectorToCopy 'FileNameLike.*' -sourcePath 'C:\A\B\Website\SubFolder1\SubFolder2\SubFolder3\'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM