How to deploy to remote sites with PowerShell (no DFS required)

Steven van Dijk headshot
Steven van Dijk|September 7, 2018
Alternative to DFS – Deploying To Remote Sites With PowerShell
Alternative to DFS – Deploying To Remote Sites With PowerShell

If you’re getting tired of paying overage fees to the blood-sucking vampires that run the ISPs servicing your remote sites, I’m going to show you an alternative to DFS which allows you to cache your deploy patch /install files to each remote site. Target machines can then grab the install files from their closest cache server instead of downloading individual copies across a slow WAN connection.

Generally, the best solution is to set up DFS and use the ‘pull’ copy mode. Using the ‘pull’ copy mode allows computers to pull the install files directly from a local DFS share at the remote site. More information about that can be found here.

Using PowerShell as an Alternative to DFS

Sometimes DFS isn’t the answer for your environment. Maybe your remote sites are all on the same subnet, so namespaces can’t resolve to the closest server. Or maybe ‘DFS’ are the initials of the Ex who broke your heart and… you know… you’re just not ready. Whatever the reason, here’s an alternative to DFS which saves bandwidth when deploying to remote sites using PowerShell and Robocopy.

Step 1 – Find a local computer to cache install files on.

The first part of our deployment will run ‘Get Closest Server.ps1’ on our target machine to find a close server we can cache the install files on. This script does the following:

  1. Retrieves a text file with a list of possible cache servers, one hostname per line.

  2. Pings each server in the list and finds the average ping time per hostname. Sorts the list, and saves the hostname with the lowest ping to an environment variable on the target machine.

In my testing, this has been a reliable way to find a server on the local network. Any machine at a different site should have a significantly higher ping time than the one onsite.

Step 2 – Copy install files from the Repository to the cache server, then from the cache server to the target machine.

‘Precache installer files.ps1’ has two functions:

Function ‘CheckFilesAndCopy’ does a few things:

  1. Checks to make sure the ‘PDQClosestServer’ environment variable exists. If not, something went wrong in the previous step, so it exits.

  2. Checks to see if the install files already exist on the target machine. If they do, no reason to copy again.

  3. If the files don’t exist or are out of date, the ‘RobocopyFiles’ function is called to copy the files.

Function ‘RobocopyFiles’ uses Robocopy to copy the install files:

  1. Avoids collisions in case multiple deployments are attempting to copy from the repository to the same cache server at the same time. Does this by having a random delayed start, and by checking for lock files and creating a lock file.

  2. Robocopy from the central repository to the cache server. Uses the /xo flag so it doesn’t recopy the files if they have the same name and modified date.

3. Robocopy from the cache server to the target machine. Uses the /xo flag so it doesn’t recopy the files if they have the same name and modified date.

Step 3 – Run install command

Now that the files have been copied to the target machine, you can run your silent install string. Just update your variables in ‘Run Install.ps1’

Step 4 – Clean up local install files (Optional), or leave them behind if storage space is more available than bandwidth.

If you’d like to clean up files (Remove-Item) on the target machine, just add this line after the Start-Process cmdlet which runs the install command:

Remove-Item -Path '\\localhost\$RepoPath\$InstallFolder\' -Recurse -Force

Putting it all together in PDQ Deploy

I like to separate the ‘Get Closest Server’ script into its own Deploy package so that I can run it separately to see where machines are. You can do that with an Inventory collection that looks at environment variables.*

'Get Closest Server' Package using PowerShell an alternative to DFS

Then I create a second deployment with three steps:

  1. Nested ‘Get Closest Server'

  2. Precache Installer Files

  3. Run Install Command

'Precache Install Files' Package Step
'Run Install' Package Step with PowerShell as an alternative to deploying with DFS

*Bonus: Inventory report to display the closest servers of your target machines

After running ‘Get Closest Server’ and doing an environment variable scan (included in the default scan profile), your target machines will have an environment variable of the closest server. You can create a report to show you the information like this:

Closest Server Report   Columns
Closest Server Report   Filters

DFS is usually the best option for spreading out network load, but in situations when that’s not an option, you can use this method an alternative to DFS and script your deployments to use a cache server. I hope this method saves you some headaches copying files to your remote site in the Siberian wilderness with that spotty satellite connection, or your site in rural Vermont still running on dial-up. Drop a comment if you run into any problems or tweak this method to do other cool stuff!

And if videos are more your thing, here’s the webcast Lex and I did on this subject.

Steven van Dijk headshot
Steven van Dijk

Steven has over 8+ years of experience in system administration and software engineering. Steven codes exclusively on ErgoDox keyboards.

Related articles