1

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"

1
  • In PowerShell 5, the Copy-Item cmdlet has a -Recurse switch. Commented Mar 31, 2018 at 18:54

5 Answers 5

1

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
Sign up to request clarification or add additional context in comments.

2 Comments

This code is not creating folder structure, I want the folder structure to be created user this param $maintainFolderStructureFrom ="Website"
This creates the destination folder structure from $destination. What do you mean it not creating folder structure?
1

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 (e.g. '\' 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.

2 Comments

Any time that I need to duplicate a folder structure, I use New-Item to first layout the directory structure, then copy items into their final place. Why? Well, Copy-Item, even when using the -Force switch, doesn't actually replicate folder structure like you'd think it would. It's misleading and can result in Copy commands failing because the destination folder doesn't exist.
Yup, New-Item is useful like that. In this case (OP) you should be able to nail it in just one New-Item statement, as you only need to the structure between the root path and the specific file, and the cmdlet will fill in any missing intermediary folders in the path if necessary. Calling in ROBOCOPY to help may be even easier as that does behave as you describe, but sometimes it is nice to keep it in-house, so to speak.
0

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

Comments

0

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
    }

1 Comment

ForEach-Object : Cannot bind parameter 'RemainingScripts'. Cannot convert the "Else" value of type "System.String" to type "System.Management.Automation.ScriptBlock". At line:4 char:33 + $source | Where PSIsContainer | ForEach-Object { + ~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [ForEach-Object], ParameterBindingException + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.ForEachObjectCommand
0

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\'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.