Here is a quick code block that I use quite often to copy directories from a management server to a ton of other servers.
Copy-Item [-Recurse]

For the pros or even a beginner, you’re done, you’ve got the command you wanted… but did you think about the rest of the information in this blog? Keep reading!

The problem is a request comes across your desk, more often than we want to admit, saying “We” need to update this file or files on these completely random machines. Then you given a list of servers and you need to quickly copy files to them.

Solutions

  1. Save the list of servers to a text file, read it in with Get-Content. This works cumbersome when in RDP and PS Remitting Environments
  2. $content = Get-Content C:\Temp\SomeRandomFileCopy176.txt
    
  3. Reformat them into a PowerShell array by putting quotes around each of them and commas. Example:
    $Computers = @(
        "Server01",
    	"Server02",
        "Server03.mydomain.local",
    	"Server06"
    )
    
  4. Using/modifying the code at the bottom of this blog post

Myself, I love scripts, I love modules, but what I love more than anything is the flexibility of PowerShell. I even love copying and pasting blocks or one liners directly into PowerShell. So for the copy task presented above here is the magic that my mind goes through:

  1. Which machines do I need to copy files to
  2. Are all the machines online
  3. Test that the destination share path is reachable on all machines
  4. Fix any errors with the remote destinations or simply remove them from the list
  5. Copy the files

Here-Strings to the Rescue


Normally when you create a string in PowerShell, or an array it has some form of structure it has to follow. With a Here-String,

$MyHereString = @"
   This can
be some random te    text    that
           and it's formatting will be preserved when the Here-String variable 
  is used"
"@
$MyHereString
   This can
be some random te    text    that
           and it's formatting will be preserved when the Here-String variable
  is used"

So instead of creating some random temp file on the management server every time, I simply open my Microsoft OneNote and copy and paste the code below. But the technique I use to manage the list of machines is called a PowerShell “Here-String”. Then further down in the code will “convert” the Here-String into an array so that we can easily loop through it. In my opinion when using reusable code blocks, PowerShell Here-Strings are the most forgiving and easiest/fastest to work with as they maintain formatting. To use a Here-String, the unformatted text, in this case a list of machines, are encapsulated between a starting @” tag and a close “@.
*Note* The closing “@ MUST BE on its own line and in column 1.

Again, this is code I copy and paste directly into a PS Window. It allows flexibility when logging into a locked down Remote Desktop environment or when using PowerShell remoting.

Here is the sample script to copy a directory from a source server to the servers listed in the $Computers Here-String below.

$Computers = 
@"
	Server01
	Server02
Server03.mydomain.local
	Server06
	Server07
  Server08
	Server09
	Server26
	Server27
		Server28
	Server29
		 Server30.mydomain.local
	Server35
	Server36
	Server45
	Server46
	Server112
Server113
	Server114 
"@

# Here we will set the source and remote share location and path
$SourceDir = "D:\Software\Datadog\v5.8.5-x64-privatefix"
$RemoteSharePath = "D$\Software\Datadog"

# Loop through the Here-String, trim each line and build the ComputersArray
$ComputersArray = @()
$Computers.Split("`n") | % { if ($_.Trim()) { $ComputersArray += $_.Trim()  } }
$AllRemoteSharePathsExist = $True

# Do a precheck to see if all the remote directories are reachable and exist
$ComputersArray | % { 
    If ((Test-Path "\\$_\$RemoteSharePath") -eq $False) {
        Write-Host -ForegroundColor Red "[PreCheck Error] \\$_\$RemoteSharePath does not exist"
        $AllRemoteSharePathsExist = $False        
    }
}

# If the precheck passes, then copy and overwrite existing files
If ($AllRemoteSharePathsExist) {
    $ComputersArray | % { Write-Host "[$_] Copying $SourceDir to \\$_\$RemoteSharePath"; Copy-Item -Path "$SourceDir" -Destination "\\$_\$RemoteSharePath" -Recurse -Force }
} Else {
    Write-Host "Errors Exist, Exiting"
}     

Happy Copying!