Jumlins TechBlog

The coding hell and the daily IT of Niklas Jumlin

May 11th, 2012 by Niklas Jumlin

I wrote a script that utilizes RoboCopy to mirror directories. It can easily be changed to do file level backups by changing some configurable parameters within the script. Read RoboCopys documentation to understand the use of switches.

Whats interesting about this script is that it writes events/logs to EventLog if executed with administrative privileges, otherwise it will just fallback to logging to file and screen.

## This Script Mirrors a directory tree from source to destination with the Windows builtin command robocopy.
## Exit codes from robocopy are logged to Windows Eventlog.
## Author: NIKLAS JUMLIN
 
## Usage: Run with administrative rights in Windows Task Scheduler or Administrator:PowerShell
## If not executed with administrative privileges the script will not write to eventlog.
 
## Change these parameters
## ================================================================
 
## Name of the job, name of source in Windows Event Log and name of robocopy Logfile.
$JOB = "MyApplication"
 
## Source directory
$SOURCE = "D:\PSTesting\Folder1"
 
## Destination directory. Files in this directory will mirror the source directory. Extra files will be deleted!
$DESTINATION = "D:\PSTesting\Folder2"
 
## Path to robocopy logfile
$LOGFILE = "D:\PSTesting\$JOB"
 
## Log events from the script to this location
$SCRIPTLOG = "D:\PSTesting\$JOB-scriptlog.log"
 
## Mirror a direcotory tree
$WHAT = @("/MIR")
## /COPY:DATS: Copy Data, Attributes, Timestamps, Security
## /SECFIX : FIX file SECurity on all files, even skipped files.
 
## Retry open files 3 times wait 30 seconds between tries. 
$OPTIONS = @("/R:3","/W:30","/NDL","/NFL")
## /NFL : No File List - don't log file names.
## /NDL : No Directory List - don't log directory names.
## /L   : List only - don't copy, timestamp or delete any files.
 
## This will create a timestamp like yyyy-mm-yy
$TIMESTAMP = get-date -uformat "%Y-%m%-%d"
 
## This will get the time like HH:MM:SS
$TIME = get-date -uformat "%T"
 
## Append to robocopy logfile with timestamp
$ROBOCOPYLOG = "/LOG+:$LOGFILE`-Robocopy`-$TIMESTAMP.log"
 
## Wrap all above arguments
$cmdArgs = @("$SOURCE","$DESTINATION",$WHAT,$ROBOCOPYLOG,$OPTIONS)
 
## ================================================================
 
## Start the robocopy with above parameters and log errors in Windows Eventlog.
& C:\Windows\System32\Robocopy.exe @cmdArgs
 
## Get LastExitCode and store in variable
$ExitCode = $LastExitCode
 
$MSGType=@{
"16"="Errror"
"8"="Error"
"4"="Warning"
"2"="Information"
"1"="Information"
"0"="Information"
}
 
## Message descriptions for each ExitCode.
$MSG=@{
"16"="Serious error. robocopy did not copy any files.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"8"="Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded).`n
Check these errors further: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"4"="Some Mismatched files or directories were detected.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log.`
Housekeeping is probably necessary."
"2"="Some Extra files or directories were detected and removed in $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"1"="New files from $SOURCE copied to $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"0"="$SOURCE and $DESTINATION in sync. No files copied.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
}
 
## Function to see if running with administrator privileges
function Test-Administrator  
{  
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)  
}
 
## If running with administrator privileges
If (Test-Administrator -eq $True) {
	"Has administrator privileges"
 
	## Create EventLog Source if not already exists
	if ([System.Diagnostics.EventLog]::SourceExists("$JOB") -eq $false) {
	"Creating EventLog Source `"$JOB`""
    [System.Diagnostics.EventLog]::CreateEventSource("$JOB", "Application")
	}
 
	## Write known ExitCodes to EventLog
	if ($MSG."$ExitCode" -gt $null) {
		Write-EventLog -LogName Application -Source $JOB -EventID $ExitCode -EntryType $MSGType."$ExitCode" -Message $MSG."$ExitCode"
	}
	## Write unknown ExitCodes to EventLog
	else {
		Write-EventLog -LogName Application -Source $JOB -EventID $ExitCode -EntryType Warning -Message "Unknown ExitCode. EventID equals ExitCode"
	}
}
## If not running with administrator privileges
else {
	## Write to screen and logfile
	Add-content $SCRIPTLOG "$TIMESTAMP $TIME No administrator privileges" -PassThru
	Add-content $SCRIPTLOG "$TIMESTAMP $TIME Cannot write to EventLog" -PassThru
 
	## Write known ExitCodes to screen and logfile
	if ($MSG."$ExitCode" -gt $null) {
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME Printing message to logfile:" -PassThru
		Add-content $SCRIPTLOG ($TIMESTAMP + ' ' + $TIME + ' ' + $MSG."$ExitCode") -PassThru
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME ExitCode`=$ExitCode" -PassThru
	}
	## Write unknown ExitCodes to screen and logfile
	else {
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME ExitCode`=$ExitCode (UNKNOWN)" -PassThru
	}
	Add-content $SCRIPTLOG ""
	Return
}

Any new updates will be available for Download from my DropBox:
RoboCopyMir.ps1

Share on Facebook

11 Responses to “ RoboCopy PowerShell Script ”

  1. Mike says:

    This script is absolutely excellent. It not only did exactly what I needed, but is a model template script that is clean, concise and well documented. Well done!

  2. Thank you Mike! As always, I’m thrilled whenever someone finds a use for my scripts. I’m not really a professional programmer therefore I’m happy that I’m on the track.

  3. Brian says:

    Brilliant script. If I want to replace the log file each time I run script what code changes should I make.

  4. Hi Brian,
    Thanks for using my script!

    First of, there are two log files as you might have noticed. One is from the logical steps of the script itself, the other one is the Robocopy job.

    To clear the log on each execution go ahead with these changes:

    Look for these lines:
    ## Log events from the script to this location
    $SCRIPTLOG = “D:\PSTesting\$JOB-scriptlog.log”

    Edit it so it looks like this:
    ## Log events from the script to this location
    $SCRIPTLOG = “D:\PSTesting\$JOB-scriptlog.log”
    Clear-Content $SCRIPTLOG

    Replace this line:
    $ROBOCOPYLOG = “/LOG+:$LOGFILE`-Robocopy`-$TIMESTAMP.log”
    With the below line:
    $ROBOCOPYLOG = “/LOG:$LOGFILE`-Robocopy`-$TIMESTAMP.log”

    See these sites for reference:
    http://technet.microsoft.com/en-us/library/ee156808.aspx
    http://ss64.com/nt/robocopy.html

  5. Chad says:

    Excellent. A few tweaks here and there for my scenario, but you’ve helped! Thanks!

  6. Chester says:

    Nice script!, but would be good if this was explicitly licensed.

  7. Dan Hughes says:

    Hi Niklas, I’ve stumbled across your blog looking for a way to let someone download a file from my blog which they can then copy onto a USB which they can take to a print store and print out a large blueprint-size poster.

    My goal is to use something like robocopy to move the file from their download to their USB so they do not retain the original download.

    Then after taking the USB to store, automatically delete the file from the USB after printing.

    Perhaps some code in the file that will delete source after either event.

    I’m still coming to grips with .php in word press such is the depth of my ignorance so I don’t know how to start experimenting with code to achieve the goal.
    Where does a newbie start?

  8. jay says:

    Hi Nikkas. Great script, thankyou.

    I’m just wondering why my robocopy log is showing:
    Options : *.* /NDL /NFL /S /E /COPY:DAT /PURGE /MIR /R:1 /W:10

    When in the script I have set:
    $WHAT = @(“/MIR”)
    $OPTIONS = @(“/R:1″,”/W:10″,”/NDL”,”/NFL”)

    Where is it getting the /s /e /copy:DAT /purge switches from?

    Cheers
    Jay

  9. Hi jey,
    Thanks!

    These are defaults of robocopy itself. If you wish to change the defaults you must explicitly tell it what to copy (Default is COPY:DAT for example)

    /COPY:copyflag[s] : What to COPY (default is /COPY:DAT)
    /MIR : MIRror a directory tree – equivalent to /PURGE plus all subfolders (/E)

    Read more here:
    http://ss64.com/nt/robocopy.html

  10. Dan Hughes, I’m sorry for late reply. This sounds like a project I would need more time for, time I dont have unfortunately. I would suggest asking your questions on StackOverflow.com for example, its great for learning basics to even asking advanced questions. Good luck!

  11. Sophia Joseph says:

    Why are there so many codes and commands just for a simple task, for file copying! How can you expect someone to remember so many commands at once! This is the main problem with robocopy, there should have been a GUI, a similar software with overwhelming features which was suggested by my friend once is GS Richcopy. This software works like a charm, no remembering code, no complex task to do, just simple and efficient file copying. Some of its features are long path name support, pre-scheduled file transfer, email notification when the transfer is complete and many more features. Hope it helps!

Leave a Reply