4

I'm trying to copy files from one location to another using the following PowerShell command:

mkdir Service\ABC\Hosts\A\Infrastructure\compute\parameters
mkdir Service\ABC\Hosts\A\Infrastructure\data\parameters
mkdir Service\ABC\Hosts\B\Infrastructure\compute\parameters
mkdir Service\ABC\Hosts\B\Infrastructure\data\parameters
mkdir Service\ABC\Hosts\C\Infrastructure\compute\parameters
mkdir Service\ABC\Hosts\C\Infrastructure\data\parameters

Copy-Item "public\Service\ABC\Hosts\A\Infrastructure\compute\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\A\Infrastructure\compute\parameters\parameters.xyz.json"
Copy-Item "public\Service\ABC\Hosts\A\Infrastructure\data\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\A\Infrastructure\data\parameters\parameters.xyz.json"
Copy-Item "public\Service\ABC\Hosts\B\Infrastructure\compute\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\B\Infrastructure\compute\parameters\parameters.xyz.json"
Copy-Item "public\Service\ABC\Hosts\B\Infrastructure\data\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\B\Infrastructure\data\parameters\parameters.xyz.json"
Copy-Item "public\Service\ABC\Hosts\C\Infrastructure\compute\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\C\Infrastructure\compute\parameters\parameters.xyz.json"
Copy-Item "public\Service\ABC\Hosts\C\Infrastructure\data\parameters\parameters.int.json" -Destination "Service\ABC\Hosts\C\Infrastructure\data\parameters\parameters.xyz.json"

Because the paths are same for all these files except the directory name 'A, B, C' and 'compute, data' is there a way to simplify this?

3
  • Looks pretty simple to me. What do you find complex about it? Commented Jan 10, 2022 at 22:51
  • agreed @DougMaurer. What are you trying to do ? maybe add some try/catch and error checking. meta.stackoverflow.com/questions/251225/… Commented Jan 10, 2022 at 22:53
  • You can add a loop to make it less "manual" but, I think it's fine as is as well. Maybe use -Force instead and remove mkdir. Commented Jan 10, 2022 at 23:19

1 Answer 1

7

It depends on what your goals are. Separate mkdir and Copy-Item is "conceptually" the "simplest" and maintainable by any beginner PowerShell scripter. If you want to make it more flexible, you can use loops and variables, but that may require more knowledge of PowerShell.

PowerShell Tricks

But to answer your question, yes, there are some optimizations and PowerShell tricks we can take advantage of. The first is to take advantage of arrays of strings, the ForEach-Object, the Subexpression operator $(), and $_ variable to create our paths with "A", "B", and "C"

"A","B","C" | ForEach-Object { "path\$($_)\file.txt" }

Flexible All Variables Method

If you want the more flexible methods, I tend to put all the path information into variables, separate out my shared Source, Destination, and File components. We still do "data" and "compute" separately just so that it is conceptually easier to maintain:

$src = "public\Service\ABC\Hosts"
$dest = "Service\ABC\Hosts"

$path1 = "Infrastructure\compute\parameters"
$path2 = "Infrastructure\data\parameters"

$srcFile = "parameters.int.json"
$destFile = "parameters.xyz.json"

"A","B","C" | ForEach-Object {
     #Compute 
     New-Item "$dest\$($_)\$path1\" -ItemType Directory -Force

     Copy-Item "$src\$($_)\$path1\$srcFile" -Destination  "$dest\$($_)\$path1\$destFile"

     #Data
     New-Item "$dest\$($_)\$path2\" -ItemType Directory -Force

     Copy-Item "$src\$($_)\$path2\$srcFile" -Destination  "$dest\$($_)\$path1\$destFile"
}

PowerShell Trick #2

@AbrahamZinala mentioned using Copy-Item with the -Force parameter to create the directory. Unfortunately it doesn't work. The -Force parameter is used for read-only files or aliases. The directories only get created automatically if you are copying entire directories with -Recurse. Since we are copying individual files, we have to pre-create the directories we are copying to.

The next PowerShell trick is combining Copy-Item with New-Item. First, we put a bracketed New-Item in the Copy-Item -Destination parameter. When New-Item creates the directory (and -Force handles if it already exists), it outputs the object it creates, e.g. the new directory. Copy-Item can take this directory and use it. As long as you don't need to rename the file, this is a neat trick.

Copy-Item "path\file.txt" -Destination (New-Item "path2\newDir\" -ItemType Directory -Force)

If we do have to rename the file, then we simply wrap the entire New-Item in quotes and use the Subexpression operator $() for evaluation.

Copy-Item "path\file.txt" -Destination "$(New-Item "path2\newDir\" -ItemType Directory -Force)\newFileName.txt"

Optimization 1

Using Trick #2, we can reduce the script down a bit, but still pretty maintainable and understandable with a little more PowerShell knowledge:

$src = "public\Service\ABC\Hosts"
$dest = "Service\ABC\Hosts"

$path1 = "Infrastructure\compute\parameters"
$path2 = "Infrastructure\data\parameters"

$srcFile = "parameters.int.json"
$destFile = "parameters.xyz.json"

"A","B","C" | ForEach-Object {
     #Compute 
     Copy-Item "$src\$($_)\$path1\$srcFile" -Destination "$(New-Item "$dest\$($_)\$path1\" -ItemType Directory -Force)\$destFile"

     #Data
     Copy-Item "$src\$($_)\$path2\$srcFile" -Destination "$(New-Item "$dest\$($_)\$path2\" -ItemType Directory -Force)\$destFile"
}

The 2 Liner

If you are looking for simply less, this next script is a bit less maintainable, a little harder to read but if we forego variables, and also using Trick #2, we can reduce the script down to 2 lines:

#Compute
"A","B","C" | ForEach-Object { Copy-Item "public\Service\ABC\Hosts\$($_)\Infrastructure\compute\parameters\parameters.int.json" -Destination "$(New-Item "public\Service\ABC\Hosts\$($_)\Infrastructure\compute\parameters\" -ItemType Directory -Force)\parameters.xyz.json" }

#Data
"A","B","C" | ForEach-Object { Copy-Item "public\Service\ABC\Hosts\$($_)\Infrastructure\data\parameters\parameters.int.json" -Destination "$(New-Item "public\Service\ABC\Hosts\$($_)\Infrastructure\data\parameters\" -ItemType Directory -Force)\parameters.xyz.json" }

The 1 Liner

This next script is even less maintainable, but if the compute and data paths are the same, doing 2 ForEach-Object loops where we prebuild the file path, we can reduce the script down to 1 line:

"A","B","C" | ForEach-Object { "$($_)\Infrastructure\compute\parameters", "$($_)\Infrastructure\data\parameters" | ForEach-Object { Copy-Item "public\Service\ABC\Hosts\$($_)\parameters.int.json" -Destination "$(New-Item "public\Service\ABC\Hosts\$($_)\" -ItemType Directory -Force)\parameters.xyz.json" } }

The CSV

If you have files all over the place, or differing names, you could also put all the files in a CSV e.g.:

InputFile.csv

Path, Destination
"public\Service\ABC\Hosts\A\Infrastructure\compute\parameters\parameters.int.json", "Service\ABC\Hosts\A\Infrastructure\compute\parameters\parameters.xyz.json"
"public\Service\ABC\Hosts\A\Infrastructure\data\parameters\parameters.int.json", "Service\ABC\Hosts\A\Infrastructure\data\parameters\parameters.xyz.json"
"public\Service\ABC\Hosts\B\Infrastructure\compute\parameters\parameters.int.json", "Service\ABC\Hosts\B\Infrastructure\compute\parameters\parameters.xyz.json"
"public\Service\ABC\Hosts\B\Infrastructure\data\parameters\parameters.int.json", "Service\ABC\Hosts\B\Infrastructure\data\parameters\parameters.xyz.json"
"public\Service\ABC\Hosts\C\Infrastructure\compute\parameters\parameters.int.json", "Service\ABC\Hosts\C\Infrastructure\compute\parameters\parameters.xyz.json"
"public\Service\ABC\Hosts\C\Infrastructure\data\parameters\parameters.int.json", "Service\ABC\Hosts\C\Infrastructure\data\parameters\parameters.xyz.json"

PowerShell

$files = Import-CSV -Path "InputFile.csv"
$files | ForEach-Object { Copy-Item $_.Path -Destination $_.Destination }
Sign up to request clarification or add additional context in comments.

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.